Merge branch 'dev' into dev1.2

# Conflicts:
#	app/src/main/java/com/geeksville/mesh/MainActivity.kt
#	app/src/main/java/com/geeksville/mesh/service/MeshService.kt
pull/257/head
Kevin Hester 2021-03-02 14:38:55 +08:00
commit 2fc4099bfc
8 zmienionych plików z 71 dodań i 36 usunięć

Wyświetl plik

@ -31,8 +31,8 @@ android {
applicationId "com.geeksville.mesh"
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
targetSdkVersion 29
versionCode 20148 // format is Mmmss (where M is 1+the numeric major number
versionName "1.1.48"
versionCode 20150 // format is Mmmss (where M is 1+the numeric major number
versionName "1.1.50"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// per https://developer.android.com/studio/write/vector-asset-studio

Wyświetl plik

@ -121,7 +121,7 @@
android:name="com.geeksville.mesh.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
android:windowSoftInputMode="stateAlwaysHidden"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Wyświetl plik

@ -26,7 +26,8 @@ data class DataPacket(
var from: String? = ID_LOCAL, // a nodeID string, or ID_LOCAL for localhost
var time: Long = System.currentTimeMillis(), // msecs since 1970
var id: Int = 0, // 0 means unassigned
var status: MessageStatus? = MessageStatus.UNKNOWN
var status: MessageStatus? = MessageStatus.UNKNOWN,
var hopLimit: Int = 0
) : Parcelable {
/**
@ -60,7 +61,8 @@ data class DataPacket(
parcel.readString(),
parcel.readLong(),
parcel.readInt(),
parcel.readParcelable(MessageStatus::class.java.classLoader)
parcel.readParcelable(MessageStatus::class.java.classLoader),
parcel.readInt()
) {
}
@ -77,6 +79,7 @@ data class DataPacket(
if (dataType != other.dataType) return false
if (!bytes!!.contentEquals(other.bytes!!)) return false
if (status != other.status) return false
if (hopLimit != other.hopLimit) return false
return true
}
@ -89,6 +92,7 @@ data class DataPacket(
result = 31 * result + dataType
result = 31 * result + bytes!!.contentHashCode()
result = 31 * result + status.hashCode()
result = 31 * result + hopLimit
return result
}
@ -100,6 +104,7 @@ data class DataPacket(
parcel.writeLong(time)
parcel.writeInt(id)
parcel.writeParcelable(status, flags)
parcel.writeInt(hopLimit)
}
override fun describeContents(): Int {
@ -115,6 +120,7 @@ data class DataPacket(
time = parcel.readLong()
id = parcel.readInt()
status = parcel.readParcelable(MessageStatus::class.java.classLoader)
hopLimit = parcel.readInt()
}
companion object CREATOR : Parcelable.Creator<DataPacket> {

Wyświetl plik

@ -20,10 +20,14 @@ import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.RemoteException
import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.text.util.Linkify
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
@ -65,6 +69,7 @@ import java.nio.charset.Charset
import java.text.DateFormat
import java.util.*
/*
UI design
@ -620,26 +625,38 @@ class MainActivity : AppCompatActivity(), Logging,
debug("Getting latest radioconfig from service")
try {
model.radioConfig.value =
RadioConfigProtos.RadioConfig.parseFrom(service.radioConfig)
val info = service.myNodeInfo
model.myNodeInfo.value = info
val isOld = info.minAppVersion > BuildConfig.VERSION_CODE
if (isOld)
MaterialAlertDialogBuilder(this)
if (isOld) {
// make links clickable per https://stackoverflow.com/a/62642807
val messageStr = getText(R.string.must_update)
val builder = MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.app_too_old))
.setMessage(getString(R.string.must_update))
.setMessage(messageStr)
.setPositiveButton("Okay") { _, _ ->
info("User acknowledged app is old")
}
.show()
updateNodesFromDevice()
val dialog = builder.show()
// we have a connection to our device now, do the channel change
perhapsChangeChannel()
// Make the textview clickable. Must be called after show()
val view = (dialog.findViewById(android.R.id.message) as TextView?)!!
// Linkify.addLinks(view, Linkify.ALL) // not needed with this method
view.movementMethod = LinkMovementMethod.getInstance()
} else {
// If our app is too old, we probably don't understand the new radioconfig messages
model.radioConfig.value =
RadioConfigProtos.RadioConfig.parseFrom(service.radioConfig)
updateNodesFromDevice()
// we have a connection to our device now, do the channel change
perhapsChangeChannel()
}
} catch (ex: RemoteException) {
warn("Abandoning connect $ex, because we probably just lost device connection")
model.isConnected.value = oldConnection
@ -933,7 +950,8 @@ class MainActivity : AppCompatActivity(), Logging,
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
menu.findItem(R.id.stress_test).isVisible = BuildConfig.DEBUG // only show stress test for debug builds (for now)
menu.findItem(R.id.stress_test).isVisible =
BuildConfig.DEBUG // only show stress test for debug builds (for now)
return super.onPrepareOptionsMenu(menu)
}
@ -974,7 +992,7 @@ class MainActivity : AppCompatActivity(), Logging,
)
}
item.isChecked = !item.isChecked // toggle ping test
if(item.isChecked)
if (item.isChecked)
postPing()
else
handler.removeCallbacksAndMessages(null)

Wyświetl plik

@ -73,6 +73,9 @@ 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?)") :
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 */
class IsUpdatingException() :
RadioNotConnectedException("Operation prohibited during firmware update")
@ -528,7 +531,8 @@ class MeshService : Service(), Logging {
set(value) {
val asChannels = value.settingsList.mapIndexed { i, c ->
ChannelProtos.Channel.newBuilder().apply {
role = if(i == 0) ChannelProtos.Channel.Role.PRIMARY else ChannelProtos.Channel.Role.SECONDARY
role =
if (i == 0) ChannelProtos.Channel.Role.PRIMARY else ChannelProtos.Channel.Role.SECONDARY
index = i
settings = c
}.build()
@ -566,10 +570,12 @@ class MeshService : Service(), Logging {
destId: String,
wantAck: Boolean = false,
id: Int = 0,
hopLimit: Int = 0,
initFn: MeshProtos.Data.Builder.() -> Unit
): MeshPacket = newMeshPacketTo(destId).apply {
this.wantAck = wantAck
this.id = id
this.hopLimit = hopLimit
decoded = MeshProtos.Data.newBuilder().also {
initFn(it)
}.build()
@ -590,9 +596,10 @@ class MeshService : Service(), Logging {
val bytes = data.payload.toByteArray()
val fromId = toNodeID(packet.from)
val toId = toNodeID(packet.to)
val hopLimit = packet.hopLimit
// If the rxTime was not set by the device (because device software was old), guess at a time
val rxTime = if (packet.rxTime == 0) packet.rxTime else currentSecond()
val rxTime = if (packet.rxTime != 0) packet.rxTime else currentSecond()
when {
fromId == null -> {
@ -610,7 +617,8 @@ class MeshService : Service(), Logging {
time = rxTime * 1000L,
id = packet.id,
dataType = data.portnumValue,
bytes = bytes
bytes = bytes,
hopLimit = hopLimit
)
}
}
@ -618,7 +626,7 @@ class MeshService : Service(), Logging {
}
private fun toMeshPacket(p: DataPacket): MeshPacket {
return buildMeshPacket(p.to!!, id = p.id, wantAck = true) {
return buildMeshPacket(p.to!!, id = p.id, wantAck = true, hopLimit = p.hopLimit) {
portnumValue = p.dataType
payload = ByteString.copyFrom(p.bytes)
}
@ -655,11 +663,10 @@ class MeshService : Service(), Logging {
if (myInfo.myNodeNum == packet.from) {
// Handle position updates from the device
if (data.portnumValue == Portnums.PortNum.POSITION_APP_VALUE) {
val rxTime = if (packet.rxTime != 0) packet.rxTime else currentSecond()
handleReceivedPosition(
packet.from,
MeshProtos.Position.parseFrom(data.payload),
rxTime
dataPacket.time
)
} else
debug("Ignoring packet sent from our node, portnum=${data.portnumValue} ${bytes.size} bytes")
@ -679,9 +686,8 @@ class MeshService : Service(), Logging {
// Handle new style position info
Portnums.PortNum.POSITION_APP_VALUE -> {
val rxTime = if (packet.rxTime != 0) packet.rxTime else currentSecond()
val u = MeshProtos.Position.parseFrom(data.payload)
handleReceivedPosition(packet.from, u, rxTime)
handleReceivedPosition(packet.from, u, dataPacket.time)
}
// Handle new style user info
@ -730,15 +736,17 @@ class MeshService : Service(), Logging {
}
}
/// Update our DB of users based on someone sending out a Position subpacket
/** Update our DB of users based on someone sending out a Position subpacket
* @param defaultTime in msecs since 1970
*/
private fun handleReceivedPosition(
fromNum: Int,
p: MeshProtos.Position,
defaultTime: Int = Position.currentTime()
defaultTime: Long = System.currentTimeMillis()
) {
updateNodeInfo(fromNum) {
it.position = Position(p)
updateNodeInfoTime(it, defaultTime)
updateNodeInfoTime(it, (defaultTime / 1000).toInt())
}
}
@ -820,8 +828,6 @@ class MeshService : Service(), Logging {
packet.toString()
)
insertPacket(packetToSave)
// If the rxTime was not set by the device (because device software was old), guess at a time
val rxTime = if (packet.rxTime != 0) packet.rxTime else currentSecond()
// Update last seen for the node that sent the packet, but also for _our node_ because anytime a packet passes
// through our node on the way to the phone that means that local node is also alive in the mesh
@ -832,6 +838,8 @@ class MeshService : Service(), Logging {
// if (p.hasPosition()) handleReceivedPosition(fromNum, p.position, rxTime)
// If the rxTime was not set by the device (because device software was old), guess at a time
val rxTime = if (packet.rxTime != 0) packet.rxTime else currentSecond()
updateNodeInfo(fromNum) {
// Update our last seen based on any valid timestamps. If the device didn't provide a timestamp make one
updateNodeInfoTime(it, rxTime)
@ -1203,7 +1211,8 @@ class MeshService : Service(), Logging {
ignoreException {
// 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
val curConfigRegion =
radioConfig?.preferences?.region ?: RadioConfigProtos.RegionCode.Unset
if (curConfigRegion != RadioConfigProtos.RegionCode.Unset) {
info("Using device region $curConfigRegion (code ${curConfigRegion.number})")
curRegionValue = curConfigRegion.number
@ -1626,7 +1635,7 @@ class MeshService : Service(), Logging {
override fun getRadioConfig(): ByteArray = toRemoteExceptions {
this@MeshService.radioConfig?.toByteArray()
?: throw RadioNotConnectedException()
?: throw NoRadioConfigException()
}
override fun setRadioConfig(payload: ByteArray) = toRemoteExceptions {
@ -1634,7 +1643,7 @@ class MeshService : Service(), Logging {
}
override fun getChannels(): ByteArray = toRemoteExceptions {
channelSet.toByteArray()
channelSet.toByteArray()
}
override fun setChannels(payload: ByteArray?) {

Wyświetl plik

@ -26,6 +26,7 @@ open class RadioNotConnectedException(message: String = "Not connected to radio"
BLEException(message)
/**
* Handles the bluetooth link with a mesh radio device. Does not cache any device state,
* just does bluetooth comms etc...

@ -1 +1 @@
Subproject commit 39c41e0ef130e7239eed916f7609aad1aa7f6db8
Subproject commit 7de496ffe941f88e9d99c2ef2c7bc01f79efe11e

Wyświetl plik

@ -1,4 +1,5 @@
<resources>
<string name="app_name" translatable="false">Meshtastic</string>
<string name="action_settings">Settings</string>
<string name="channel_name">Channel Name</string>
<string name="channel_options">Channel options</string>
@ -59,8 +60,8 @@
<string name="not_connected">Not connected, select radio below</string>
<string name="connected_sleeping">Connected to radio, but it is sleeping</string>
<string name="update_to">Update to %s</string>
<string name="app_too_old">Application too old</string>
<string name="must_update">You must update this application on the Google Play store (or Github). It is too old to talk to this radio.</string>
<string name="app_too_old">Application update required</string>
<string name="must_update">You must update this application on the Google Play store (or Github). It is too old to talk to this radio firmware. Please read our <a href="https://www.meshtastic.org/software/android-too-old.html">wiki</a> on this topic.</string>
<string name="none">None (disable)</string>
<string name="modem_config_short">Short range (but fast)</string>
<string name="modem_config_medium">Medium range (but fast)</string>