kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
Example project: Appease Detekt (#3125)
rodzic
07d798d506
commit
299dac415d
|
@ -22,17 +22,14 @@ import android.os.Parcelable
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
/**
|
/** Generic [Parcel.readParcelable] Android 13 compatibility extension. */
|
||||||
* Generic [Parcel.readParcelable] Android 13 compatibility extension.
|
private inline fun <reified T : Parcelable> Parcel.readParcelableCompat(loader: ClassLoader?): T? =
|
||||||
*/
|
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||||
private inline fun <reified T : Parcelable> Parcel.readParcelableCompat(loader: ClassLoader?): T? {
|
|
||||||
return if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
readParcelable(loader)
|
readParcelable(loader)
|
||||||
} else {
|
} else {
|
||||||
readParcelable(loader, T::class.java)
|
readParcelable(loader, T::class.java)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
enum class MessageStatus : Parcelable {
|
enum class MessageStatus : Parcelable {
|
||||||
|
@ -41,17 +38,16 @@ enum class MessageStatus : Parcelable {
|
||||||
QUEUED, // Waiting to send to the mesh as soon as we connect to the device
|
QUEUED, // Waiting to send to the mesh as soon as we connect to the device
|
||||||
ENROUTE, // Delivered to the radio, but no ACK or NAK received
|
ENROUTE, // Delivered to the radio, but no ACK or NAK received
|
||||||
DELIVERED, // We received an ack
|
DELIVERED, // We received an ack
|
||||||
ERROR // We received back a nak, message not delivered
|
ERROR, // We received back a nak, message not delivered
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** A parcelable version of the protobuf MeshPacket + Data subpacket. */
|
||||||
* A parcelable version of the protobuf MeshPacket + Data subpacket.
|
|
||||||
*/
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class DataPacket(
|
data class DataPacket(
|
||||||
var to: String? = ID_BROADCAST, // a nodeID string, or ID_BROADCAST for broadcast
|
var to: String? = ID_BROADCAST, // a nodeID string, or ID_BROADCAST for broadcast
|
||||||
val bytes: ByteArray?,
|
val bytes: ByteArray?,
|
||||||
val dataType: Int, // A port number for this packet (formerly called DataType, see portnums.proto for new usage instructions)
|
// A port number for this packet (formerly called DataType, see portnums.proto for new usage instructions)
|
||||||
|
val dataType: Int,
|
||||||
var from: String? = ID_LOCAL, // a nodeID string, or ID_LOCAL for localhost
|
var from: String? = ID_LOCAL, // a nodeID string, or ID_LOCAL for localhost
|
||||||
var time: Long = System.currentTimeMillis(), // msecs since 1970
|
var time: Long = System.currentTimeMillis(), // msecs since 1970
|
||||||
var id: Int = 0, // 0 means unassigned
|
var id: Int = 0, // 0 means unassigned
|
||||||
|
@ -61,55 +57,57 @@ data class DataPacket(
|
||||||
var wantAck: Boolean = true, // If true, the receiver should send an ack back
|
var wantAck: Boolean = true, // If true, the receiver should send an ack back
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
/**
|
/** If there was an error with this message, this string describes what was wrong. */
|
||||||
* If there was an error with this message, this string describes what was wrong.
|
|
||||||
*/
|
|
||||||
var errorMessage: String? = null
|
var errorMessage: String? = null
|
||||||
|
|
||||||
/**
|
/** Syntactic sugar to make it easy to create text messages */
|
||||||
* Syntactic sugar to make it easy to create text messages
|
constructor(
|
||||||
*/
|
to: String?,
|
||||||
constructor(to: String?, channel: Int, text: String) : this(
|
channel: Int,
|
||||||
|
text: String,
|
||||||
|
) : this(
|
||||||
to = to,
|
to = to,
|
||||||
bytes = text.encodeToByteArray(),
|
bytes = text.encodeToByteArray(),
|
||||||
dataType = Portnums.PortNum.TEXT_MESSAGE_APP_VALUE,
|
dataType = Portnums.PortNum.TEXT_MESSAGE_APP_VALUE,
|
||||||
channel = channel
|
channel = channel,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/** If this is a text message, return the string, otherwise null */
|
||||||
* If this is a text message, return the string, otherwise null
|
|
||||||
*/
|
|
||||||
val text: String?
|
val text: String?
|
||||||
get() = if (dataType == Portnums.PortNum.TEXT_MESSAGE_APP_VALUE) {
|
get() =
|
||||||
bytes?.decodeToString()
|
if (dataType == Portnums.PortNum.TEXT_MESSAGE_APP_VALUE) {
|
||||||
} else {
|
bytes?.decodeToString()
|
||||||
null
|
} else {
|
||||||
}
|
null
|
||||||
|
}
|
||||||
|
|
||||||
val alert: String?
|
val alert: String?
|
||||||
get() = if (dataType == Portnums.PortNum.ALERT_APP_VALUE) {
|
get() =
|
||||||
bytes?.decodeToString()
|
if (dataType == Portnums.PortNum.ALERT_APP_VALUE) {
|
||||||
} else {
|
bytes?.decodeToString()
|
||||||
null
|
} else {
|
||||||
}
|
null
|
||||||
|
}
|
||||||
|
|
||||||
constructor(to: String?, channel: Int, waypoint: MeshProtos.Waypoint) : this(
|
constructor(
|
||||||
to = to,
|
to: String?,
|
||||||
bytes = waypoint.toByteArray(),
|
channel: Int,
|
||||||
dataType = Portnums.PortNum.WAYPOINT_APP_VALUE,
|
waypoint: MeshProtos.Waypoint,
|
||||||
channel = channel
|
) : this(to = to, bytes = waypoint.toByteArray(), dataType = Portnums.PortNum.WAYPOINT_APP_VALUE, channel = channel)
|
||||||
)
|
|
||||||
|
|
||||||
val waypoint: MeshProtos.Waypoint?
|
val waypoint: MeshProtos.Waypoint?
|
||||||
get() = if (dataType == Portnums.PortNum.WAYPOINT_APP_VALUE) {
|
get() =
|
||||||
MeshProtos.Waypoint.parseFrom(bytes)
|
if (dataType == Portnums.PortNum.WAYPOINT_APP_VALUE) {
|
||||||
} else {
|
MeshProtos.Waypoint.parseFrom(bytes)
|
||||||
null
|
} else {
|
||||||
}
|
null
|
||||||
|
}
|
||||||
|
|
||||||
// Autogenerated comparision, because we have a byte array
|
// Autogenerated comparision, because we have a byte array
|
||||||
|
|
||||||
constructor(parcel: Parcel) : this(
|
constructor(
|
||||||
|
parcel: Parcel,
|
||||||
|
) : this(
|
||||||
parcel.readString(),
|
parcel.readString(),
|
||||||
parcel.createByteArray(),
|
parcel.createByteArray(),
|
||||||
parcel.readInt(),
|
parcel.readInt(),
|
||||||
|
@ -169,9 +167,7 @@ data class DataPacket(
|
||||||
parcel.writeInt(if (wantAck) 1 else 0)
|
parcel.writeInt(if (wantAck) 1 else 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int = 0
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update our object from our parcel (used for inout parameters
|
// Update our object from our parcel (used for inout parameters
|
||||||
fun readFromParcel(parcel: Parcel) {
|
fun readFromParcel(parcel: Parcel) {
|
||||||
|
@ -203,14 +199,11 @@ data class DataPacket(
|
||||||
const val PKC_CHANNEL_INDEX = 8
|
const val PKC_CHANNEL_INDEX = 8
|
||||||
|
|
||||||
fun nodeNumToDefaultId(n: Int): String = "!%08x".format(n)
|
fun nodeNumToDefaultId(n: Int): String = "!%08x".format(n)
|
||||||
|
|
||||||
fun idToDefaultNodeNum(id: String?): Int? = runCatching { id?.toLong(16)?.toInt() }.getOrNull()
|
fun idToDefaultNodeNum(id: String?): Int? = runCatching { id?.toLong(16)?.toInt() }.getOrNull()
|
||||||
|
|
||||||
override fun createFromParcel(parcel: Parcel): DataPacket {
|
override fun createFromParcel(parcel: Parcel): DataPacket = DataPacket(parcel)
|
||||||
return DataPacket(parcel)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newArray(size: Int): Array<DataPacket?> {
|
override fun newArray(size: Int): Array<DataPacket?> = arrayOfNulls(size)
|
||||||
return arrayOfNulls(size)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,21 +23,22 @@ import kotlinx.parcelize.Parcelize
|
||||||
// MyNodeInfo sent via special protobuf from radio
|
// MyNodeInfo sent via special protobuf from radio
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class MyNodeInfo(
|
data class MyNodeInfo(
|
||||||
val myNodeNum: Int,
|
val myNodeNum: Int,
|
||||||
val hasGPS: Boolean,
|
val hasGPS: Boolean,
|
||||||
val model: String?,
|
val model: String?,
|
||||||
val firmwareVersion: String?,
|
val firmwareVersion: String?,
|
||||||
val couldUpdate: Boolean, // this application contains a software load we _could_ install if you want
|
val couldUpdate: Boolean, // this application contains a software load we _could_ install if you want
|
||||||
val shouldUpdate: Boolean, // this device has old firmware
|
val shouldUpdate: Boolean, // this device has old firmware
|
||||||
val currentPacketId: Long,
|
val currentPacketId: Long,
|
||||||
val messageTimeoutMsec: Int,
|
val messageTimeoutMsec: Int,
|
||||||
val minAppVersion: Int,
|
val minAppVersion: Int,
|
||||||
val maxChannels: Int,
|
val maxChannels: Int,
|
||||||
val hasWifi: Boolean,
|
val hasWifi: Boolean,
|
||||||
val channelUtilization: Float,
|
val channelUtilization: Float,
|
||||||
val airUtilTx: Float,
|
val airUtilTx: Float,
|
||||||
val deviceId: String?,
|
val deviceId: String?,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
/** A human readable description of the software/hardware version */
|
/** A human readable description of the software/hardware version */
|
||||||
val firmwareString: String get() = "$model $firmwareVersion"
|
val firmwareString: String
|
||||||
}
|
get() = "$model $firmwareVersion"
|
||||||
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ package com.geeksville.mesh
|
||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.geeksville.mesh.util.anonymize
|
||||||
import com.geeksville.mesh.util.bearing
|
import com.geeksville.mesh.util.bearing
|
||||||
import com.geeksville.mesh.util.latLongToMeter
|
import com.geeksville.mesh.util.latLongToMeter
|
||||||
import com.geeksville.mesh.util.anonymize
|
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -38,33 +38,27 @@ data class MeshUser(
|
||||||
val role: Int = 0,
|
val role: Int = 0,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String = "MeshUser(id=${id.anonymize}, " +
|
||||||
return "MeshUser(id=${id.anonymize}, " +
|
"longName=${longName.anonymize}, " +
|
||||||
"longName=${longName.anonymize}, " +
|
"shortName=${shortName.anonymize}, " +
|
||||||
"shortName=${shortName.anonymize}, " +
|
"hwModel=$hwModelString, " +
|
||||||
"hwModel=$hwModelString, " +
|
"isLicensed=$isLicensed, " +
|
||||||
"isLicensed=$isLicensed, " +
|
"role=$role)"
|
||||||
"role=$role)"
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create our model object from a protobuf.
|
/** Create our model object from a protobuf. */
|
||||||
|
constructor(p: MeshProtos.User) : this(p.id, p.longName, p.shortName, p.hwModel, p.isLicensed, p.roleValue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a string version of the hardware model, converted into pretty lowercase and changing _ to -, and p to dot or null
|
||||||
|
* if unset
|
||||||
*/
|
*/
|
||||||
constructor(p: MeshProtos.User) : this(
|
|
||||||
p.id,
|
|
||||||
p.longName,
|
|
||||||
p.shortName,
|
|
||||||
p.hwModel,
|
|
||||||
p.isLicensed,
|
|
||||||
p.roleValue
|
|
||||||
)
|
|
||||||
|
|
||||||
/** a string version of the hardware model, converted into pretty lowercase and changing _ to -, and p to dot
|
|
||||||
* or null if unset
|
|
||||||
* */
|
|
||||||
val hwModelString: String?
|
val hwModelString: String?
|
||||||
get() =
|
get() =
|
||||||
if (hwModel == MeshProtos.HardwareModel.UNSET) null
|
if (hwModel == MeshProtos.HardwareModel.UNSET) {
|
||||||
else hwModel.name.replace('_', '-').replace('p', '.').lowercase()
|
null
|
||||||
|
} else {
|
||||||
|
hwModel.name.replace('_', '-').replace('p', '.').lowercase()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -80,16 +74,22 @@ data class Position(
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/// Convert to a double representation of degrees
|
// / Convert to a double representation of degrees
|
||||||
fun degD(i: Int) = i * 1e-7
|
fun degD(i: Int) = i * 1e-7
|
||||||
|
|
||||||
fun degI(d: Double) = (d * 1e7).toInt()
|
fun degI(d: Double) = (d * 1e7).toInt()
|
||||||
|
|
||||||
fun currentTime() = (System.currentTimeMillis() / 1000).toInt()
|
fun currentTime() = (System.currentTimeMillis() / 1000).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create our model object from a protobuf. If time is unspecified in the protobuf, the provided default time will be used.
|
/**
|
||||||
|
* Create our model object from a protobuf. If time is unspecified in the protobuf, the provided default time will
|
||||||
|
* be used.
|
||||||
*/
|
*/
|
||||||
constructor(position: MeshProtos.Position, defaultTime: Int = currentTime()) : this(
|
constructor(
|
||||||
|
position: MeshProtos.Position,
|
||||||
|
defaultTime: Int = currentTime(),
|
||||||
|
) : this(
|
||||||
// We prefer the int version of lat/lon but if not available use the depreciated legacy version
|
// We prefer the int version of lat/lon but if not available use the depreciated legacy version
|
||||||
degD(position.latitudeI),
|
degD(position.latitudeI),
|
||||||
degD(position.longitudeI),
|
degD(position.longitudeI),
|
||||||
|
@ -98,28 +98,25 @@ data class Position(
|
||||||
position.satsInView,
|
position.satsInView,
|
||||||
position.groundSpeed,
|
position.groundSpeed,
|
||||||
position.groundTrack,
|
position.groundTrack,
|
||||||
position.precisionBits
|
position.precisionBits,
|
||||||
)
|
)
|
||||||
|
|
||||||
/// @return distance in meters to some other node (or null if unknown)
|
// / @return distance in meters to some other node (or null if unknown)
|
||||||
fun distance(o: Position) = latLongToMeter(latitude, longitude, o.latitude, o.longitude)
|
fun distance(o: Position) = latLongToMeter(latitude, longitude, o.latitude, o.longitude)
|
||||||
|
|
||||||
/// @return bearing to the other position in degrees
|
// / @return bearing to the other position in degrees
|
||||||
fun bearing(o: Position) = bearing(latitude, longitude, o.latitude, o.longitude)
|
fun bearing(o: Position) = bearing(latitude, longitude, o.latitude, o.longitude)
|
||||||
|
|
||||||
// If GPS gives a crap position don't crash our app
|
// If GPS gives a crap position don't crash our app
|
||||||
fun isValid(): Boolean {
|
fun isValid(): Boolean = latitude != 0.0 &&
|
||||||
return latitude != 0.0 && longitude != 0.0 &&
|
longitude != 0.0 &&
|
||||||
(latitude >= -90 && latitude <= 90.0) &&
|
(latitude >= -90 && latitude <= 90.0) &&
|
||||||
(longitude >= -180 && longitude <= 180)
|
(longitude >= -180 && longitude <= 180)
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String =
|
||||||
return "Position(lat=${latitude.anonymize}, lon=${longitude.anonymize}, alt=${altitude.anonymize}, time=${time})"
|
"Position(lat=${latitude.anonymize}, lon=${longitude.anonymize}, alt=${altitude.anonymize}, time=$time)"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class DeviceMetrics(
|
data class DeviceMetrics(
|
||||||
val time: Int = currentTime(), // default to current time in secs (NOT MILLISECONDS!)
|
val time: Int = currentTime(), // default to current time in secs (NOT MILLISECONDS!)
|
||||||
|
@ -133,16 +130,11 @@ data class DeviceMetrics(
|
||||||
fun currentTime() = (System.currentTimeMillis() / 1000).toInt()
|
fun currentTime() = (System.currentTimeMillis() / 1000).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create our model object from a protobuf.
|
/** Create our model object from a protobuf. */
|
||||||
*/
|
constructor(
|
||||||
constructor(p: TelemetryProtos.DeviceMetrics, telemetryTime: Int = currentTime()) : this(
|
p: TelemetryProtos.DeviceMetrics,
|
||||||
telemetryTime,
|
telemetryTime: Int = currentTime(),
|
||||||
p.batteryLevel,
|
) : this(telemetryTime, p.batteryLevel, p.voltage, p.channelUtilization, p.airUtilTx, p.uptimeSeconds)
|
||||||
p.voltage,
|
|
||||||
p.channelUtilization,
|
|
||||||
p.airUtilTx,
|
|
||||||
p.uptimeSeconds,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -172,7 +164,7 @@ data class NodeInfo(
|
||||||
var deviceMetrics: DeviceMetrics? = null,
|
var deviceMetrics: DeviceMetrics? = null,
|
||||||
var channel: Int = 0,
|
var channel: Int = 0,
|
||||||
var environmentMetrics: EnvironmentMetrics? = null,
|
var environmentMetrics: EnvironmentMetrics? = null,
|
||||||
var hopsAway: Int = 0
|
var hopsAway: Int = 0,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
|
|
||||||
val colors: Pair<Int, Int>
|
val colors: Pair<Int, Int>
|
||||||
|
@ -184,13 +176,17 @@ data class NodeInfo(
|
||||||
return (if (brightness > 0.5) Color.BLACK else Color.WHITE) to Color.rgb(r, g, b)
|
return (if (brightness > 0.5) Color.BLACK else Color.WHITE) to Color.rgb(r, g, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
val batteryLevel get() = deviceMetrics?.batteryLevel
|
val batteryLevel
|
||||||
val voltage get() = deviceMetrics?.voltage
|
get() = deviceMetrics?.batteryLevel
|
||||||
val batteryStr get() = if (batteryLevel in 1..100) String.format("%d%%", batteryLevel) else ""
|
|
||||||
|
|
||||||
/**
|
val voltage
|
||||||
* true if the device was heard from recently
|
get() = deviceMetrics?.voltage
|
||||||
*/
|
|
||||||
|
val batteryStr
|
||||||
|
get() = if (batteryLevel in 1..100) String.format("%d%%", batteryLevel) else ""
|
||||||
|
|
||||||
|
/** true if the device was heard from recently */
|
||||||
|
@Suppress("MagicNumber")
|
||||||
val isOnline: Boolean
|
val isOnline: Boolean
|
||||||
get() {
|
get() {
|
||||||
val now = System.currentTimeMillis() / 1000
|
val now = System.currentTimeMillis() / 1000
|
||||||
|
@ -198,35 +194,39 @@ data class NodeInfo(
|
||||||
return (now - lastHeard <= timeout)
|
return (now - lastHeard <= timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return the position if it is valid, else null
|
// / return the position if it is valid, else null
|
||||||
val validPosition: Position?
|
val validPosition: Position?
|
||||||
get() {
|
get() {
|
||||||
return position?.takeIf { it.isValid() }
|
return position?.takeIf { it.isValid() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return distance in meters to some other node (or null if unknown)
|
// / @return distance in meters to some other node (or null if unknown)
|
||||||
fun distance(o: NodeInfo?): Int? {
|
fun distance(o: NodeInfo?): Int? {
|
||||||
val p = validPosition
|
val p = validPosition
|
||||||
val op = o?.validPosition
|
val op = o?.validPosition
|
||||||
return if (p != null && op != null) p.distance(op).toInt() else null
|
return if (p != null && op != null) p.distance(op).toInt() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return bearing to the other position in degrees
|
// / @return bearing to the other position in degrees
|
||||||
fun bearing(o: NodeInfo?): Int? {
|
fun bearing(o: NodeInfo?): Int? {
|
||||||
val p = validPosition
|
val p = validPosition
|
||||||
val op = o?.validPosition
|
val op = o?.validPosition
|
||||||
return if (p != null && op != null) p.bearing(op).toInt() else null
|
return if (p != null && op != null) p.bearing(op).toInt() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return a nice human readable string for the distance, or null for unknown
|
// / @return a nice human readable string for the distance, or null for unknown
|
||||||
fun distanceStr(o: NodeInfo?, prefUnits: Int = 0) = distance(o)?.let { dist ->
|
fun distanceStr(o: NodeInfo?, prefUnits: Int = 0) = distance(o)?.let { dist ->
|
||||||
when {
|
when {
|
||||||
dist == 0 -> null // same point
|
dist == 0 -> null // same point
|
||||||
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.METRIC_VALUE && dist < 1000 -> "%.0f m".format(dist.toDouble())
|
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.METRIC_VALUE && dist < 1000 ->
|
||||||
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.METRIC_VALUE && dist >= 1000 -> "%.1f km".format(dist / 1000.0)
|
"%.0f m".format(dist.toDouble())
|
||||||
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.IMPERIAL_VALUE && dist < 1609 -> "%.0f ft".format(dist.toDouble()*3.281)
|
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.METRIC_VALUE && dist >= 1000 ->
|
||||||
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.IMPERIAL_VALUE && dist >= 1609 -> "%.1f mi".format(dist / 1609.34)
|
"%.1f km".format(dist / 1000.0)
|
||||||
|
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.IMPERIAL_VALUE && dist < 1609 ->
|
||||||
|
"%.0f ft".format(dist.toDouble() * 3.281)
|
||||||
|
prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.IMPERIAL_VALUE && dist >= 1609 ->
|
||||||
|
"%.1f mi".format(dist / 1609.34)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("TooManyFunctions")
|
||||||
|
|
||||||
package com.geeksville.mesh.util
|
package com.geeksville.mesh.util
|
||||||
|
|
||||||
import com.geeksville.mesh.MeshProtos
|
import com.geeksville.mesh.MeshProtos
|
||||||
|
@ -24,6 +26,8 @@ import mil.nga.mgrs.MGRS
|
||||||
import mil.nga.mgrs.utm.UTM
|
import mil.nga.mgrs.utm.UTM
|
||||||
import org.osmdroid.util.BoundingBox
|
import org.osmdroid.util.BoundingBox
|
||||||
import org.osmdroid.util.GeoPoint
|
import org.osmdroid.util.GeoPoint
|
||||||
|
import java.util.Locale
|
||||||
|
import kotlin.math.PI
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.acos
|
import kotlin.math.acos
|
||||||
import kotlin.math.atan2
|
import kotlin.math.atan2
|
||||||
|
@ -31,78 +35,72 @@ import kotlin.math.cos
|
||||||
import kotlin.math.log2
|
import kotlin.math.log2
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
import kotlin.math.PI
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/**
|
||||||
|
* ****************************************************************************
|
||||||
* Revive some of my old Gaggle source code...
|
* Revive some of my old Gaggle source code...
|
||||||
*
|
*
|
||||||
* GNU Public License, version 2
|
* GNU Public License, version 2 All other distribution of Gaggle must conform to the terms of the GNU Public License,
|
||||||
* All other distribution of Gaggle must conform to the terms of the GNU Public License, version 2. The full
|
* version 2. The full text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt.
|
||||||
* text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt.
|
* ****************************************************************************
|
||||||
******************************************************************************/
|
*/
|
||||||
|
|
||||||
object GPSFormat {
|
object GPSFormat {
|
||||||
fun DEC(p: Position): String {
|
fun dec(p: Position): String =
|
||||||
return String.format("%.5f %.5f", p.latitude, p.longitude).replace(",", ".")
|
String.format(Locale.getDefault(), "%.5f %.5f", p.latitude, p.longitude).replace(",", ".")
|
||||||
}
|
|
||||||
|
|
||||||
fun DMS(p: Position): String {
|
@Suppress("MagicNumber")
|
||||||
|
fun dms(p: Position): String {
|
||||||
val lat = degreesToDMS(p.latitude, true)
|
val lat = degreesToDMS(p.latitude, true)
|
||||||
val lon = degreesToDMS(p.longitude, false)
|
val lon = degreesToDMS(p.longitude, false)
|
||||||
fun string(a: Array<String>) = String.format("%s°%s'%.5s\"%s", a[0], a[1], a[2], a[3])
|
fun string(a: Array<String>) = String.format(Locale.getDefault(), "%s°%s'%.5s\"%s", a[0], a[1], a[2], a[3])
|
||||||
return string(lat) + " " + string(lon)
|
return string(lat) + " " + string(lon)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun UTM(p: Position): String {
|
fun utm(p: Position): String {
|
||||||
val UTM = UTM.from(Point.point(p.longitude, p.latitude))
|
val utm = UTM.from(Point.point(p.longitude, p.latitude))
|
||||||
return String.format(
|
return String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
"%s%s %.6s %.7s",
|
"%s%s %.6s %.7s",
|
||||||
UTM.zone,
|
utm.zone,
|
||||||
UTM.toMGRS().band,
|
utm.toMGRS().band,
|
||||||
UTM.easting,
|
utm.easting,
|
||||||
UTM.northing
|
utm.northing,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MGRS(p: Position): String {
|
fun mgrs(p: Position): String {
|
||||||
val MGRS = MGRS.from(Point.point(p.longitude, p.latitude))
|
val mgrs = MGRS.from(Point.point(p.longitude, p.latitude))
|
||||||
return String.format(
|
return String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
"%s%s %s%s %05d %05d",
|
"%s%s %s%s %05d %05d",
|
||||||
MGRS.zone,
|
mgrs.zone,
|
||||||
MGRS.band,
|
mgrs.band,
|
||||||
MGRS.column,
|
mgrs.column,
|
||||||
MGRS.row,
|
mgrs.row,
|
||||||
MGRS.easting,
|
mgrs.easting,
|
||||||
MGRS.northing
|
mgrs.northing,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toDEC(latitude: Double, longitude: Double): String {
|
fun toDEC(latitude: Double, longitude: Double): String = "%.5f %.5f".format(latitude, longitude).replace(",", ".")
|
||||||
return "%.5f %.5f".format(latitude, longitude).replace(",", ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
fun toDMS(latitude: Double, longitude: Double): String {
|
fun toDMS(latitude: Double, longitude: Double): String {
|
||||||
val lat = degreesToDMS(latitude, true)
|
val lat = degreesToDMS(latitude, true)
|
||||||
val lon = degreesToDMS(longitude, false)
|
val lon = degreesToDMS(longitude, false)
|
||||||
fun string(a: Array<String>) = "%s°%s'%.5s\"%s".format(a[0], a[1], a[2], a[3])
|
fun string(a: Array<String>) = "%s°%s'%.5s\"%s".format(Locale.getDefault(), a[0], a[1], a[2], a[3])
|
||||||
return string(lat) + " " + string(lon)
|
return string(lat) + " " + string(lon)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toUTM(latitude: Double, longitude: Double): String {
|
fun toUTM(latitude: Double, longitude: Double): String {
|
||||||
val UTM = UTM.from(Point.point(longitude, latitude))
|
val utm = UTM.from(Point.point(longitude, latitude))
|
||||||
return "%s%s %.6s %.7s".format(UTM.zone, UTM.toMGRS().band, UTM.easting, UTM.northing)
|
return "%s%s %.6s %.7s".format(Locale.getDefault(), utm.zone, utm.toMGRS().band, utm.easting, utm.northing)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toMGRS(latitude: Double, longitude: Double): String {
|
fun toMGRS(latitude: Double, longitude: Double): String {
|
||||||
val MGRS = MGRS.from(Point.point(longitude, latitude))
|
val mgrs = MGRS.from(Point.point(longitude, latitude))
|
||||||
return "%s%s %s%s %05d %05d".format(
|
return "%s%s %s%s %05d %05d"
|
||||||
MGRS.zone,
|
.format(Locale.getDefault(), mgrs.zone, mgrs.band, mgrs.column, mgrs.row, mgrs.easting, mgrs.northing)
|
||||||
MGRS.band,
|
|
||||||
MGRS.column,
|
|
||||||
MGRS.row,
|
|
||||||
MGRS.easting,
|
|
||||||
MGRS.northing
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,75 +111,71 @@ object GPSFormat {
|
||||||
* @param isLatitude
|
* @param isLatitude
|
||||||
* @return a string like 120deg
|
* @return a string like 120deg
|
||||||
*/
|
*/
|
||||||
fun degreesToDMS(
|
@Suppress("MagicNumber")
|
||||||
_degIn: Double,
|
fun degreesToDMS(degIn: Double, isLatitude: Boolean): Array<String> {
|
||||||
isLatitude: Boolean
|
var degIn = degIn
|
||||||
): Array<String> {
|
|
||||||
var degIn = _degIn
|
|
||||||
val isPos = degIn >= 0
|
val isPos = degIn >= 0
|
||||||
val dirLetter =
|
val dirLetter =
|
||||||
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
|
if (isLatitude) if (isPos) 'N' else 'S'
|
||||||
|
else if (isPos) {
|
||||||
|
'E'
|
||||||
|
} else {
|
||||||
|
'W'
|
||||||
|
}
|
||||||
degIn = abs(degIn)
|
degIn = abs(degIn)
|
||||||
val degOut = degIn.toInt()
|
val degOut = degIn.toInt()
|
||||||
val minutes = 60 * (degIn - degOut)
|
val minutes = 60 * (degIn - degOut)
|
||||||
val minwhole = minutes.toInt()
|
val minwhole = minutes.toInt()
|
||||||
val seconds = (minutes - minwhole) * 60
|
val seconds = (minutes - minwhole) * 60
|
||||||
return arrayOf(
|
return arrayOf(degOut.toString(), minwhole.toString(), seconds.toString(), dirLetter.toString())
|
||||||
degOut.toString(), minwhole.toString(),
|
|
||||||
seconds.toString(),
|
|
||||||
dirLetter.toString()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun degreesToDM(_degIn: Double, isLatitude: Boolean): Array<String> {
|
@Suppress("MagicNumber")
|
||||||
var degIn = _degIn
|
fun degreesToDM(degIn: Double, isLatitude: Boolean): Array<String> {
|
||||||
|
var degIn = degIn
|
||||||
val isPos = degIn >= 0
|
val isPos = degIn >= 0
|
||||||
val dirLetter =
|
val dirLetter =
|
||||||
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
|
if (isLatitude) if (isPos) 'N' else 'S'
|
||||||
|
else if (isPos) {
|
||||||
|
'E'
|
||||||
|
} else {
|
||||||
|
'W'
|
||||||
|
}
|
||||||
degIn = abs(degIn)
|
degIn = abs(degIn)
|
||||||
val degOut = degIn.toInt()
|
val degOut = degIn.toInt()
|
||||||
val minutes = 60 * (degIn - degOut)
|
val minutes = 60 * (degIn - degOut)
|
||||||
val seconds = 0
|
val seconds = 0
|
||||||
return arrayOf(
|
return arrayOf(degOut.toString(), minutes.toString(), seconds.toString(), dirLetter.toString())
|
||||||
degOut.toString(), minutes.toString(),
|
|
||||||
seconds.toString(),
|
|
||||||
dirLetter.toString()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun degreesToD(_degIn: Double, isLatitude: Boolean): Array<String> {
|
fun degreesToD(degIn: Double, isLatitude: Boolean): Array<String> {
|
||||||
var degIn = _degIn
|
var degIn = degIn
|
||||||
val isPos = degIn >= 0
|
val isPos = degIn >= 0
|
||||||
val dirLetter =
|
val dirLetter =
|
||||||
if (isLatitude) if (isPos) 'N' else 'S' else if (isPos) 'E' else 'W'
|
if (isLatitude) if (isPos) 'N' else 'S'
|
||||||
|
else if (isPos) {
|
||||||
|
'E'
|
||||||
|
} else {
|
||||||
|
'W'
|
||||||
|
}
|
||||||
degIn = abs(degIn)
|
degIn = abs(degIn)
|
||||||
val degOut = degIn
|
val degOut = degIn
|
||||||
val minutes = 0
|
val minutes = 0
|
||||||
val seconds = 0
|
val seconds = 0
|
||||||
return arrayOf(
|
return arrayOf(degOut.toString(), minutes.toString(), seconds.toString(), dirLetter.toString())
|
||||||
degOut.toString(), minutes.toString(),
|
|
||||||
seconds.toString(),
|
|
||||||
dirLetter.toString()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A not super efficent mapping from a starting lat/long + a distance at a
|
* A not super efficent mapping from a starting lat/long + a distance at a certain direction
|
||||||
* certain direction
|
|
||||||
*
|
*
|
||||||
* @param lat
|
* @param lat
|
||||||
* @param longitude
|
* @param longitude
|
||||||
* @param distMeters
|
* @param distMeters
|
||||||
* @param theta
|
* @param theta in radians, 0 == north
|
||||||
* in radians, 0 == north
|
|
||||||
* @return an array with lat and long
|
* @return an array with lat and long
|
||||||
*/
|
*/
|
||||||
fun addDistance(
|
@Suppress("MagicNumber")
|
||||||
lat: Double,
|
fun addDistance(lat: Double, longitude: Double, distMeters: Double, theta: Double): DoubleArray {
|
||||||
longitude: Double,
|
|
||||||
distMeters: Double,
|
|
||||||
theta: Double
|
|
||||||
): DoubleArray {
|
|
||||||
val dx = distMeters * sin(theta) // theta measured clockwise
|
val dx = distMeters * sin(theta) // theta measured clockwise
|
||||||
// from due north
|
// from due north
|
||||||
val dy = distMeters * cos(theta) // dx, dy same units as R
|
val dy = distMeters * cos(theta) // dx, dy same units as R
|
||||||
|
@ -190,20 +184,14 @@ fun addDistance(
|
||||||
return doubleArrayOf(lat + dLat, longitude + dLong)
|
return doubleArrayOf(lat + dLat, longitude + dLong)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @return distance in meters along the surface of the earth (ish) */
|
||||||
* @return distance in meters along the surface of the earth (ish)
|
@Suppress("MagicNumber")
|
||||||
*/
|
fun latLongToMeter(latA: Double, lngA: Double, latB: Double, lngB: Double): Double {
|
||||||
fun latLongToMeter(
|
|
||||||
lat_a: Double,
|
|
||||||
lng_a: Double,
|
|
||||||
lat_b: Double,
|
|
||||||
lng_b: Double
|
|
||||||
): Double {
|
|
||||||
val pk = (180 / PI)
|
val pk = (180 / PI)
|
||||||
val a1 = lat_a / pk
|
val a1 = latA / pk
|
||||||
val a2 = lng_a / pk
|
val a2 = lngA / pk
|
||||||
val b1 = lat_b / pk
|
val b1 = latB / pk
|
||||||
val b2 = lng_b / pk
|
val b2 = lngB / pk
|
||||||
val t1 = cos(a1) * cos(a2) * cos(b1) * cos(b2)
|
val t1 = cos(a1) * cos(a2) * cos(b1) * cos(b2)
|
||||||
val t2 = cos(a1) * sin(a2) * cos(b1) * sin(b2)
|
val t2 = cos(a1) * sin(a2) * cos(b1) * sin(b2)
|
||||||
val t3 = sin(a1) * sin(b1)
|
val t3 = sin(a1) * sin(b1)
|
||||||
|
@ -213,14 +201,8 @@ fun latLongToMeter(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as above, but takes Mesh Position proto.
|
// Same as above, but takes Mesh Position proto.
|
||||||
fun positionToMeter(a: MeshProtos.Position, b: MeshProtos.Position): Double {
|
fun positionToMeter(a: MeshProtos.Position, b: MeshProtos.Position): Double =
|
||||||
return latLongToMeter(
|
latLongToMeter(a.latitudeI * 1e-7, a.longitudeI * 1e-7, b.latitudeI * 1e-7, b.longitudeI * 1e-7)
|
||||||
a.latitudeI * 1e-7,
|
|
||||||
a.longitudeI * 1e-7,
|
|
||||||
b.latitudeI * 1e-7,
|
|
||||||
b.longitudeI * 1e-7
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert degrees/mins/secs to a single double
|
* Convert degrees/mins/secs to a single double
|
||||||
|
@ -231,44 +213,24 @@ fun positionToMeter(a: MeshProtos.Position, b: MeshProtos.Position): Double {
|
||||||
* @param isPostive
|
* @param isPostive
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
fun DMSToDegrees(
|
@Suppress("MagicNumber")
|
||||||
degrees: Int,
|
fun dmsToDegrees(degrees: Int, minutes: Int, seconds: Float, isPostive: Boolean): Double =
|
||||||
minutes: Int,
|
(if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
|
||||||
seconds: Float,
|
|
||||||
isPostive: Boolean
|
|
||||||
): Double {
|
|
||||||
return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DMSToDegrees(
|
@Suppress("MagicNumber")
|
||||||
degrees: Double,
|
fun dmsToDegrees(degrees: Double, minutes: Double, seconds: Double, isPostive: Boolean): Double =
|
||||||
minutes: Double,
|
(if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
|
||||||
seconds: Double,
|
|
||||||
isPostive: Boolean
|
|
||||||
): Double {
|
|
||||||
return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the bearing in degrees between two points on Earth.
|
* Computes the bearing in degrees between two points on Earth.
|
||||||
*
|
*
|
||||||
* @param lat1
|
* @param lat1 Latitude of the first point
|
||||||
* Latitude of the first point
|
* @param lon1 Longitude of the first point
|
||||||
* @param lon1
|
* @param lat2 Latitude of the second point
|
||||||
* Longitude of the first point
|
* @param lon2 Longitude of the second point
|
||||||
* @param lat2
|
* @return Bearing between the two points in degrees. A value of 0 means due north.
|
||||||
* Latitude of the second point
|
|
||||||
* @param lon2
|
|
||||||
* Longitude of the second point
|
|
||||||
* @return Bearing between the two points in degrees. A value of 0 means due
|
|
||||||
* north.
|
|
||||||
*/
|
*/
|
||||||
fun bearing(
|
fun bearing(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double {
|
||||||
lat1: Double,
|
|
||||||
lon1: Double,
|
|
||||||
lat2: Double,
|
|
||||||
lon2: Double
|
|
||||||
): Double {
|
|
||||||
val lat1Rad = Math.toRadians(lat1)
|
val lat1Rad = Math.toRadians(lat1)
|
||||||
val lat2Rad = Math.toRadians(lat2)
|
val lat2Rad = Math.toRadians(lat2)
|
||||||
val deltaLonRad = Math.toRadians(lon2 - lon1)
|
val deltaLonRad = Math.toRadians(lon2 - lon1)
|
||||||
|
@ -277,17 +239,16 @@ fun bearing(
|
||||||
return radToBearing(atan2(y, x))
|
return radToBearing(atan2(y, x))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Converts an angle in radians to degrees */
|
||||||
* Converts an angle in radians to degrees
|
@Suppress("MagicNumber")
|
||||||
*/
|
fun radToBearing(rad: Double): Double = (Math.toDegrees(rad) + 360) % 360
|
||||||
fun radToBearing(rad: Double): Double {
|
|
||||||
return (Math.toDegrees(rad) + 360) % 360
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the zoom level required to fit the entire [BoundingBox] inside the map view.
|
* Calculates the zoom level required to fit the entire [BoundingBox] inside the map view.
|
||||||
|
*
|
||||||
* @return The zoom level as a Double value.
|
* @return The zoom level as a Double value.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("MagicNumber")
|
||||||
fun BoundingBox.requiredZoomLevel(): Double {
|
fun BoundingBox.requiredZoomLevel(): Double {
|
||||||
val topLeft = GeoPoint(this.latNorth, this.lonWest)
|
val topLeft = GeoPoint(this.latNorth, this.lonWest)
|
||||||
val bottomRight = GeoPoint(this.latSouth, this.lonEast)
|
val bottomRight = GeoPoint(this.latSouth, this.lonEast)
|
||||||
|
@ -300,6 +261,7 @@ fun BoundingBox.requiredZoomLevel(): Double {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new bounding box with adjusted dimensions based on the provided [zoomFactor].
|
* Creates a new bounding box with adjusted dimensions based on the provided [zoomFactor].
|
||||||
|
*
|
||||||
* @return A new [BoundingBox] with added [zoomFactor]. Example:
|
* @return A new [BoundingBox] with added [zoomFactor]. Example:
|
||||||
* ```
|
* ```
|
||||||
* // Setting the zoom level directly using setZoom()
|
* // Setting the zoom level directly using setZoom()
|
||||||
|
@ -322,6 +284,6 @@ fun BoundingBox.zoomIn(zoomFactor: Double): BoundingBox {
|
||||||
center.latitude + newLatDiff / 2,
|
center.latitude + newLatDiff / 2,
|
||||||
center.longitude + newLonDiff / 2,
|
center.longitude + newLonDiff / 2,
|
||||||
center.latitude - newLatDiff / 2,
|
center.latitude - newLatDiff / 2,
|
||||||
center.longitude - newLonDiff / 2
|
center.longitude - newLonDiff / 2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
private var isMeshServiceBound = false
|
private var isMeshServiceBound = false
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
|
@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
|
||||||
|
@Suppress("TooGenericExceptionCaught", "LongMethod")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
this.enableEdgeToEdge()
|
this.enableEdgeToEdge()
|
||||||
|
@ -109,6 +110,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
val meshtasticReceiver: BroadcastReceiver =
|
val meshtasticReceiver: BroadcastReceiver =
|
||||||
object : BroadcastReceiver() {
|
object : BroadcastReceiver() {
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
@Suppress("ReturnCount")
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
Log.w(TAG, "Received null intent")
|
Log.w(TAG, "Received null intent")
|
||||||
|
@ -166,7 +168,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
Log.d(TAG, "Position App NodeInfo: $ni")
|
Log.d(TAG, "Position App NodeInfo: $ni")
|
||||||
mainTextView.text = "Position App NodeInfo: $ni"
|
mainTextView.text = "Position App NodeInfo: $ni"
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
Log.e(TAG, "onReceive: $e")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,7 +191,8 @@ class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
while (!bindMeshService()) {
|
while (!bindMeshService()) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000)
|
@Suppress("MagicNumber")
|
||||||
|
Thread.sleep(1_000)
|
||||||
} catch (e: InterruptedException) {
|
} catch (e: InterruptedException) {
|
||||||
Log.e(TAG, "Binding interrupted", e)
|
Log.e(TAG, "Binding interrupted", e)
|
||||||
break
|
break
|
||||||
|
|
Ładowanie…
Reference in New Issue