From c8107441dec78c5187de8c6ba085ba0eb9be6227 Mon Sep 17 00:00:00 2001 From: goga Date: Mon, 15 Mar 2021 23:46:53 +0500 Subject: [PATCH 1/6] display timeAgo properly and show coords in users screen --- .../com/geeksville/mesh/ui/UsersFragment.kt | 36 ++++++------------- .../main/res/layout/adapter_node_layout.xml | 13 +++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index 0b6529679..60116a948 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -17,6 +17,7 @@ import com.geeksville.mesh.R import com.geeksville.mesh.databinding.AdapterNodeLayoutBinding import com.geeksville.mesh.databinding.NodelistFragmentBinding import com.geeksville.mesh.model.UIViewModel +import com.geeksville.util.formatAgo import java.text.ParseException import java.util.* @@ -24,6 +25,7 @@ import java.util.* class UsersFragment : ScreenFragment("Users"), Logging { private var _binding: NodelistFragmentBinding? = null + // This property is only valid between onCreateView and onDestroyView. private val binding get() = _binding!! @@ -34,6 +36,7 @@ class UsersFragment : ScreenFragment("Users"), Logging { class ViewHolder(itemView: AdapterNodeLayoutBinding) : RecyclerView.ViewHolder(itemView.root) { val nodeNameView = itemView.nodeNameView val distanceView = itemView.distanceView + val coordsview = itemView.coordsView val batteryPctView = itemView.batteryPercentageView val lastTime = itemView.lastConnectionView val powerIcon = itemView.batteryIcon @@ -108,6 +111,13 @@ class UsersFragment : ScreenFragment("Users"), Logging { holder.nodeNameView.text = n.user?.longName ?: n.user?.id ?: "Unknown node" val ourNodeInfo = model.nodeDB.ourNodeInfo + val pos = ourNodeInfo?.position; + if (pos != null) { + holder.coordsview.text = pos.latitude.toString() + " " + pos.longitude + holder.coordsview.visibility = View.VISIBLE + } else { + holder.coordsview.visibility = View.INVISIBLE + } val distance = ourNodeInfo?.distanceStr(n) if (distance != null) { holder.distanceView.text = distance @@ -118,7 +128,7 @@ class UsersFragment : ScreenFragment("Users"), Logging { renderBattery(n.batteryPctLevel, holder) - holder.lastTime.text = getLastTimeValue(n) + holder.lastTime.text = formatAgo(n.lastSeen); } private var nodes = arrayOf() @@ -150,30 +160,6 @@ class UsersFragment : ScreenFragment("Users"), Logging { }) } - private fun getLastTimeValue(n: NodeInfo): String { - var lastTimeText = "?" - val currentTime = (System.currentTimeMillis()/1000).toInt() - val threeDaysLong = 3 * 60*60*24 - - //if the lastSeen is too old - if (n.lastSeen < (currentTime - threeDaysLong)) - return lastTimeText - - try { - val toLong: Long = n.lastSeen.toLong() - val long1000 = toLong * 1000L - val date = Date(long1000) - val timeFormat = DateFormat.getTimeFormat(context) - - lastTimeText = timeFormat.format(date) - - } catch (e: ParseException) { - // - } - return lastTimeText - } - - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? diff --git a/app/src/main/res/layout/adapter_node_layout.xml b/app/src/main/res/layout/adapter_node_layout.xml index 86d70f043..def23200e 100644 --- a/app/src/main/res/layout/adapter_node_layout.xml +++ b/app/src/main/res/layout/adapter_node_layout.xml @@ -51,6 +51,19 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imageView" /> + + Okay You must set a region! Region + 55.332244 34.442211 From 53745ca9f58685ee0df92289013fec246d11d3e3 Mon Sep 17 00:00:00 2001 From: goga Date: Tue, 16 Mar 2021 00:05:28 +0500 Subject: [PATCH 2/6] display timeAgo properly and show coords in users screen --- app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt | 3 ++- app/src/main/proto | 2 +- design | 2 +- geeksville-androidlib | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt index e4d6bd771..67a1a8583 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt @@ -13,6 +13,7 @@ import com.geeksville.android.Logging import com.geeksville.mesh.NodeInfo import com.geeksville.mesh.R import com.geeksville.mesh.model.UIViewModel +import com.geeksville.util.formatAgo import com.mapbox.geojson.Feature import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point @@ -79,7 +80,7 @@ class MapFragment : ScreenFragment("Map"), Logging { ) ) node.user?.let { - f.addStringProperty("name", it.longName) + f.addStringProperty("name", it.longName + " " + formatAgo(node.lastSeen)) } f } diff --git a/app/src/main/proto b/app/src/main/proto index 7c025b9a4..ac26ffdc7 160000 --- a/app/src/main/proto +++ b/app/src/main/proto @@ -1 +1 @@ -Subproject commit 7c025b9a4d54bb410ec17ee653122861b413f177 +Subproject commit ac26ffdc71dad5765124186df5ec38771a0e5240 diff --git a/design b/design index a81074152..d0339f029 160000 --- a/design +++ b/design @@ -1 +1 @@ -Subproject commit a81074152157fa54b0d02ccbbd6a6357cc3cedcf +Subproject commit d0339f0297c629f1bd6873b4abccfecb98443538 diff --git a/geeksville-androidlib b/geeksville-androidlib index 99cf0da30..6da250358 160000 --- a/geeksville-androidlib +++ b/geeksville-androidlib @@ -1 +1 @@ -Subproject commit 99cf0da30fe41163a735ac291f3dd018a7d6295d +Subproject commit 6da250358ed13e3c58fd4fa2a123b01b3826d4bf From 452bf6f6cb6ee11f12baee660bd43aa4ed8143c2 Mon Sep 17 00:00:00 2001 From: goga Date: Tue, 16 Mar 2021 10:04:01 +0500 Subject: [PATCH 3/6] show coordinates with geo url to open in other mapping app --- .../geeksville/mesh/service/MeshService.kt | 6 +++--- .../geeksville/mesh/service/MockInterface.kt | 2 +- .../com/geeksville/mesh/ui/MapFragment.kt | 12 ++++++++---- .../com/geeksville/mesh/ui/UsersFragment.kt | 19 +++++++++++-------- .../main/res/layout/adapter_node_layout.xml | 3 ++- 5 files changed, 25 insertions(+), 17 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 217ee0f29..f40b38115 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1235,7 +1235,7 @@ class MeshService : Service(), Logging { MyNodeInfo( myNodeNum, hasGps, - hwModel, + hwModelDeprecated, firmwareVersion, firmwareUpdateFilename != null, isBluetoothInterface && SoftwareUpdateService.shouldUpdate( @@ -1545,10 +1545,10 @@ class MeshService : Service(), Logging { */ private fun setFirmwareUpdateFilename(info: MeshProtos.MyNodeInfo) { firmwareUpdateFilename = try { - if (info.region != null && info.firmwareVersion != null && info.hwModel != null) + if (info.region != null && info.firmwareVersion != null && info.hwModelDeprecated != null) SoftwareUpdateService.getUpdateFilename( this, - info.hwModel + info.hwModelDeprecated ) else null diff --git a/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt b/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt index 7c76458e5..a6786c13c 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MockInterface.kt @@ -160,7 +160,7 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi MeshProtos.FromRadio.newBuilder().apply { myInfo = MeshProtos.MyNodeInfo.newBuilder().apply { myNodeNum = MY_NODE - hwModel = "Sim" + hwModelDeprecated = "Sim" messageTimeoutMsec = 5 * 60 * 1000 firmwareVersion = service.getString(R.string.cur_firmware_version) numBands = 13 diff --git a/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt index 67a1a8583..f40c78b3d 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/MapFragment.kt @@ -80,7 +80,7 @@ class MapFragment : ScreenFragment("Map"), Logging { ) ) node.user?.let { - f.addStringProperty("name", it.longName + " " + formatAgo(node.lastSeen)) + f.addStringProperty("name", it.longName + " " + formatAgo(p.time)) } f } @@ -94,7 +94,8 @@ class MapFragment : ScreenFragment("Map"), Logging { } fun zoomToNodes(map: MapboxMap) { - val nodesWithPosition = model.nodeDB.nodes.value?.values?.filter { it.validPosition != null } + val nodesWithPosition = + model.nodeDB.nodes.value?.values?.filter { it.validPosition != null } if (nodesWithPosition != null && nodesWithPosition.isNotEmpty()) { val update = if (nodesWithPosition.size >= 2) { // Multiple nodes, make them all fit on the map view @@ -159,7 +160,10 @@ class MapFragment : ScreenFragment("Map"), Logging { 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 = - ContextCompat.getDrawable(requireActivity(), R.drawable.ic_twotone_person_pin_24)!! + ContextCompat.getDrawable( + requireActivity(), + R.drawable.ic_twotone_person_pin_24 + )!! map.setStyle(Style.OUTDOORS) { style -> style.addSource(nodePositions) @@ -177,7 +181,7 @@ class MapFragment : ScreenFragment("Map"), Logging { // Any times nodes change update our map model.nodeDB.nodes.observe(viewLifecycleOwner, Observer { nodes -> - if(isViewVisible) + if (isViewVisible) onNodesChanged(map, nodes.values) }) zoomToNodes(map) diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index 60116a948..0eed4d7a2 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -2,11 +2,13 @@ package com.geeksville.mesh.ui import android.os.Bundle -import android.text.format.DateFormat +import android.text.Html +import android.text.method.LinkMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat +import androidx.core.text.HtmlCompat import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager @@ -18,8 +20,6 @@ import com.geeksville.mesh.databinding.AdapterNodeLayoutBinding import com.geeksville.mesh.databinding.NodelistFragmentBinding import com.geeksville.mesh.model.UIViewModel import com.geeksville.util.formatAgo -import java.text.ParseException -import java.util.* class UsersFragment : ScreenFragment("Users"), Logging { @@ -36,7 +36,7 @@ class UsersFragment : ScreenFragment("Users"), Logging { class ViewHolder(itemView: AdapterNodeLayoutBinding) : RecyclerView.ViewHolder(itemView.root) { val nodeNameView = itemView.nodeNameView val distanceView = itemView.distanceView - val coordsview = itemView.coordsView + val coordsView = itemView.coordsView val batteryPctView = itemView.batteryPercentageView val lastTime = itemView.lastConnectionView val powerIcon = itemView.batteryIcon @@ -111,12 +111,15 @@ class UsersFragment : ScreenFragment("Users"), Logging { holder.nodeNameView.text = n.user?.longName ?: n.user?.id ?: "Unknown node" val ourNodeInfo = model.nodeDB.ourNodeInfo - val pos = ourNodeInfo?.position; + val pos = ourNodeInfo?.validPosition; if (pos != null) { - holder.coordsview.text = pos.latitude.toString() + " " + pos.longitude - holder.coordsview.visibility = View.VISIBLE + val html = + "${pos.latitude.toString()} ${pos.longitude}" + holder.coordsView.text = HtmlCompat.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) + holder.coordsView.movementMethod = LinkMovementMethod.getInstance() + holder.coordsView.visibility = View.VISIBLE } else { - holder.coordsview.visibility = View.INVISIBLE + holder.coordsView.visibility = View.INVISIBLE } val distance = ourNodeInfo?.distanceStr(n) if (distance != null) { diff --git a/app/src/main/res/layout/adapter_node_layout.xml b/app/src/main/res/layout/adapter_node_layout.xml index def23200e..e2b5fbe0a 100644 --- a/app/src/main/res/layout/adapter_node_layout.xml +++ b/app/src/main/res/layout/adapter_node_layout.xml @@ -55,10 +55,11 @@ android:id="@+id/coords_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="76dp" + android:layout_marginStart="140dp" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:text="@string/sample_coords" + android:textAppearance="@style/TextAppearance.AppCompat.Small" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/imageView" From 6958e3c86a1b05d2d3a51531c0fa07b26e8170b8 Mon Sep 17 00:00:00 2001 From: goga Date: Tue, 16 Mar 2021 11:38:42 +0500 Subject: [PATCH 4/6] coords position fix --- app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt | 3 ++- app/src/main/res/layout/adapter_node_layout.xml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index 0eed4d7a2..f5f743c14 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -113,8 +113,9 @@ class UsersFragment : ScreenFragment("Users"), Logging { val ourNodeInfo = model.nodeDB.ourNodeInfo val pos = ourNodeInfo?.validPosition; if (pos != null) { + val coords = String.format("%.5f %.5f", pos.latitude, pos.longitude).replace(",",".") val html = - "${pos.latitude.toString()} ${pos.longitude}" + "${coords}" holder.coordsView.text = HtmlCompat.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) holder.coordsView.movementMethod = LinkMovementMethod.getInstance() holder.coordsView.visibility = View.VISIBLE diff --git a/app/src/main/res/layout/adapter_node_layout.xml b/app/src/main/res/layout/adapter_node_layout.xml index e2b5fbe0a..f5577aaac 100644 --- a/app/src/main/res/layout/adapter_node_layout.xml +++ b/app/src/main/res/layout/adapter_node_layout.xml @@ -55,13 +55,13 @@ android:id="@+id/coords_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="140dp" + android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginBottom="8dp" android:text="@string/sample_coords" android:textAppearance="@style/TextAppearance.AppCompat.Small" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintStart_toStartOf="parent" + app:layout_constraintStart_toEndOf="@+id/distance_view" app:layout_constraintTop_toBottomOf="@+id/imageView" app:layout_constraintVertical_bias="0.0" /> From 78a08898fe6097f7f7198282d9e2a26afc5c2d30 Mon Sep 17 00:00:00 2001 From: Vadim Furman Date: Wed, 17 Mar 2021 21:00:01 -0700 Subject: [PATCH 5/6] Save messages in CSV and fix position broadcast --- .../java/com/geeksville/mesh/MainActivity.kt | 67 +++++++++++++++++-- .../geeksville/mesh/database/dao/PacketDao.kt | 2 +- .../geeksville/mesh/database/entity/Packet.kt | 27 +++++++- .../geeksville/mesh/service/MeshService.kt | 41 +++++++----- .../com/geeksville/mesh/ui/LocationUtils.kt | 11 ++- app/src/main/res/menu/menu_main.xml | 4 ++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 126 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 136169f67..2d2320950 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -20,9 +20,7 @@ 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 @@ -43,8 +41,8 @@ import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.Logging import com.geeksville.android.ServiceClient import com.geeksville.concurrent.handledLaunch +import com.geeksville.mesh.database.entity.Packet import com.geeksville.mesh.databinding.ActivityMainBinding -import com.geeksville.mesh.model.Channel import com.geeksville.mesh.model.ChannelSet import com.geeksville.mesh.model.DeviceVersion import com.geeksville.mesh.model.UIViewModel @@ -66,9 +64,11 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancel +import java.io.FileOutputStream import java.nio.charset.Charset import java.text.DateFormat import java.util.* +import kotlin.math.roundToInt /* @@ -132,6 +132,7 @@ class MainActivity : AppCompatActivity(), Logging, const val RC_SIGN_IN = 12 // google signin completed const val RC_SELECT_DEVICE = 13 // seems to be hardwired in CompanionDeviceManager to add 65536 + const val CREATE_CSV_FILE = 14 } private lateinit var binding: ActivityMainBinding @@ -555,6 +556,18 @@ class MainActivity : AppCompatActivity(), Logging, else -> warn("BLE device select intent failed") } + CREATE_CSV_FILE -> { + if (resultCode == Activity.RESULT_OK) { + data?.data?.let { file_uri -> + model.allPackets.observe(this, { packets -> + if (packets != null) { + saveMessagesCSV(file_uri, packets) + model.allPackets.removeObservers(this) + } + }) + } + } + } } } @@ -659,7 +672,7 @@ class MainActivity : AppCompatActivity(), Logging, val curVer = DeviceVersion(info.firmwareVersion ?: "0.0.0") val minVer = DeviceVersion("1.2.0") - if(curVer < minVer) + if (curVer < minVer) 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 @@ -869,8 +882,7 @@ class MainActivity : AppCompatActivity(), Logging, errormsg("Device error during init ${ex.message}") model.isConnected.value = MeshService.ConnectionState.valueOf(service.connectionState()) - } - finally { + } finally { connectionJob = null } @@ -1029,6 +1041,15 @@ class MainActivity : AppCompatActivity(), Logging, fragmentTransaction.commit() return true } + R.id.save_messages_csv -> { + val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "application/csv" + putExtra(Intent.EXTRA_TITLE, "messages.csv") + } + startActivityForResult(intent, CREATE_CSV_FILE) + return true + } else -> super.onOptionsItemSelected(item) } } @@ -1042,4 +1063,38 @@ class MainActivity : AppCompatActivity(), Logging, errormsg("Can not find the version: ${e.message}") } } + + private fun saveMessagesCSV(file_uri: Uri, packets: List) { + // Extract distances to this device from position messages and put (node,SNR,distance) in + // the file_uri + val myNodeNum = model.myNodeInfo.value?.myNodeNum ?: return + + applicationContext.contentResolver.openFileDescriptor(file_uri, "w")?.use { + FileOutputStream(it.fileDescriptor).use { fs -> + // Write header + fs.write(("from,snr,time,dist\n").toByteArray()); + // Packets are ordered by time, we keep most recent position of + // our device in my_position. + var my_position: MeshProtos.Position? = null + packets.forEach { + it.proto?.let { packet_proto -> + it.position?.let { position -> + if (packet_proto.from == myNodeNum) { + my_position = position + } else if (my_position != null) { + val dist: Int = + positionToMeter(my_position!!, position).roundToInt() + fs.write( + ("${packet_proto.from.toUInt().toString(16)}," + + "${packet_proto.rxSnr},${packet_proto.rxTime},$dist\n") + .toByteArray() + ) + } + } + } + } + } + } + } } + diff --git a/app/src/main/java/com/geeksville/mesh/database/dao/PacketDao.kt b/app/src/main/java/com/geeksville/mesh/database/dao/PacketDao.kt index 3eb4e4031..a02016a94 100644 --- a/app/src/main/java/com/geeksville/mesh/database/dao/PacketDao.kt +++ b/app/src/main/java/com/geeksville/mesh/database/dao/PacketDao.kt @@ -9,7 +9,7 @@ import com.geeksville.mesh.database.entity.Packet @Dao interface PacketDao { - @Query("Select * from packet order by rowid desc limit 0,:maxItem") + @Query("Select * from packet order by received_date desc limit 0,:maxItem") fun getAllPacket(maxItem: Int): LiveData> @Insert diff --git a/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt b/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt index 0c4d37e17..ad516e1ec 100644 --- a/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt +++ b/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt @@ -3,6 +3,10 @@ package com.geeksville.mesh.database.entity import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey +import com.geeksville.mesh.MeshProtos +import com.geeksville.mesh.Portnums +import com.google.protobuf.TextFormat +import java.io.IOException @Entity(tableName = "packet") @@ -12,6 +16,25 @@ data class Packet(@PrimaryKey val uuid: String, @ColumnInfo(name = "message") val raw_message: String ) { - - + val proto: MeshProtos.MeshPacket? + get() { + if (message_type == "packet") { + val builder = MeshProtos.MeshPacket.newBuilder() + try { + TextFormat.getParser().merge(raw_message, builder) + return builder.build() + } catch (e: IOException) { + } + } + return null + } + val position: MeshProtos.Position? + get() { + return proto?.run { + if (hasDecoded() && decoded.portnumValue == Portnums.PortNum.POSITION_APP_VALUE) { + return MeshProtos.Position.parseFrom(decoded.payload) + } + return null + } + } } \ No newline at end of file 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 217ee0f29..236c352e9 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -163,15 +163,13 @@ class MeshService : Service(), Logging { */ @SuppressLint("MissingPermission") @UiThread - private fun startLocationRequests() { + private fun startLocationRequests(requestInterval: Long) { // FIXME - currently we don't support location reading without google play if (fusedLocationClient == null && isGooglePlayAvailable(this)) { GeeksvilleApplication.analytics.track("location_start") // Figure out how many users needed to use the phone GPS - + val request = LocationRequest.create().apply { - interval = - 5 * 60 * 1000 // FIXME, do more like once every 5 mins while we are connected to our radio _and_ someone else is in the mesh - + interval = requestInterval priority = LocationRequest.PRIORITY_HIGH_ACCURACY } val builder = LocationSettingsRequest.Builder().addLocationRequest(request) @@ -938,19 +936,28 @@ class MeshService : Service(), Logging { private fun onNodeDBChanged() { maybeUpdateServiceStatusNotification() - // we don't ask for GPS locations from android if our device has a built in GPS - // Note: myNodeInfo can go away if we lose connections, so it might be null - if (myNodeInfo?.hasGPS != true) { - // If we have at least one other person in the mesh, send our GPS position otherwise stop listening to GPS + serviceScope.handledLaunch(Dispatchers.Main) { + setupLocationRequest() + } + } - serviceScope.handledLaunch(Dispatchers.Main) { - if (numOnlineNodes >= 2) - startLocationRequests() - else - stopLocationRequests() - } - } else - debug("Our radio has a built in GPS, so not reading GPS in phone") + private var locationRequestInterval: Long = 0; + private fun setupLocationRequest () { + val desiredInterval: Long = if (myNodeInfo?.hasGPS == true) { + 0L // no requests when device has GPS + } else if (numOnlineNodes < 2) { + 5 * 60 * 1000L // send infrequently, device needs these requests to set its clock + } else { + radioConfig?.preferences?.positionBroadcastSecs?.times( 1000L) ?: 5 * 60 * 1000L + } + + debug("desired location request $desiredInterval, current $locationRequestInterval") + + if (desiredInterval != locationRequestInterval) { + if (locationRequestInterval > 0) stopLocationRequests() + if (desiredInterval > 0) startLocationRequests(desiredInterval) + locationRequestInterval = desiredInterval + } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/LocationUtils.kt b/app/src/main/java/com/geeksville/mesh/ui/LocationUtils.kt index 10df4cacc..eed32c702 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/LocationUtils.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/LocationUtils.kt @@ -1,5 +1,6 @@ package com.geeksville.mesh.ui +import com.geeksville.mesh.MeshProtos import kotlin.math.cos import kotlin.math.sin @@ -124,6 +125,14 @@ fun latLongToMeter( return 6366000 * tt } +// Same as above, but takes Mesh Position proto. +fun positionToMeter(a: MeshProtos.Position, b: MeshProtos.Position): Double { + return latLongToMeter( + a.latitudeI * 1e-7, + a.longitudeI * 1e-7, + b.latitudeI * 1e-7, + b.longitudeI * 1e-7) +} /** * Convert degrees/mins/secs to a single double * @@ -186,4 +195,4 @@ fun bearing( */ fun radToBearing(rad: Double): Double { return (Math.toDegrees(rad) + 360) % 360 -} \ No newline at end of file +} diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index db3e1a6da..45f8e5cf0 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -20,6 +20,10 @@ android:id="@+id/advanced_settings" app:showAsAction="withText" android:title="@string/advanced_settings" /> + Okay You must set a region! Region + Save messages as csv... From 3e3dc47440ce9006eaa11f7f80c2d56fab42dfea Mon Sep 17 00:00:00 2001 From: goga Date: Thu, 18 Mar 2021 11:11:37 +0500 Subject: [PATCH 6/6] oops, show not only my coords, but neighbour's too --- .../com/geeksville/mesh/ui/UsersFragment.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index f5f743c14..66bc2c270 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -20,6 +20,7 @@ import com.geeksville.mesh.databinding.AdapterNodeLayoutBinding import com.geeksville.mesh.databinding.NodelistFragmentBinding import com.geeksville.mesh.model.UIViewModel import com.geeksville.util.formatAgo +import java.net.URLEncoder class UsersFragment : ScreenFragment("Users"), Logging { @@ -107,21 +108,28 @@ class UsersFragment : ScreenFragment("Users"), Logging { */ override fun onBindViewHolder(holder: ViewHolder, position: Int) { val n = nodes[position] + val name = n.user?.longName ?: n.user?.id ?: "Unknown node" + holder.nodeNameView.text = name - holder.nodeNameView.text = n.user?.longName ?: n.user?.id ?: "Unknown node" - - val ourNodeInfo = model.nodeDB.ourNodeInfo - val pos = ourNodeInfo?.validPosition; + val pos = n.validPosition; if (pos != null) { - val coords = String.format("%.5f %.5f", pos.latitude, pos.longitude).replace(",",".") + val coords = + String.format("%.5f %.5f", pos.latitude, pos.longitude).replace(",", ".") val html = - "${coords}" + "${coords}" holder.coordsView.text = HtmlCompat.fromHtml(html, Html.FROM_HTML_MODE_LEGACY) holder.coordsView.movementMethod = LinkMovementMethod.getInstance() holder.coordsView.visibility = View.VISIBLE } else { holder.coordsView.visibility = View.INVISIBLE } + + val ourNodeInfo = model.nodeDB.ourNodeInfo val distance = ourNodeInfo?.distanceStr(n) if (distance != null) { holder.distanceView.text = distance