diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl index fd4e297e4..4914c0247 100644 --- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl +++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl @@ -80,12 +80,12 @@ interface IMeshService { List getOldMessages(); /// This method is only intended for use in our GUI, so the user can set radio options - /// It returns a RadioConfig protobuf. - byte []getRadioConfig(); + /// It returns a DeviceConfig protobuf. + byte []getDeviceConfig(); /// This method is only intended for use in our GUI, so the user can set radio options - /// It sets a RadioConfig protobuf - void setRadioConfig(in byte []payload); + /// It sets a DeviceConfig protobuf + void setDeviceConfig(in byte []payload); /// This method is only intended for use in our GUI, so the user can set radio options /// It returns a ChannelSet protobuf. diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 508ce8396..267dbdc7d 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -218,9 +218,6 @@ class MainActivity : BaseActivity(), Logging, /** Ask the user to grant Bluetooth scan/discovery permission */ fun requestScanPermission() = requestPermission(getScanPermissions(), true) - /** Ask the user to grant camera permission */ - fun requestCameraPermission() = requestPermission(getCameraPermissions()) - /** Ask the user to grant foreground location permission */ fun requestLocationPermission() = requestPermission(getLocationPermissions()) @@ -644,7 +641,7 @@ class MainActivity : BaseActivity(), Logging, model.setConnectionState(newConnection) - debug("Getting latest radioconfig from service") + debug("Getting latest DeviceConfig from service") try { val info: MyNodeInfo? = service.myNodeInfo // this can be null model.setMyNodeInfo(info) @@ -662,9 +659,9 @@ class MainActivity : BaseActivity(), Logging, if (curVer < MeshService.minFirmwareVersion) showAlert(R.string.firmware_too_old, R.string.firmware_old) else { - // If our app is too old/new, we probably don't understand the new radioconfig messages, so we don't read them until here + // If our app is too old/new, we probably don't understand the new DeviceConfig messages, so we don't read them until here - model.setRadioConfig(RadioConfigProtos.RadioConfig.parseFrom(service.radioConfig)) + model.setDeviceConfig(ConfigProtos.Config.parseFrom(service.deviceConfig)) model.setChannels(ChannelSet(AppOnlyProtos.ChannelSet.parseFrom(service.channels))) diff --git a/app/src/main/java/com/geeksville/mesh/model/Channel.kt b/app/src/main/java/com/geeksville/mesh/model/Channel.kt index a4c8f5c83..7928efb90 100644 --- a/app/src/main/java/com/geeksville/mesh/model/Channel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/Channel.kt @@ -22,7 +22,7 @@ data class Channel(val settings: ChannelProtos.ChannelSettings) { // TH=he unsecured channel that devices ship with val default = Channel( ChannelProtos.ChannelSettings.newBuilder() - .setModemConfig(ChannelProtos.ChannelSettings.ModemConfig.LongFast) + // .setModemConfig(ChannelProtos.ChannelSettings.ModemConfig.LongFast) .setPsk(ByteString.copyFrom(defaultPSK)) .build() ) @@ -30,26 +30,20 @@ data class Channel(val settings: ChannelProtos.ChannelSettings) { /// Return the name of our channel as a human readable string. If empty string, assume "Default" per mesh.proto spec val name: String - get() = if (settings.name.isEmpty()) { - // We have a new style 'empty' channel name. Use the same logic from the device to convert that to a human readable name - if (settings.bandwidth != 0) - "Unset" - else when (settings.modemConfig) { - ChannelProtos.ChannelSettings.ModemConfig.ShortFast -> "ShortFast" - ChannelProtos.ChannelSettings.ModemConfig.ShortSlow -> "ShortSlow" - ChannelProtos.ChannelSettings.ModemConfig.MidFast -> "MidFast" - ChannelProtos.ChannelSettings.ModemConfig.MidSlow -> "MidSlow" - ChannelProtos.ChannelSettings.ModemConfig.LongFast -> "LongFast" - ChannelProtos.ChannelSettings.ModemConfig.LongSlow -> "LongSlow" - ChannelProtos.ChannelSettings.ModemConfig.VLongSlow -> "VLongSlow" + get() = settings.name.ifEmpty { "Placeholder" /* + when (settings.modemConfig) { + ConfigProtos.Config.LoRaConfig.ModemPreset.ShortFast -> "ShortFast" + ConfigProtos.Config.LoRaConfig.ModemPreset.ShortSlow -> "ShortSlow" + ConfigProtos.Config.LoRaConfig.ModemPreset.MidFast -> "MidFast" + ConfigProtos.Config.LoRaConfig.ModemPreset.MidSlow -> "MidSlow" + ConfigProtos.Config.LoRaConfig.ModemPreset.LongFast -> "LongFast" + ConfigProtos.Config.LoRaConfig.ModemPreset.LongSlow -> "LongSlow" + ConfigProtos.Config.LoRaConfig.ModemPreset.VLongSlow -> "VLongSlow" else -> "Invalid" - } - } else - settings.name + }*/ + } - val modemConfig: ChannelProtos.ChannelSettings.ModemConfig get() = settings.modemConfig - - val psk + val psk: ByteString get() = if (settings.psk.size() != 1) settings.psk // A standard PSK else { @@ -86,4 +80,4 @@ data class Channel(val settings: ChannelProtos.ChannelSettings) { && name == o.name } -fun xorHash(b: ByteArray) = b.fold(0, { acc, x -> acc xor (x.toInt() and 0xff) }) \ No newline at end of file +fun xorHash(b: ByteArray) = b.fold(0) { acc, x -> acc xor (x.toInt() and 0xff) } \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/model/ChannelOption.kt b/app/src/main/java/com/geeksville/mesh/model/ChannelOption.kt index fc690442f..cbb56ad56 100644 --- a/app/src/main/java/com/geeksville/mesh/model/ChannelOption.kt +++ b/app/src/main/java/com/geeksville/mesh/model/ChannelOption.kt @@ -1,25 +1,25 @@ package com.geeksville.mesh.model -import com.geeksville.mesh.ChannelProtos +import com.geeksville.mesh.ConfigProtos import com.geeksville.mesh.R enum class ChannelOption( - val modemConfig: ChannelProtos.ChannelSettings.ModemConfig, + val modemPreset: ConfigProtos.Config.LoRaConfig.ModemPreset, val configRes: Int, val minBroadcastPeriodSecs: Int ) { - SHORT_FAST(ChannelProtos.ChannelSettings.ModemConfig.ShortFast,R.string.modem_config_short, 30), - SHORT_SLOW(ChannelProtos.ChannelSettings.ModemConfig.ShortSlow, R.string.modem_config_slow_short, 30), - MED_FAST(ChannelProtos.ChannelSettings.ModemConfig.MidFast,R.string.modem_config_medium, 60), - MED_SLOW(ChannelProtos.ChannelSettings.ModemConfig.MidSlow,R.string.modem_config_slow_medium, 60), - LONG_FAST(ChannelProtos.ChannelSettings.ModemConfig.LongFast, R.string.modem_config_long, 240), - LONG_SLOW(ChannelProtos.ChannelSettings.ModemConfig.LongSlow, R.string.modem_config_slow_long, 375), - VERY_LONG(ChannelProtos.ChannelSettings.ModemConfig.VLongSlow, R.string.modem_config_very_long, 375); + SHORT_FAST(ConfigProtos.Config.LoRaConfig.ModemPreset.ShortFast, R.string.modem_config_short, 30), + SHORT_SLOW(ConfigProtos.Config.LoRaConfig.ModemPreset.ShortSlow, R.string.modem_config_slow_short, 30), + MED_FAST(ConfigProtos.Config.LoRaConfig.ModemPreset.MidFast, R.string.modem_config_medium, 60), + MED_SLOW(ConfigProtos.Config.LoRaConfig.ModemPreset.MidSlow, R.string.modem_config_slow_medium, 60), + LONG_FAST(ConfigProtos.Config.LoRaConfig.ModemPreset.LongFast, R.string.modem_config_long, 240), + LONG_SLOW(ConfigProtos.Config.LoRaConfig.ModemPreset.LongSlow, R.string.modem_config_slow_long, 375), + VERY_LONG(ConfigProtos.Config.LoRaConfig.ModemPreset.VLongSlow, R.string.modem_config_very_long, 375); companion object { - fun fromConfig(modemConfig: ChannelProtos.ChannelSettings.ModemConfig?): ChannelOption? { + fun fromConfig(modemPreset: ConfigProtos.Config.LoRaConfig.ModemPreset?): ChannelOption? { for (option in values()) { - if (option.modemConfig == modemConfig) + if (option.modemPreset == modemPreset) return option } return null diff --git a/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt b/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt index 3e803bcda..44785c611 100644 --- a/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt +++ b/app/src/main/java/com/geeksville/mesh/model/ChannelSet.kt @@ -22,8 +22,6 @@ data class ChannelSet( private fun urlToChannels(url: Uri): AppOnlyProtos.ChannelSet { val urlStr = url.toString() - // We no longer support the super old (about 0.8ish? verison of the URLs that don't use the # separator - I doubt - // anyone is still using that old format val pathRegex = Regex("$prefix(.*)", RegexOption.IGNORE_CASE) val (base64) = pathRegex.find(urlStr)?.destructured ?: throw MalformedURLException("Not a meshtastic URL: ${urlStr.take(40)}") @@ -51,13 +49,13 @@ data class ChannelSet( /// Return an URL that represents the current channel values /// @param upperCasePrefix - portions of the URL can be upper case to make for more efficient QR codes fun getChannelUrl(upperCasePrefix: Boolean = false): Uri { - // If we have a valid radio config use it, othterwise use whatever we have saved in the prefs + // If we have a valid radio config use it, otherwise use whatever we have saved in the prefs val channelBytes = protobuf.toByteArray() ?: ByteArray(0) // if unset just use empty val enc = Base64.encodeToString(channelBytes, base64Flags) val p = if (upperCasePrefix) - prefix.toUpperCase() + prefix.uppercase() else prefix return Uri.parse("$p$enc") 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 75105cfb0..7d46a6f80 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -43,8 +43,8 @@ fun getInitials(nameIn: String): String { val words = name.split(Regex("\\s+")).filter { it.isNotEmpty() } val initials = when (words.size) { - in 0..minchars - 1 -> { - val nm = if (name.length >= 1) + in 0 until minchars -> { + val nm = if (name.isNotEmpty()) name.first() + name.drop(1).filterNot { c -> c.lowercase() in "aeiou" } else "" @@ -101,8 +101,8 @@ class UIViewModel @Inject constructor( } /// various radio settings (including the channel) - private val _radioConfig = MutableLiveData() - val radioConfig: LiveData get() = _radioConfig + private val _deviceConfig = MutableLiveData() + val deviceConfig: LiveData get() = _deviceConfig private val _channels = MutableLiveData() val channels: LiveData get() = _channels @@ -123,7 +123,7 @@ class UIViewModel @Inject constructor( var positionBroadcastSecs: Int? get() { - _radioConfig.value?.preferences?.let { + _deviceConfig.value?.position?.let { if (it.positionBroadcastSecs > 0) return it.positionBroadcastSecs // These default values are borrowed from the device code. return 15 * 60 @@ -131,50 +131,50 @@ class UIViewModel @Inject constructor( return null } set(value) { - val config = _radioConfig.value + val config = _deviceConfig.value if (value != null && config != null) { val builder = config.toBuilder() - builder.preferencesBuilder.positionBroadcastSecs = value - setRadioConfig(builder.build()) + builder.positionBuilder.positionBroadcastSecs = value + setDeviceConfig(builder.build()) } } var lsSleepSecs: Int? - get() = _radioConfig.value?.preferences?.lsSecs + get() = _deviceConfig.value?.power?.lsSecs set(value) { - val config = _radioConfig.value + val config = _deviceConfig.value if (value != null && config != null) { val builder = config.toBuilder() - builder.preferencesBuilder.lsSecs = value - setRadioConfig(builder.build()) + builder.powerBuilder.lsSecs = value + setDeviceConfig(builder.build()) } } - var locationShareDisabled: Boolean - get() = _radioConfig.value?.preferences?.locationShareDisabled ?: false + var gpsDisabled: Boolean + get() = _deviceConfig.value?.position?.gpsDisabled ?: false set(value) { - val config = _radioConfig.value + val config = _deviceConfig.value if (config != null) { val builder = config.toBuilder() - builder.preferencesBuilder.locationShareDisabled = value - setRadioConfig(builder.build()) + builder.positionBuilder.gpsDisabled = value + setDeviceConfig(builder.build()) } } var isPowerSaving: Boolean? - get() = _radioConfig.value?.preferences?.isPowerSaving + get() = _deviceConfig.value?.power?.isPowerSaving set(value) { - val config = _radioConfig.value + val config = _deviceConfig.value if (value != null && config != null) { val builder = config.toBuilder() - builder.preferencesBuilder.isPowerSaving = value - setRadioConfig(builder.build()) + builder.powerBuilder.isPowerSaving = value + setDeviceConfig(builder.build()) } } - var region: RadioConfigProtos.RegionCode - get() = meshService?.region?.let { RadioConfigProtos.RegionCode.forNumber(it) } - ?: RadioConfigProtos.RegionCode.Unset + var region: ConfigProtos.Config.LoRaConfig.RegionCode + get() = meshService?.region?.let { ConfigProtos.Config.LoRaConfig.RegionCode.forNumber(it) } + ?: ConfigProtos.Config.LoRaConfig.RegionCode.Unset set(value) { meshService?.region = value.number } @@ -216,10 +216,10 @@ class UIViewModel @Inject constructor( val primaryChannel: Channel? get() = _channels.value?.primaryChannel // Set the radio config (also updates our saved copy in preferences) - fun setRadioConfig(c: RadioConfigProtos.RadioConfig) { + fun setDeviceConfig(c: ConfigProtos.Config) { debug("Setting new radio config!") - meshService?.radioConfig = c.toByteArray() - _radioConfig.value = + meshService?.deviceConfig = c.toByteArray() + _deviceConfig.value = c // Must be done after calling the service, so we will will properly throw if the service failed (and therefore not cache invalid new settings) } diff --git a/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt b/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt index 6aa794323..4e5a1bbb0 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt @@ -60,13 +60,13 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi private fun handleAdminPacket(pr: MeshProtos.ToRadio, d: AdminProtos.AdminMessage) { when { - d.getRadioRequest -> + d.getConfigRequest == AdminProtos.AdminMessage.ConfigType.LORA_CONFIG -> sendAdmin(pr.packet.to, pr.packet.from, pr.packet.id) { - getRadioResponse = RadioConfigProtos.RadioConfig.newBuilder().apply { + getConfigResponse = ConfigProtos.Config.newBuilder().apply { - preferences = - RadioConfigProtos.RadioConfig.UserPreferences.newBuilder().apply { - region = RadioConfigProtos.RegionCode.TW + lora = + ConfigProtos.Config.LoRaConfig.newBuilder().apply { + region = ConfigProtos.Config.LoRaConfig.RegionCode.TW // FIXME set critical times? }.build() }.build() 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 6b3b4ff86..07f802717 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -83,7 +83,7 @@ class MeshService : Service(), Logging { class NodeNumNotFoundException(id: Int) : NodeNotFoundException("NodeNum not found $id") class IdNotFoundException(id: String) : NodeNotFoundException("ID not found $id") - class NoRadioConfigException(message: String = "No radio settings received (is our app too old?)") : + class NoDeviceConfigException(message: String = "No radio settings received (is our app too old?)") : RadioNotConnectedException(message) /** We treat software update as similar to loss of comms to the regular bluetooth service (so things like sendPosition for background GPS ignores the problem */ @@ -128,7 +128,7 @@ class MeshService : Service(), Logging { private var locationFlow: Job? = null // If we've ever read a valid region code from our device it will be here - var curRegionValue = RadioConfigProtos.RegionCode.Unset_VALUE + var curRegionValue = ConfigProtos.Config.LoRaConfig.RegionCode.Unset_VALUE private fun getSenderName(packet: DataPacket?): String { val name = nodeDBbyID[packet?.from]?.user?.longName @@ -350,7 +350,7 @@ class MeshService : Service(), Logging { var myNodeInfo: MyNodeInfo? = null - private var radioConfig: RadioConfigProtos.RadioConfig? = null + private var deviceConfig: ConfigProtos.Config? = null private var channels = fixupChannelList(listOf()) @@ -725,9 +725,9 @@ class MeshService : Service(), Logging { // For the time being we only care about admin messages from our local node if (fromNodeNum == myNodeNum) { when (a.variantCase) { - AdminProtos.AdminMessage.VariantCase.GET_RADIO_RESPONSE -> { - debug("Admin: received radioConfig") - radioConfig = a.getRadioResponse + AdminProtos.AdminMessage.VariantCase.GET_CONFIG_RESPONSE -> { + debug("Admin: received deviceConfig") + deviceConfig = a.getConfigResponse requestChannel(0) // Now start reading channels } @@ -983,7 +983,7 @@ class MeshService : Service(), Logging { sleepTimeout = serviceScope.handledLaunch { try { // If we have a valid timeout, wait that long (+30 seconds) otherwise, just wait 30 seconds - val timeout = (radioConfig?.preferences?.lsSecs ?: 0) + 30 + val timeout = (deviceConfig?.power?.lsSecs ?: 0) + 30 debug("Waiting for sleeping device, timeout=$timeout secs") delay(timeout * 1000L) @@ -1075,7 +1075,7 @@ class MeshService : Service(), Logging { private fun onRadioConnectionState(state: RadioServiceConnectionState) { // sleep now disabled by default on ESP32, permanent is true unless isPowerSaving enabled - val lsEnabled = radioConfig?.preferences?.isPowerSaving ?: false + val lsEnabled = deviceConfig?.power?.isPowerSaving ?: false val connected = state.isConnected val permanent = state.isPermanent || !lsEnabled onConnectionChanged( @@ -1105,7 +1105,7 @@ class MeshService : Service(), Logging { MeshProtos.FromRadio.NODE_INFO_FIELD_NUMBER -> handleNodeInfo(proto.nodeInfo) - // MeshProtos.FromRadio.RADIO_FIELD_NUMBER -> handleRadioConfig(proto.radio) + // MeshProtos.FromRadio.RADIO_FIELD_NUMBER -> handleDeviceConfig(proto.radio) else -> errormsg("Unexpected FromRadio variant") } @@ -1249,7 +1249,7 @@ class MeshService : Service(), Logging { regenMyNodeInfo() // We'll need to get a new set of channels and settings now - radioConfig = null + deviceConfig = null // prefill the channel array with null channels channels = fixupChannelList(listOf()) @@ -1272,21 +1272,21 @@ class MeshService : Service(), Logging { private fun setRegionOnDevice() { val curConfigRegion = - radioConfig?.preferences?.region ?: RadioConfigProtos.RegionCode.Unset + deviceConfig?.lora?.region ?: ConfigProtos.Config.LoRaConfig.RegionCode.Unset - if (curConfigRegion.number != curRegionValue && curRegionValue != RadioConfigProtos.RegionCode.Unset_VALUE) + if (curConfigRegion.number != curRegionValue && curRegionValue != ConfigProtos.Config.LoRaConfig.RegionCode.Unset_VALUE) if (deviceVersion >= minFirmwareVersion) { info("Telling device to upgrade region") // Tell the device to set the new region field (old devices will simply ignore this) - radioConfig?.let { currentConfig -> + deviceConfig?.let { currentConfig -> val newConfig = currentConfig.toBuilder() - val newPrefs = currentConfig.preferences.toBuilder() + val newPrefs = currentConfig.lora.toBuilder() newPrefs.regionValue = curRegionValue - newConfig.preferences = newPrefs.build() + newConfig.lora = newPrefs.build() - sendRadioConfig(newConfig.build()) + sendDeviceConfig(newConfig.build()) } } else warn("Device is too old to understand region changes") @@ -1301,8 +1301,8 @@ class MeshService : Service(), Logging { // Try to pull our region code from the new preferences field // FIXME - do not check net - figuring out why board is rebooting val curConfigRegion = - radioConfig?.preferences?.region ?: RadioConfigProtos.RegionCode.Unset - if (curConfigRegion != RadioConfigProtos.RegionCode.Unset) { + deviceConfig?.lora?.region ?: ConfigProtos.Config.LoRaConfig.RegionCode.Unset + if (curConfigRegion != ConfigProtos.Config.LoRaConfig.RegionCode.Unset) { info("Using device region $curConfigRegion (code ${curConfigRegion.number})") curRegionValue = curConfigRegion.number } @@ -1357,15 +1357,15 @@ class MeshService : Service(), Logging { info("Device firmware is too old, faking config so firmware update can occur") onHasSettings() } else - requestRadioConfig() + requestDeviceConfig() } } else warn("Ignoring stale config complete") } - private fun requestRadioConfig() { + private fun requestDeviceConfig() { sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket(wantResponse = true) { - getRadioRequest = true + getConfigRequest = AdminProtos.AdminMessage.ConfigType.DEVICE_CONFIG }) } @@ -1440,22 +1440,22 @@ class MeshService : Service(), Logging { /** Send our current radio config to the device */ - private fun sendRadioConfig(c: RadioConfigProtos.RadioConfig) { + private fun sendDeviceConfig(c: ConfigProtos.Config) { // send the packet into the mesh sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket { - setRadio = c + setConfig = c }) // Update our cached copy - this@MeshService.radioConfig = c + this@MeshService.deviceConfig = c } /** Set our radio config */ - private fun setRadioConfig(payload: ByteArray) { - val parsed = RadioConfigProtos.RadioConfig.parseFrom(payload) + private fun setDeviceConfig(payload: ByteArray) { + val parsed = ConfigProtos.Config.parseFrom(payload) - sendRadioConfig(parsed) + sendDeviceConfig(parsed) } /** @@ -1690,13 +1690,13 @@ class MeshService : Service(), Logging { } } - override fun getRadioConfig(): ByteArray = toRemoteExceptions { - this@MeshService.radioConfig?.toByteArray() - ?: throw NoRadioConfigException() + override fun getDeviceConfig(): ByteArray = toRemoteExceptions { + this@MeshService.deviceConfig?.toByteArray() + ?: throw NoDeviceConfigException() } - override fun setRadioConfig(payload: ByteArray) = toRemoteExceptions { - this@MeshService.setRadioConfig(payload) + override fun setDeviceConfig(payload: ByteArray) = toRemoteExceptions { + this@MeshService.setDeviceConfig(payload) } override fun getChannels(): ByteArray = toRemoteExceptions { diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshServiceSettingsData.kt b/app/src/main/java/com/geeksville/mesh/service/MeshServiceSettingsData.kt index b7776acd8..a84356605 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshServiceSettingsData.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshServiceSettingsData.kt @@ -3,7 +3,7 @@ package com.geeksville.mesh.service import com.geeksville.mesh.DataPacket import com.geeksville.mesh.MyNodeInfo import com.geeksville.mesh.NodeInfo -import com.geeksville.mesh.RadioConfigProtos +import com.geeksville.mesh.ConfigProtos import kotlinx.serialization.Serializable /// Our saved preferences as stored on disk @@ -12,7 +12,7 @@ data class MeshServiceSettingsData( val nodeDB: Array, val myInfo: MyNodeInfo, val messages: Array, - val regionCode: Int = RadioConfigProtos.RegionCode.Unset_VALUE + val regionCode: Int = ConfigProtos.Config.LoRaConfig.RegionCode.Unset_VALUE ) { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt index daa81b1e8..05c32525a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt @@ -37,18 +37,18 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - model.radioConfig.observe(viewLifecycleOwner) { + model.deviceConfig.observe(viewLifecycleOwner) { binding.positionBroadcastPeriodEditText.setText(model.positionBroadcastSecs.toString()) binding.lsSleepEditText.setText(model.lsSleepSecs.toString()) - binding.positionBroadcastPeriodView.isEnabled = !model.locationShareDisabled - binding.positionBroadcastSwitch.isChecked = !model.locationShareDisabled + binding.positionBroadcastPeriodView.isEnabled = !model.gpsDisabled + binding.positionBroadcastSwitch.isChecked = !model.gpsDisabled binding.lsSleepView.isEnabled = model.isPowerSaving ?: false binding.lsSleepSwitch.isChecked = model.isPowerSaving ?: false } model.connectionState.observe(viewLifecycleOwner) { connectionState -> val connected = connectionState == MeshService.ConnectionState.CONNECTED - binding.positionBroadcastPeriodView.isEnabled = connected && !model.locationShareDisabled + binding.positionBroadcastPeriodView.isEnabled = connected && !model.gpsDisabled binding.lsSleepView.isEnabled = connected && model.isPowerSaving ?: false binding.positionBroadcastSwitch.isEnabled = connected binding.lsSleepSwitch.isEnabled = connected @@ -58,7 +58,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { val textEdit = binding.positionBroadcastPeriodEditText val n = textEdit.text.toString().toIntOrNull() val minBroadcastPeriodSecs = - ChannelOption.fromConfig(model.primaryChannel?.modemConfig)?.minBroadcastPeriodSecs + ChannelOption.fromConfig(model.deviceConfig.value?.lora?.modemPreset)?.minBroadcastPeriodSecs ?: ChannelOption.defaultMinBroadcastPeriod if (n != null && n < MAX_INT_DEVICE && (n == 0 || n >= minBroadcastPeriodSecs)) { @@ -81,7 +81,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { binding.positionBroadcastSwitch.setOnCheckedChangeListener { view, isChecked -> if (view.isPressed) { - model.locationShareDisabled = !isChecked + model.gpsDisabled = !isChecked debug("User changed locationShare to $isChecked") } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt index 50392eb6a..194f771d1 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt @@ -23,6 +23,7 @@ import com.geeksville.android.hideKeyboard import com.geeksville.android.isGooglePlayAvailable import com.geeksville.mesh.AppOnlyProtos import com.geeksville.mesh.ChannelProtos +import com.geeksville.mesh.ConfigProtos import com.geeksville.mesh.R import com.geeksville.mesh.android.hasCameraPermission import com.geeksville.mesh.databinding.ChannelFragmentBinding @@ -107,15 +108,15 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { binding.channelNameEdit.setText(channel.humanName) // For now, we only let the user edit/save channels while the radio is awake - because the service - // doesn't cache radioconfig writes. + // doesn't cache DeviceConfig writes. binding.editableCheckbox.isEnabled = connected val bitmap = channels.qrCode if (bitmap != null) binding.qrView.setImageBitmap(bitmap) - val modemConfig = channel.modemConfig - val channelOption = ChannelOption.fromConfig(modemConfig) + val modemPreset = model.deviceConfig.value?.lora?.modemPreset + val channelOption = ChannelOption.fromConfig(modemPreset) binding.filledExposedDropdown.setText( getString( channelOption?.configRes ?: R.string.modem_config_unrecognized @@ -128,12 +129,12 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { binding.editableCheckbox.isEnabled = false } - val modemConfigs = ChannelOption.values() - val modemConfigList = modemConfigs.map { getString(it.configRes) } + val modemPresets = ChannelOption.values() + val modemPresetList = modemPresets.map { getString(it.configRes) } val adapter = ArrayAdapter( requireContext(), R.layout.dropdown_menu_popup_item, - modemConfigList + modemPresetList ) binding.filledExposedDropdown.setAdapter(adapter) @@ -174,10 +175,10 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { private fun installSettings(newChannel: ChannelProtos.ChannelSettings) { val newSet = ChannelSet(AppOnlyProtos.ChannelSet.newBuilder().addSettings(newChannel).build()) - // Try to change the radio, if it fails, tell the user why and throw away their redits + // Try to change the radio, if it fails, tell the user why and throw away their edits try { model.setChannels(newSet) - // Since we are writing to radioconfig, that will trigger the rest of the GUI update (QR code etc) + // Since we are writing to DeviceConfig, that will trigger the rest of the GUI update (QR code etc) } catch (ex: RemoteException) { errormsg("ignoring channel problem", ex) @@ -282,7 +283,7 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { if (checked) { // User just unlocked for editing - remove the # goo around the channel name model.channels.value?.primaryChannel?.let { ch -> - // Note: We are careful to show the emptystring here if the user was on a default channel, so the user knows they should it for any changes + // Note: We are careful to show the empty string here if the user was on a default channel, so the user knows they should it for any changes originalName = ch.settings.name binding.channelNameEdit.setText(originalName) } @@ -303,18 +304,20 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { // Find the new modem config val selectedChannelOptionString = binding.filledExposedDropdown.editableText.toString() - var modemConfig = getModemConfig(selectedChannelOptionString) - if (modemConfig == ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED) // Huh? didn't find it - keep same - modemConfig = oldPrimary.settings.modemConfig + var modemPreset = getModemPreset(selectedChannelOptionString) + // if (modemPreset == ConfigProtos.Config.LoRaConfig.ModemPreset.UNRECOGNIZED) // Huh? didn't find it - keep same + // modemPreset = oldPrimary.settings.modemConfig -> TODO add from LoraConfig.ModemPreset? // Generate a new AES256 key if the user changes channel name or the name is non-default and the settings changed - if (newName != originalName || (newName.isNotEmpty() && modemConfig != oldPrimary.settings.modemConfig)) { + // if (newName != originalName || (newName.isNotEmpty() && modemConfig != oldPrimary.settings.modemConfig)) { + if (newName != originalName || newName.isNotEmpty()) { + // Install a new customized channel debug("ASSIGNING NEW AES256 KEY") val random = SecureRandom() val bytes = ByteArray(32) random.nextBytes(bytes) - newSettings.name = newName + newSettings.name = newName.take(11) // proto max_size:12 newSettings.psk = ByteString.copyFrom(bytes) } else { debug("Switching back to default channel") @@ -322,7 +325,7 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { } // No matter what apply the speed selection from the user - newSettings.modemConfig = modemConfig + // newSettings.modemConfig = modemPreset -> TODO add from LoraConfig.ModemPreset? installSettings(newSettings.build()) } @@ -348,12 +351,12 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { } } - private fun getModemConfig(selectedChannelOptionString: String): ChannelProtos.ChannelSettings.ModemConfig { + private fun getModemPreset(selectedChannelOptionString: String): ConfigProtos.Config.LoRaConfig.ModemPreset { for (item in ChannelOption.values()) { if (getString(item.configRes) == selectedChannelOptionString) - return item.modemConfig + return item.modemPreset } - return ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED + return ConfigProtos.Config.LoRaConfig.ModemPreset.UNRECOGNIZED } private val requestPermissionAndScanLauncher = diff --git a/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt index 8da8a0906..84b06122f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ContactsFragment.kt @@ -87,7 +87,7 @@ class ContactsFragment : ScreenFragment("Messages"), Logging { val nodes = model.nodeDB.nodes.value!! val node = nodes[if (isLocal) contact.to else contact.from] - //grab channel names from RadioConfig + //grab channel names from DeviceConfig val channels = model.channels.value val primaryChannel = channels?.primaryChannel diff --git a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt index 135f20a67..e925032ff 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MessagesFragment.kt @@ -296,9 +296,6 @@ class MessagesFragment : Fragment(), Logging { val connected = connectionState == MeshService.ConnectionState.CONNECTED binding.textInputLayout.isEnabled = connected binding.sendButton.isEnabled = connected - - // Just being connected is enough to allow sending texts I think - // && model.nodeDB.myId.value != null && model.radioConfig.value != null } } 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 4476d91a0..492b30d14 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -32,7 +32,7 @@ import com.geeksville.android.hideKeyboard import com.geeksville.android.isGooglePlayAvailable import com.geeksville.mesh.MainActivity import com.geeksville.mesh.R -import com.geeksville.mesh.RadioConfigProtos +import com.geeksville.mesh.ConfigProtos import com.geeksville.mesh.android.* import com.geeksville.mesh.databinding.SettingsFragmentBinding import com.geeksville.mesh.model.BluetoothViewModel @@ -659,7 +659,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { // update the region selection from the device val region = model.region val spinner = binding.regionSpinner - val unsetIndex = regions.indexOf(RadioConfigProtos.RegionCode.Unset.name) + val unsetIndex = regions.indexOf(ConfigProtos.Config.LoRaConfig.RegionCode.Unset.name) spinner.onItemSelectedListener = null debug("current region is $region") @@ -673,7 +673,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { spinner.isEnabled = true // If actively connected possibly let the user update firmware - refreshUpdateButton(region != RadioConfigProtos.RegionCode.Unset) + refreshUpdateButton(region != ConfigProtos.Config.LoRaConfig.RegionCode.Unset) // Update the status string (highest priority messages first) val info = model.myNodeInfo.value @@ -683,7 +683,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { (permissionsWarning != null) -> statusText.text = permissionsWarning - region == RadioConfigProtos.RegionCode.Unset -> + region == ConfigProtos.Config.LoRaConfig.RegionCode.Unset -> statusText.text = getString(R.string.must_set_region) connected == MeshService.ConnectionState.CONNECTED -> { @@ -705,7 +705,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { id: Long ) { val item = parent.getItemAtPosition(position) as String? - val asProto = item!!.let { RadioConfigProtos.RegionCode.valueOf(it) } + val asProto = item!!.let { ConfigProtos.Config.LoRaConfig.RegionCode.valueOf(it) } exceptionToSnackbar(requireView()) { model.region = asProto } @@ -718,8 +718,8 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { } /// the sorted list of region names like arrayOf("US", "CN", "EU488") - private val regions = RadioConfigProtos.RegionCode.values().filter { - it != RadioConfigProtos.RegionCode.UNRECOGNIZED + private val regions = ConfigProtos.Config.LoRaConfig.RegionCode.values().filter { + it != ConfigProtos.Config.LoRaConfig.RegionCode.UNRECOGNIZED }.map { it.name }.sorted() @@ -746,10 +746,10 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { updateDevicesButtons(scanModel.devices.value) } - model.radioConfig.observe(viewLifecycleOwner) { + model.deviceConfig.observe(viewLifecycleOwner) { binding.provideLocationCheckbox.isEnabled = - isGooglePlayAvailable(requireContext()) && !model.locationShareDisabled - if (model.locationShareDisabled) { + isGooglePlayAvailable(requireContext()) && !model.gpsDisabled + if (model.gpsDisabled) { model.provideLocation.value = false binding.provideLocationCheckbox.isChecked = false } diff --git a/app/src/main/res/layout/channel_fragment.xml b/app/src/main/res/layout/channel_fragment.xml index e66cf44ba..fc66fe285 100644 --- a/app/src/main/res/layout/channel_fragment.xml +++ b/app/src/main/res/layout/channel_fragment.xml @@ -13,6 +13,8 @@ android:layout_marginTop="16dp" android:layout_marginEnd="64dp" android:hint="@string/channel_name" + app:counterEnabled="true" + app:counterMaxLength="11" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> @@ -23,7 +25,6 @@ android:layout_height="wrap_content" android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890- " android:imeOptions="actionDone" - android:maxLength="15" android:singleLine="true" android:text="@string/unset" />