From ead36b2fc65b0499a41999b8c3ebb35296edbb5f Mon Sep 17 00:00:00 2001 From: Vadim Furman Date: Mon, 22 Feb 2021 15:00:32 -0800 Subject: [PATCH 1/6] Do not use windowSoftInputMode=adjustPan, as the toolbar hides when input is active. --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 421034192..97d4bf2f1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -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"> From a6c80cc2039f81200077e7dcd46632eba7c9b139 Mon Sep 17 00:00:00 2001 From: Paul Mandal Date: Sat, 27 Feb 2021 22:28:59 -0700 Subject: [PATCH 2/6] Add hopLimit to the DataPacket class, update MeshService to use hopLimit when building its MeshPackets --- app/src/main/java/com/geeksville/mesh/DataPacket.kt | 10 ++++++++-- .../java/com/geeksville/mesh/service/MeshService.kt | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/DataPacket.kt b/app/src/main/java/com/geeksville/mesh/DataPacket.kt index bbb13f1b2..352cdfa6d 100644 --- a/app/src/main/java/com/geeksville/mesh/DataPacket.kt +++ b/app/src/main/java/com/geeksville/mesh/DataPacket.kt @@ -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 { 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 817fdd95e..6d62a08bb 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -540,10 +540,12 @@ class MeshService : Service(), Logging { destId: String, wantAck: Boolean = false, id: Int = 0, + hopLimit: Int = 0, initFn: MeshProtos.SubPacket.Builder.() -> Unit ): MeshPacket = newMeshPacketTo(destId).apply { this.wantAck = wantAck this.id = id + this.hopLimit = hopLimit decoded = MeshProtos.SubPacket.newBuilder().also { initFn(it) }.build() @@ -564,6 +566,7 @@ 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() @@ -584,7 +587,8 @@ class MeshService : Service(), Logging { time = rxTime * 1000L, id = packet.id, dataType = data.portnumValue, - bytes = bytes + bytes = bytes, + hopLimit = hopLimit ) } } @@ -598,7 +602,7 @@ class MeshService : Service(), Logging { }.build() 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) { data = makeData(p.dataType, ByteString.copyFrom(p.bytes)) } } From d33defb5028d474ed71746f0344acf16b10291ec Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 12:01:34 +0800 Subject: [PATCH 3/6] oops - I nuked a string by accident --- app/src/main/res/values/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb3447e1e..0f56c52e1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ + Meshtastic Settings Channel Name Channel options From ae402e8fd2b648efc95fb5423f57e0ba7f83c14f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 13:22:55 +0800 Subject: [PATCH 4/6] add warning text for downrev apps --- .../java/com/geeksville/mesh/MainActivity.kt | 42 +++++++++++++------ .../geeksville/mesh/service/MeshService.kt | 5 ++- .../mesh/service/RadioInterfaceService.kt | 1 + app/src/main/proto | 2 +- app/src/main/res/values/strings.xml | 4 +- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index b79a26156..8e5a7230a 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -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 @@ -64,6 +68,7 @@ import java.nio.charset.Charset import java.text.DateFormat import java.util.* + /* UI design @@ -619,26 +624,38 @@ class MainActivity : AppCompatActivity(), Logging, debug("Getting latest radioconfig from service") try { - model.radioConfig.value = - MeshProtos.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 = + MeshProtos.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 @@ -931,7 +948,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) } @@ -972,7 +990,7 @@ class MainActivity : AppCompatActivity(), Logging, ) } item.isChecked = !item.isChecked // toggle ping test - if(item.isChecked) + if (item.isChecked) postPing() else handler.removeCallbacksAndMessages(null) 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 6d62a08bb..729072844 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -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") @@ -1589,7 +1592,7 @@ class MeshService : Service(), Logging { override fun getRadioConfig(): ByteArray = toRemoteExceptions { this@MeshService.radioConfig?.toByteArray() - ?: throw RadioNotConnectedException() + ?: throw NoRadioConfigException() } override fun setRadioConfig(payload: ByteArray) = toRemoteExceptions { diff --git a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt index 78890c334..112f7010f 100644 --- a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt @@ -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... diff --git a/app/src/main/proto b/app/src/main/proto index b1aed0644..512d1aca0 160000 --- a/app/src/main/proto +++ b/app/src/main/proto @@ -1 +1 @@ -Subproject commit b1aed06442025624841b2288fac273d9bc41c438 +Subproject commit 512d1aca0a066107de749c0c47397c7f9bf9cb99 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0f56c52e1..33c6f745f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -60,8 +60,8 @@ Not connected, select radio below Connected to radio, but it is sleeping Update to %s - Application too old - You must update this application on the Google Play store (or Github). It is too old to talk to this radio. + Application update required + 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 wiki on this topic. None (disable) Short range (but fast) Medium range (but fast) From 0fe6c91a4efaaea6da8f64f1d8b88928ff58fd1c Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 14:16:57 +0800 Subject: [PATCH 5/6] fix #254 typo changed != to ==. fix rxtime displays --- .../geeksville/mesh/service/MeshService.kt | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) 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 729072844..13b314737 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -572,7 +572,7 @@ class MeshService : Service(), Logging { 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 -> { @@ -641,11 +641,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") @@ -663,9 +662,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 @@ -705,15 +703,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()) } } @@ -794,8 +794,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 @@ -804,8 +802,11 @@ class MeshService : Service(), Logging { it.position = it.position?.copy(time = currentSecond()) } - 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() + if (p.hasPosition()) { + handleReceivedPosition(fromNum, p.position, rxTime.toLong() * 1000) + } else updateNodeInfo(fromNum) { // Update our last seen based on any valid timestamps. If the device didn't provide a timestamp make one From 5c19b2649feccbcf76e1a9ac3188665feed01712 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 14:19:44 +0800 Subject: [PATCH 6/6] 1.1.50 --- app/build.gradle | 6 +++--- geeksville-androidlib | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 08e0929fb..ffb8e7599 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 @@ -130,7 +130,7 @@ dependencies { // optional - Test helpers testImplementation "androidx.room:room-testing:$room_version" - testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' diff --git a/geeksville-androidlib b/geeksville-androidlib index 9b15752bb..ff93b088b 160000 --- a/geeksville-androidlib +++ b/geeksville-androidlib @@ -1 +1 @@ -Subproject commit 9b15752bb0ce1fa383a9f4b65e204d4dd0afb03b +Subproject commit ff93b088b4652f099ab99c0359388f2d0541ddc9