kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
60b2fe6768
1
TODO.md
1
TODO.md
|
@ -1,7 +1,6 @@
|
||||||
# Remaining tasks before declaring 1.0
|
# Remaining tasks before declaring 1.0
|
||||||
|
|
||||||
* add a low level settings screen (let user change any of the RadioConfig parameters)
|
* add a low level settings screen (let user change any of the RadioConfig parameters)
|
||||||
* if user edits the channel, generate a new AES256 key
|
|
||||||
* add play store link with https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder and the play icon
|
* add play store link with https://developers.google.com/analytics/devguides/collection/android/v4/campaigns#google-play-url-builder and the play icon
|
||||||
|
|
||||||
Things for the betaish period.
|
Things for the betaish period.
|
||||||
|
|
|
@ -17,8 +17,8 @@ android {
|
||||||
applicationId "com.geeksville.mesh"
|
applicationId "com.geeksville.mesh"
|
||||||
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
|
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 176
|
versionCode 10771 // format is Mmmss (where M is 1+the numeric major number
|
||||||
versionName "0.7.6"
|
versionName "0.7.71"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
@ -14,10 +14,12 @@ data class Channel(
|
||||||
val settings: MeshProtos.ChannelSettings = MeshProtos.ChannelSettings.getDefaultInstance()
|
val settings: MeshProtos.ChannelSettings = MeshProtos.ChannelSettings.getDefaultInstance()
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
|
// Note: this string _SHOULD NOT BE LOCALIZED_ because it directly hashes to values used on the device for the default channel name.
|
||||||
|
val defaultChannelName = "Default"
|
||||||
|
|
||||||
// Placeholder when emulating
|
// Placeholder when emulating
|
||||||
val emulated = Channel(
|
val emulated = Channel(
|
||||||
// Note: this string _SHOULD NOT BE LOCALIZED_ because it directly hashes to values used on the device for the default channel name.
|
MeshProtos.ChannelSettings.newBuilder().setName(defaultChannelName)
|
||||||
MeshProtos.ChannelSettings.newBuilder().setName("Default")
|
|
||||||
.setModemConfig(MeshProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128).build()
|
.setModemConfig(MeshProtos.ChannelSettings.ModemConfig.Bw125Cr45Sf128).build()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -620,6 +620,7 @@ class MeshService : Service(), Logging {
|
||||||
private var radioConfig: MeshProtos.RadioConfig? = null
|
private var radioConfig: MeshProtos.RadioConfig? = null
|
||||||
|
|
||||||
/// True after we've done our initial node db init
|
/// True after we've done our initial node db init
|
||||||
|
@Volatile
|
||||||
private var haveNodeDB = false
|
private var haveNodeDB = false
|
||||||
|
|
||||||
// The database of active nodes, index is the node number
|
// The database of active nodes, index is the node number
|
||||||
|
@ -933,6 +934,7 @@ class MeshService : Service(), Logging {
|
||||||
// decided to pass through to us (except for broadcast packets)
|
// decided to pass through to us (except for broadcast packets)
|
||||||
//val toNum = packet.to
|
//val toNum = packet.to
|
||||||
|
|
||||||
|
debug("Recieved: $packet")
|
||||||
val p = packet.decoded
|
val p = packet.decoded
|
||||||
|
|
||||||
// If the rxTime was not set by the device (because device software was old), guess at a time
|
// If the rxTime was not set by the device (because device software was old), guess at a time
|
||||||
|
@ -1154,29 +1156,30 @@ class MeshService : Service(), Logging {
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioInterfaceService.RECEIVE_FROMRADIO_ACTION -> {
|
RadioInterfaceService.RECEIVE_FROMRADIO_ACTION -> {
|
||||||
val proto =
|
val bytes = intent.getByteArrayExtra(EXTRA_PAYLOAD)!!
|
||||||
MeshProtos.FromRadio.parseFrom(
|
try {
|
||||||
intent.getByteArrayExtra(
|
val proto =
|
||||||
EXTRA_PAYLOAD
|
MeshProtos.FromRadio.parseFrom(bytes)
|
||||||
)!!
|
info("Received from radio service: ${proto.toOneLineString()}")
|
||||||
)
|
when (proto.variantCase.number) {
|
||||||
info("Received from radio service: ${proto.toOneLineString()}")
|
MeshProtos.FromRadio.PACKET_FIELD_NUMBER -> handleReceivedMeshPacket(
|
||||||
when (proto.variantCase.number) {
|
proto.packet
|
||||||
MeshProtos.FromRadio.PACKET_FIELD_NUMBER -> handleReceivedMeshPacket(
|
)
|
||||||
proto.packet
|
|
||||||
)
|
|
||||||
|
|
||||||
MeshProtos.FromRadio.CONFIG_COMPLETE_ID_FIELD_NUMBER -> handleConfigComplete(
|
MeshProtos.FromRadio.CONFIG_COMPLETE_ID_FIELD_NUMBER -> handleConfigComplete(
|
||||||
proto.configCompleteId
|
proto.configCompleteId
|
||||||
)
|
)
|
||||||
|
|
||||||
MeshProtos.FromRadio.MY_INFO_FIELD_NUMBER -> handleMyInfo(proto.myInfo)
|
MeshProtos.FromRadio.MY_INFO_FIELD_NUMBER -> handleMyInfo(proto.myInfo)
|
||||||
|
|
||||||
MeshProtos.FromRadio.NODE_INFO_FIELD_NUMBER -> handleNodeInfo(proto.nodeInfo)
|
MeshProtos.FromRadio.NODE_INFO_FIELD_NUMBER -> handleNodeInfo(proto.nodeInfo)
|
||||||
|
|
||||||
MeshProtos.FromRadio.RADIO_FIELD_NUMBER -> handleRadioConfig(proto.radio)
|
MeshProtos.FromRadio.RADIO_FIELD_NUMBER -> handleRadioConfig(proto.radio)
|
||||||
|
|
||||||
else -> errormsg("Unexpected FromRadio variant")
|
else -> errormsg("Unexpected FromRadio variant")
|
||||||
|
}
|
||||||
|
} catch (ex: InvalidProtocolBufferException) {
|
||||||
|
Exceptions.report(ex, "Invalid Protobuf from radio, len=${bytes.size}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,15 @@ import com.geeksville.android.GeeksvilleApplication
|
||||||
import com.geeksville.android.Logging
|
import com.geeksville.android.Logging
|
||||||
import com.geeksville.android.hideKeyboard
|
import com.geeksville.android.hideKeyboard
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
|
import com.geeksville.mesh.model.Channel
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import com.geeksville.mesh.service.MeshService
|
import com.geeksville.mesh.service.MeshService
|
||||||
import com.geeksville.util.Exceptions
|
import com.geeksville.util.Exceptions
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.google.protobuf.ByteString
|
||||||
import kotlinx.android.synthetic.main.channel_fragment.*
|
import kotlinx.android.synthetic.main.channel_fragment.*
|
||||||
|
import java.security.SecureRandom
|
||||||
|
|
||||||
|
|
||||||
// Make an image view dim
|
// Make an image view dim
|
||||||
|
@ -142,7 +145,15 @@ class ChannelFragment : ScreenFragment("Channel"), Logging {
|
||||||
UIViewModel.getChannel(model.radioConfig.value)?.let { old ->
|
UIViewModel.getChannel(model.radioConfig.value)?.let { old ->
|
||||||
val newSettings = old.settings.toBuilder()
|
val newSettings = old.settings.toBuilder()
|
||||||
newSettings.name = channelNameEdit.text.toString().trim()
|
newSettings.name = channelNameEdit.text.toString().trim()
|
||||||
// FIXME, regenerate a new preshared key!
|
|
||||||
|
// Generate a new AES256 key (for any channel not named Default)
|
||||||
|
if (newSettings.name != Channel.defaultChannelName) {
|
||||||
|
debug("ASSIGNING NEW AES256 KEY")
|
||||||
|
val random = SecureRandom()
|
||||||
|
val bytes = ByteArray(32)
|
||||||
|
random.nextBytes(bytes)
|
||||||
|
newSettings.psk = ByteString.copyFrom(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
// 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 redits
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import com.geeksville.android.GeeksvilleApplication
|
import com.geeksville.android.GeeksvilleApplication
|
||||||
import com.geeksville.android.Logging
|
import com.geeksville.android.Logging
|
||||||
import com.geeksville.mesh.NodeInfo
|
import com.geeksville.mesh.NodeInfo
|
||||||
|
@ -131,7 +130,7 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
}
|
}
|
||||||
|
|
||||||
var mapView: MapView? = null
|
var mapView: MapView? = null
|
||||||
|
var mapboxMap: MapboxMap? = null
|
||||||
|
|
||||||
override fun onViewCreated(viewIn: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(viewIn: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(viewIn, savedInstanceState)
|
super.onViewCreated(viewIn, savedInstanceState)
|
||||||
|
@ -146,6 +145,7 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
// Each time the pane is shown start fetching new map info (we do this here instead of
|
// Each time the pane is shown start fetching new map info (we do this here instead of
|
||||||
// onCreate because getMapAsync can die in native code if the view goes away)
|
// onCreate because getMapAsync can die in native code if the view goes away)
|
||||||
v.getMapAsync { map ->
|
v.getMapAsync { map ->
|
||||||
|
mapboxMap = map
|
||||||
|
|
||||||
if (view != null) { // it might have gone away by now
|
if (view != null) { // it might have gone away by now
|
||||||
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
|
// val markerIcon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_twotone_person_pin_24)
|
||||||
|
@ -159,11 +159,6 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
style.addLayer(labelLayer)
|
style.addLayer(labelLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
model.nodeDB.nodes.observe(viewLifecycleOwner, Observer { nodes ->
|
|
||||||
if (view != null)
|
|
||||||
onNodesChanged(map, nodes.values)
|
|
||||||
})
|
|
||||||
|
|
||||||
//map.uiSettings.isScrollGesturesEnabled = true
|
//map.uiSettings.isScrollGesturesEnabled = true
|
||||||
//map.uiSettings.isZoomGesturesEnabled = true
|
//map.uiSettings.isZoomGesturesEnabled = true
|
||||||
}
|
}
|
||||||
|
@ -190,6 +185,16 @@ class MapFragment : ScreenFragment("Map"), Logging {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
mapView?.onResume()
|
mapView?.onResume()
|
||||||
|
|
||||||
|
// FIXME: for now we just set the node positions when the user pages to the map - because
|
||||||
|
// otherwise we try to update in the background which breaks mapbox native code (when view is not shown
|
||||||
|
mapboxMap?.let { map ->
|
||||||
|
// model.nodeDB.nodes.observe(viewLifecycleOwner, Observer { nodes ->
|
||||||
|
model.nodeDB.nodes.value?.values?.let {
|
||||||
|
onNodesChanged(map, it)
|
||||||
|
}
|
||||||
|
//})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
|
|
@ -574,7 +574,8 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
||||||
b.text = device.name
|
b.text = device.name
|
||||||
b.id = View.generateViewId()
|
b.id = View.generateViewId()
|
||||||
b.isEnabled = enabled
|
b.isEnabled = enabled
|
||||||
b.isChecked = device.address == scanModel.selectedNotNull
|
b.isChecked =
|
||||||
|
device.address == scanModel.selectedNotNull && device.bonded // Only show checkbox if device is still paired
|
||||||
deviceRadioGroup.addView(b)
|
deviceRadioGroup.addView(b)
|
||||||
|
|
||||||
// Once we have at least one device, don't show the "looking for" animation - it makes uers think
|
// Once we have at least one device, don't show the "looking for" animation - it makes uers think
|
||||||
|
|
Ładowanie…
Reference in New Issue