add default channel button

pull/266/head
Kevin Hester 2021-03-24 13:48:26 +08:00
rodzic 12ea70174e
commit ad7a189c51
5 zmienionych plików z 105 dodań i 37 usunięć

Wyświetl plik

@ -17,10 +17,15 @@ data class Channel(
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf
)
private val cleartextPSK = ByteString.EMPTY
private val defaultPSK = byteArrayOfInts(1) // a shortstring code to indicate we need our default PSK
// TH=he unsecured channel that devices ship with
val defaultChannel = Channel(
ChannelProtos.ChannelSettings.newBuilder()
.setModemConfig(ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128).build()
.setModemConfig(ChannelProtos.ChannelSettings.ModemConfig.Bw125Cr48Sf4096)
.setPsk(ByteString.copyFrom(defaultPSK))
.build()
)
}
@ -50,7 +55,7 @@ data class Channel(
val pskIndex = settings.psk.byteAt(0).toInt()
if (pskIndex == 0)
ByteString.EMPTY // Treat as an empty PSK (no encryption)
cleartextPSK
else {
// Treat an index of 1 as the old channelDefaultKey and work up from there
val bytes = channelDefaultKey.clone()

Wyświetl plik

@ -18,7 +18,6 @@ import com.geeksville.android.Logging
import com.geeksville.android.hideKeyboard
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.ChannelProtos
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.databinding.ChannelFragmentBinding
import com.geeksville.mesh.model.Channel
@ -50,6 +49,7 @@ fun ImageView.setOpaque() {
class ChannelFragment : ScreenFragment("Channel"), Logging {
private var _binding: ChannelFragmentBinding? = null
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
@ -81,6 +81,12 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
val channels = model.channels.value
val channel = channels?.primaryChannel
val connected = model.isConnected.value == MeshService.ConnectionState.CONNECTED
// Only let buttons work if we are connected to the radio
binding.shareButton.isEnabled = connected
binding.resetButton.isEnabled = connected
binding.editableCheckbox.isChecked = false // start locked
if (channel != null) {
binding.qrView.visibility = View.VISIBLE
@ -89,7 +95,6 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
// For now, we only let the user edit/save channels while the radio is awake - because the service
// doesn't cache radioconfig writes.
val connected = model.isConnected.value == MeshService.ConnectionState.CONNECTED
binding.editableCheckbox.isEnabled = connected
binding.qrView.setImageBitmap(channels.getChannelQR())
@ -143,6 +148,28 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
}
}
/// Send new channel settings to the device
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 {
model.setChannels(newSet)
// Since we are writing to radioconfig, that will trigger the rest of the GUI update (QR code etc)
} catch (ex: RemoteException) {
errormsg("ignoring channel problem", ex)
setGUIfromModel() // Throw away user edits
// Tell the user to try again
Snackbar.make(
binding.editableCheckbox,
R.string.radio_sleeping,
Snackbar.LENGTH_SHORT
).show()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -150,6 +177,21 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
requireActivity().hideKeyboard()
}
binding.resetButton.setOnClickListener { _ ->
// User just locked it, we should warn and then apply changes to radio
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.reset_to_defaults)
.setMessage(R.string.are_you_shure_change_default)
.setNeutralButton(R.string.cancel) { _, _ ->
setGUIfromModel() // throw away any edits
}
.setPositiveButton(getString(R.string.accept)) { _, _ ->
debug("Switching back to default channel")
installSettings(Channel.defaultChannel.settings)
}
.show()
}
// Note: Do not use setOnCheckedChanged here because we don't want to be called when we programmatically disable editing
binding.editableCheckbox.setOnClickListener { _ ->
val checked = binding.editableCheckbox.isChecked
@ -178,41 +220,26 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
ignoreCase = true
)
) {
// Install a new customized channel
debug("ASSIGNING NEW AES256 KEY")
val random = SecureRandom()
val bytes = ByteArray(32)
random.nextBytes(bytes)
newSettings.psk = ByteString.copyFrom(bytes)
val selectedChannelOptionString =
binding.filledExposedDropdown.editableText.toString()
val modemConfig = getModemConfig(selectedChannelOptionString)
if (modemConfig != ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED)
newSettings.modemConfig = modemConfig
} else {
debug("Switching back to default channel")
newSettings = Channel.defaultChannel.settings.toBuilder()
}
val selectedChannelOptionString =
binding.filledExposedDropdown.editableText.toString()
val modemConfig = getModemConfig(selectedChannelOptionString)
if (modemConfig != ChannelProtos.ChannelSettings.ModemConfig.UNRECOGNIZED)
newSettings.modemConfig = modemConfig
val newChannel = newSettings.build()
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 {
model.setChannels(newSet)
// Since we are writing to radioconfig, that will trigger the rest of the GUI update (QR code etc)
} catch (ex: RemoteException) {
errormsg("ignoring channel problem", ex)
setGUIfromModel() // Throw away user edits
// Tell the user to try again
Snackbar.make(
binding.editableCheckbox,
R.string.radio_sleeping,
Snackbar.LENGTH_SHORT
).show()
}
installSettings(newSettings.build())
}
}
.show()

Wyświetl plik

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M14.99,4.59V5c0,1.1 -0.9,2 -2,2h-2v2c0,0.55 -0.45,1 -1,1h-2v2h6c0.55,0 1,0.45 1,1v3h1c0.89,0 1.64,0.59 1.9,1.4C19.19,15.98 20,14.08 20,12c0,-3.35 -2.08,-6.23 -5.01,-7.41zM8.99,16v-1l-4.78,-4.78C4.08,10.79 4,11.39 4,12c0,4.07 3.06,7.43 6.99,7.93V18c-1.1,0 -2,-0.9 -2,-2z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10.99,19.93C7.06,19.43 4,16.07 4,12c0,-0.61 0.08,-1.21 0.21,-1.78L8.99,15v1c0,1.1 0.9,2 2,2v1.93zM17.89,17.4c-0.26,-0.81 -1,-1.4 -1.9,-1.4h-1v-3c0,-0.55 -0.45,-1 -1,-1h-6v-2h2c0.55,0 1,-0.45 1,-1L10.99,7h2c1.1,0 2,-0.9 2,-2v-0.41C17.92,5.77 20,8.65 20,12c0,2.08 -0.81,3.98 -2.11,5.4z"/>
</vector>

Wyświetl plik

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -91,30 +92,46 @@
<AutoCompleteTextView
android:id="@+id/filled_exposed_dropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:hint="@string/set_channel_options" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/resetButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:text="@string/reset"
app:icon="@drawable/ic_twotone_public_24"
app:layout_constraintBottom_toBottomOf="@id/bottomButtonsGuideline"
app:layout_constraintStart_toStartOf="parent" />
<CheckBox
android:id="@+id/editableCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="96dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="8dp"
android:button="@drawable/sl_lock_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/shareButton"
app:layout_constraintStart_toStartOf="parent"></CheckBox>
app:layout_constraintBottom_toBottomOf="@id/bottomButtonsGuideline"
app:layout_constraintStart_toEndOf="@+id/resetButton"></CheckBox>
<ImageButton
android:id="@+id/shareButton"
style="@android:style/Widget.Material.ImageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="96dp"
android:layout_marginEnd="32dp"
android:contentDescription="@string/share"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/editableCheckbox"
app:srcCompat="@drawable/ic_twotone_share_24" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/bottomButtonsGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:orientation="horizontal"
app:layout_constraintGuide_end="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

Wyświetl plik

@ -97,4 +97,8 @@
<string name="cant_change_no_radio">Couldn\'t change channel, because radio is not yet connected. Please try again.</string>
<string name="sample_coords">55.332244 34.442211</string>
<string name="save_messages">Save messages as csv...</string>
<string name="set_channel_options">Set channel options</string>
<string name="reset">Reset</string>
<string name="are_you_shure_change_default">Are you sure you want to change to the default channel?</string>
<string name="reset_to_defaults">Reset to defaults</string>
</resources>