From 299dac415d63ac81ee25179b08d1c701f56e187b Mon Sep 17 00:00:00 2001 From: Phil Oliver <3497406+poliver@users.noreply.github.com> Date: Tue, 16 Sep 2025 19:38:54 -0400 Subject: [PATCH] Example project: Appease Detekt (#3125) --- .../kotlin/com/geeksville/mesh/DataPacket.kt | 101 ++++---- .../kotlin/com/geeksville/mesh/MyNodeInfo.kt | 35 +-- .../kotlin/com/geeksville/mesh/NodeInfo.kt | 130 +++++----- .../com/geeksville/mesh/util/LocationUtils.kt | 238 ++++++++---------- .../meshserviceexample/MainActivity.kt | 7 +- 5 files changed, 235 insertions(+), 276 deletions(-) diff --git a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/DataPacket.kt b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/DataPacket.kt index a6f8b7461..9a470cc17 100644 --- a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/DataPacket.kt +++ b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/DataPacket.kt @@ -22,17 +22,14 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable -/** - * Generic [Parcel.readParcelable] Android 13 compatibility extension. - */ -private inline fun Parcel.readParcelableCompat(loader: ClassLoader?): T? { - return if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) { +/** Generic [Parcel.readParcelable] Android 13 compatibility extension. */ +private inline fun Parcel.readParcelableCompat(loader: ClassLoader?): T? = + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) { @Suppress("DEPRECATION") readParcelable(loader) } else { readParcelable(loader, T::class.java) } -} @Parcelize 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 ENROUTE, // Delivered to the radio, but no ACK or NAK received 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 data class DataPacket( var to: String? = ID_BROADCAST, // a nodeID string, or ID_BROADCAST for broadcast 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 time: Long = System.currentTimeMillis(), // msecs since 1970 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 ) : 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 - /** - * Syntactic sugar to make it easy to create text messages - */ - constructor(to: String?, channel: Int, text: String) : this( + /** Syntactic sugar to make it easy to create text messages */ + constructor( + to: String?, + channel: Int, + text: String, + ) : this( to = to, bytes = text.encodeToByteArray(), 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? - get() = if (dataType == Portnums.PortNum.TEXT_MESSAGE_APP_VALUE) { - bytes?.decodeToString() - } else { - null - } + get() = + if (dataType == Portnums.PortNum.TEXT_MESSAGE_APP_VALUE) { + bytes?.decodeToString() + } else { + null + } val alert: String? - get() = if (dataType == Portnums.PortNum.ALERT_APP_VALUE) { - bytes?.decodeToString() - } else { - null - } + get() = + if (dataType == Portnums.PortNum.ALERT_APP_VALUE) { + bytes?.decodeToString() + } else { + null + } - constructor(to: String?, channel: Int, waypoint: MeshProtos.Waypoint) : this( - to = to, - bytes = waypoint.toByteArray(), - dataType = Portnums.PortNum.WAYPOINT_APP_VALUE, - channel = channel - ) + constructor( + to: String?, + channel: Int, + waypoint: MeshProtos.Waypoint, + ) : this(to = to, bytes = waypoint.toByteArray(), dataType = Portnums.PortNum.WAYPOINT_APP_VALUE, channel = channel) val waypoint: MeshProtos.Waypoint? - get() = if (dataType == Portnums.PortNum.WAYPOINT_APP_VALUE) { - MeshProtos.Waypoint.parseFrom(bytes) - } else { - null - } + get() = + if (dataType == Portnums.PortNum.WAYPOINT_APP_VALUE) { + MeshProtos.Waypoint.parseFrom(bytes) + } else { + null + } // Autogenerated comparision, because we have a byte array - constructor(parcel: Parcel) : this( + constructor( + parcel: Parcel, + ) : this( parcel.readString(), parcel.createByteArray(), parcel.readInt(), @@ -169,9 +167,7 @@ data class DataPacket( parcel.writeInt(if (wantAck) 1 else 0) } - override fun describeContents(): Int { - return 0 - } + override fun describeContents(): Int = 0 // Update our object from our parcel (used for inout parameters fun readFromParcel(parcel: Parcel) { @@ -203,14 +199,11 @@ data class DataPacket( const val PKC_CHANNEL_INDEX = 8 fun nodeNumToDefaultId(n: Int): String = "!%08x".format(n) + fun idToDefaultNodeNum(id: String?): Int? = runCatching { id?.toLong(16)?.toInt() }.getOrNull() - override fun createFromParcel(parcel: Parcel): DataPacket { - return DataPacket(parcel) - } + override fun createFromParcel(parcel: Parcel): DataPacket = DataPacket(parcel) - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } + override fun newArray(size: Int): Array = arrayOfNulls(size) } -} \ No newline at end of file +} diff --git a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/MyNodeInfo.kt b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/MyNodeInfo.kt index 15e265cc9..fa94cb21a 100644 --- a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/MyNodeInfo.kt +++ b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/MyNodeInfo.kt @@ -23,21 +23,22 @@ import kotlinx.parcelize.Parcelize // MyNodeInfo sent via special protobuf from radio @Parcelize data class MyNodeInfo( - val myNodeNum: Int, - val hasGPS: Boolean, - val model: String?, - val firmwareVersion: String?, - val couldUpdate: Boolean, // this application contains a software load we _could_ install if you want - val shouldUpdate: Boolean, // this device has old firmware - val currentPacketId: Long, - val messageTimeoutMsec: Int, - val minAppVersion: Int, - val maxChannels: Int, - val hasWifi: Boolean, - val channelUtilization: Float, - val airUtilTx: Float, - val deviceId: String?, + val myNodeNum: Int, + val hasGPS: Boolean, + val model: String?, + val firmwareVersion: String?, + val couldUpdate: Boolean, // this application contains a software load we _could_ install if you want + val shouldUpdate: Boolean, // this device has old firmware + val currentPacketId: Long, + val messageTimeoutMsec: Int, + val minAppVersion: Int, + val maxChannels: Int, + val hasWifi: Boolean, + val channelUtilization: Float, + val airUtilTx: Float, + val deviceId: String?, ) : Parcelable { - /** A human readable description of the software/hardware version */ - val firmwareString: String get() = "$model $firmwareVersion" -} \ No newline at end of file + /** A human readable description of the software/hardware version */ + val firmwareString: String + get() = "$model $firmwareVersion" +} diff --git a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/NodeInfo.kt b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/NodeInfo.kt index 73ebdae14..d339a7cfa 100644 --- a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/NodeInfo.kt +++ b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/NodeInfo.kt @@ -19,9 +19,9 @@ package com.geeksville.mesh import android.graphics.Color import android.os.Parcelable +import com.geeksville.mesh.util.anonymize import com.geeksville.mesh.util.bearing import com.geeksville.mesh.util.latLongToMeter -import com.geeksville.mesh.util.anonymize import kotlinx.parcelize.Parcelize // @@ -38,33 +38,27 @@ data class MeshUser( val role: Int = 0, ) : Parcelable { - override fun toString(): String { - return "MeshUser(id=${id.anonymize}, " + - "longName=${longName.anonymize}, " + - "shortName=${shortName.anonymize}, " + - "hwModel=$hwModelString, " + - "isLicensed=$isLicensed, " + - "role=$role)" - } + override fun toString(): String = "MeshUser(id=${id.anonymize}, " + + "longName=${longName.anonymize}, " + + "shortName=${shortName.anonymize}, " + + "hwModel=$hwModelString, " + + "isLicensed=$isLicensed, " + + "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? get() = - if (hwModel == MeshProtos.HardwareModel.UNSET) null - else hwModel.name.replace('_', '-').replace('p', '.').lowercase() + if (hwModel == MeshProtos.HardwareModel.UNSET) { + null + } else { + hwModel.name.replace('_', '-').replace('p', '.').lowercase() + } } @Parcelize @@ -80,16 +74,22 @@ data class Position( ) : Parcelable { companion object { - /// Convert to a double representation of degrees + // / Convert to a double representation of degrees fun degD(i: Int) = i * 1e-7 + fun degI(d: Double) = (d * 1e7).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 degD(position.latitudeI), degD(position.longitudeI), @@ -98,28 +98,25 @@ data class Position( position.satsInView, position.groundSpeed, 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) - /// @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) // If GPS gives a crap position don't crash our app - fun isValid(): Boolean { - return latitude != 0.0 && longitude != 0.0 && - (latitude >= -90 && latitude <= 90.0) && - (longitude >= -180 && longitude <= 180) - } + fun isValid(): Boolean = latitude != 0.0 && + longitude != 0.0 && + (latitude >= -90 && latitude <= 90.0) && + (longitude >= -180 && longitude <= 180) - override fun toString(): String { - return "Position(lat=${latitude.anonymize}, lon=${longitude.anonymize}, alt=${altitude.anonymize}, time=${time})" - } + override fun toString(): String = + "Position(lat=${latitude.anonymize}, lon=${longitude.anonymize}, alt=${altitude.anonymize}, time=$time)" } - @Parcelize data class DeviceMetrics( 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() } - /** Create our model object from a protobuf. - */ - constructor(p: TelemetryProtos.DeviceMetrics, telemetryTime: Int = currentTime()) : this( - telemetryTime, - p.batteryLevel, - p.voltage, - p.channelUtilization, - p.airUtilTx, - p.uptimeSeconds, - ) + /** Create our model object from a protobuf. */ + constructor( + p: TelemetryProtos.DeviceMetrics, + telemetryTime: Int = currentTime(), + ) : this(telemetryTime, p.batteryLevel, p.voltage, p.channelUtilization, p.airUtilTx, p.uptimeSeconds) } @Parcelize @@ -172,7 +164,7 @@ data class NodeInfo( var deviceMetrics: DeviceMetrics? = null, var channel: Int = 0, var environmentMetrics: EnvironmentMetrics? = null, - var hopsAway: Int = 0 + var hopsAway: Int = 0, ) : Parcelable { val colors: Pair @@ -184,13 +176,17 @@ data class NodeInfo( return (if (brightness > 0.5) Color.BLACK else Color.WHITE) to Color.rgb(r, g, b) } - val batteryLevel get() = deviceMetrics?.batteryLevel - val voltage get() = deviceMetrics?.voltage - val batteryStr get() = if (batteryLevel in 1..100) String.format("%d%%", batteryLevel) else "" + val batteryLevel + get() = deviceMetrics?.batteryLevel - /** - * true if the device was heard from recently - */ + val voltage + 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 get() { val now = System.currentTimeMillis() / 1000 @@ -198,35 +194,39 @@ data class NodeInfo( 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? get() { 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? { val p = validPosition val op = o?.validPosition 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? { val p = validPosition val op = o?.validPosition 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 -> when { 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 -> "%.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) + prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.METRIC_VALUE && dist < 1000 -> + "%.0f m".format(dist.toDouble()) + prefUnits == ConfigProtos.Config.DisplayConfig.DisplayUnits.METRIC_VALUE && dist >= 1000 -> + "%.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 } } -} \ No newline at end of file +} diff --git a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/util/LocationUtils.kt b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/util/LocationUtils.kt index bb4567e63..3caf2dbb5 100644 --- a/mesh_service_example/src/main/kotlin/com/geeksville/mesh/util/LocationUtils.kt +++ b/mesh_service_example/src/main/kotlin/com/geeksville/mesh/util/LocationUtils.kt @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +@file:Suppress("TooManyFunctions") + package com.geeksville.mesh.util import com.geeksville.mesh.MeshProtos @@ -24,6 +26,8 @@ import mil.nga.mgrs.MGRS import mil.nga.mgrs.utm.UTM import org.osmdroid.util.BoundingBox import org.osmdroid.util.GeoPoint +import java.util.Locale +import kotlin.math.PI import kotlin.math.abs import kotlin.math.acos import kotlin.math.atan2 @@ -31,78 +35,72 @@ import kotlin.math.cos import kotlin.math.log2 import kotlin.math.pow import kotlin.math.sin -import kotlin.math.PI -/******************************************************************************* +/** + * **************************************************************************** * Revive some of my old Gaggle source code... * - * GNU Public License, version 2 - * All other distribution of Gaggle must conform to the terms of the GNU Public License, version 2. The full - * text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt. - ******************************************************************************/ - + * GNU Public License, version 2 All other distribution of Gaggle must conform to the terms of the GNU Public License, + * version 2. The full text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt. + * **************************************************************************** + */ object GPSFormat { - fun DEC(p: Position): String { - return String.format("%.5f %.5f", p.latitude, p.longitude).replace(",", ".") - } + fun dec(p: Position): String = + 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 lon = degreesToDMS(p.longitude, false) - fun string(a: Array) = String.format("%s°%s'%.5s\"%s", a[0], a[1], a[2], a[3]) + fun string(a: Array) = String.format(Locale.getDefault(), "%s°%s'%.5s\"%s", a[0], a[1], a[2], a[3]) return string(lat) + " " + string(lon) } - fun UTM(p: Position): String { - val UTM = UTM.from(Point.point(p.longitude, p.latitude)) + fun utm(p: Position): String { + val utm = UTM.from(Point.point(p.longitude, p.latitude)) return String.format( + Locale.getDefault(), "%s%s %.6s %.7s", - UTM.zone, - UTM.toMGRS().band, - UTM.easting, - UTM.northing + utm.zone, + utm.toMGRS().band, + utm.easting, + utm.northing, ) } - fun MGRS(p: Position): String { - val MGRS = MGRS.from(Point.point(p.longitude, p.latitude)) + fun mgrs(p: Position): String { + val mgrs = MGRS.from(Point.point(p.longitude, p.latitude)) return String.format( + Locale.getDefault(), "%s%s %s%s %05d %05d", - MGRS.zone, - MGRS.band, - MGRS.column, - MGRS.row, - MGRS.easting, - MGRS.northing + mgrs.zone, + mgrs.band, + mgrs.column, + mgrs.row, + mgrs.easting, + mgrs.northing, ) } - fun toDEC(latitude: Double, longitude: Double): String { - return "%.5f %.5f".format(latitude, longitude).replace(",", ".") - } + fun toDEC(latitude: Double, longitude: Double): String = "%.5f %.5f".format(latitude, longitude).replace(",", ".") + @Suppress("MagicNumber") fun toDMS(latitude: Double, longitude: Double): String { val lat = degreesToDMS(latitude, true) val lon = degreesToDMS(longitude, false) - fun string(a: Array) = "%s°%s'%.5s\"%s".format(a[0], a[1], a[2], a[3]) + fun string(a: Array) = "%s°%s'%.5s\"%s".format(Locale.getDefault(), a[0], a[1], a[2], a[3]) return string(lat) + " " + string(lon) } fun toUTM(latitude: Double, longitude: Double): String { - val UTM = UTM.from(Point.point(longitude, latitude)) - return "%s%s %.6s %.7s".format(UTM.zone, UTM.toMGRS().band, UTM.easting, UTM.northing) + val utm = UTM.from(Point.point(longitude, latitude)) + return "%s%s %.6s %.7s".format(Locale.getDefault(), utm.zone, utm.toMGRS().band, utm.easting, utm.northing) } fun toMGRS(latitude: Double, longitude: Double): String { - val MGRS = MGRS.from(Point.point(longitude, latitude)) - return "%s%s %s%s %05d %05d".format( - MGRS.zone, - MGRS.band, - MGRS.column, - MGRS.row, - MGRS.easting, - MGRS.northing - ) + val mgrs = MGRS.from(Point.point(longitude, latitude)) + return "%s%s %s%s %05d %05d" + .format(Locale.getDefault(), mgrs.zone, mgrs.band, mgrs.column, mgrs.row, mgrs.easting, mgrs.northing) } } @@ -113,75 +111,71 @@ object GPSFormat { * @param isLatitude * @return a string like 120deg */ -fun degreesToDMS( - _degIn: Double, - isLatitude: Boolean -): Array { - var degIn = _degIn +@Suppress("MagicNumber") +fun degreesToDMS(degIn: Double, isLatitude: Boolean): Array { + var degIn = degIn val isPos = degIn >= 0 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) val degOut = degIn.toInt() val minutes = 60 * (degIn - degOut) val minwhole = minutes.toInt() val seconds = (minutes - minwhole) * 60 - return arrayOf( - degOut.toString(), minwhole.toString(), - seconds.toString(), - dirLetter.toString() - ) + return arrayOf(degOut.toString(), minwhole.toString(), seconds.toString(), dirLetter.toString()) } -fun degreesToDM(_degIn: Double, isLatitude: Boolean): Array { - var degIn = _degIn +@Suppress("MagicNumber") +fun degreesToDM(degIn: Double, isLatitude: Boolean): Array { + var degIn = degIn val isPos = degIn >= 0 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) val degOut = degIn.toInt() val minutes = 60 * (degIn - degOut) val seconds = 0 - return arrayOf( - degOut.toString(), minutes.toString(), - seconds.toString(), - dirLetter.toString() - ) + return arrayOf(degOut.toString(), minutes.toString(), seconds.toString(), dirLetter.toString()) } -fun degreesToD(_degIn: Double, isLatitude: Boolean): Array { - var degIn = _degIn +fun degreesToD(degIn: Double, isLatitude: Boolean): Array { + var degIn = degIn val isPos = degIn >= 0 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) val degOut = degIn val minutes = 0 val seconds = 0 - return arrayOf( - degOut.toString(), minutes.toString(), - seconds.toString(), - dirLetter.toString() - ) + return arrayOf(degOut.toString(), minutes.toString(), seconds.toString(), dirLetter.toString()) } /** - * A not super efficent mapping from a starting lat/long + a distance at a - * certain direction + * A not super efficent mapping from a starting lat/long + a distance at a certain direction * * @param lat * @param longitude * @param distMeters - * @param theta - * in radians, 0 == north + * @param theta in radians, 0 == north * @return an array with lat and long */ -fun addDistance( - lat: Double, - longitude: Double, - distMeters: Double, - theta: Double -): DoubleArray { +@Suppress("MagicNumber") +fun addDistance(lat: Double, longitude: Double, distMeters: Double, theta: Double): DoubleArray { val dx = distMeters * sin(theta) // theta measured clockwise // from due north val dy = distMeters * cos(theta) // dx, dy same units as R @@ -190,20 +184,14 @@ fun addDistance( return doubleArrayOf(lat + dLat, longitude + dLong) } -/** - * @return distance in meters along the surface of the earth (ish) - */ -fun latLongToMeter( - lat_a: Double, - lng_a: Double, - lat_b: Double, - lng_b: Double -): Double { +/** @return distance in meters along the surface of the earth (ish) */ +@Suppress("MagicNumber") +fun latLongToMeter(latA: Double, lngA: Double, latB: Double, lngB: Double): Double { val pk = (180 / PI) - val a1 = lat_a / pk - val a2 = lng_a / pk - val b1 = lat_b / pk - val b2 = lng_b / pk + val a1 = latA / pk + val a2 = lngA / pk + val b1 = latB / pk + val b2 = lngB / pk val t1 = cos(a1) * cos(a2) * cos(b1) * cos(b2) val t2 = cos(a1) * sin(a2) * cos(b1) * sin(b2) val t3 = sin(a1) * sin(b1) @@ -213,14 +201,8 @@ fun latLongToMeter( } // 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 - ) -} +fun positionToMeter(a: MeshProtos.Position, b: MeshProtos.Position): Double = + 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 @@ -231,44 +213,24 @@ fun positionToMeter(a: MeshProtos.Position, b: MeshProtos.Position): Double { * @param isPostive * @return */ -fun DMSToDegrees( - degrees: Int, - minutes: Int, - seconds: Float, - isPostive: Boolean -): Double { - return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0) -} +@Suppress("MagicNumber") +fun dmsToDegrees(degrees: Int, minutes: Int, seconds: Float, isPostive: Boolean): Double = + (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0) -fun DMSToDegrees( - degrees: Double, - minutes: Double, - seconds: Double, - isPostive: Boolean -): Double { - return (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0) -} +@Suppress("MagicNumber") +fun dmsToDegrees(degrees: Double, minutes: Double, seconds: Double, isPostive: Boolean): Double = + (if (isPostive) 1 else -1) * (degrees + minutes / 60.0 + seconds / 3600.0) /** * Computes the bearing in degrees between two points on Earth. * - * @param lat1 - * Latitude of the first point - * @param lon1 - * Longitude of the first point - * @param lat2 - * 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. + * @param lat1 Latitude of the first point + * @param lon1 Longitude of the first point + * @param lat2 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( - lat1: Double, - lon1: Double, - lat2: Double, - lon2: Double -): Double { +fun bearing(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double { val lat1Rad = Math.toRadians(lat1) val lat2Rad = Math.toRadians(lat2) val deltaLonRad = Math.toRadians(lon2 - lon1) @@ -277,17 +239,16 @@ fun bearing( return radToBearing(atan2(y, x)) } -/** - * Converts an angle in radians to degrees - */ -fun radToBearing(rad: Double): Double { - return (Math.toDegrees(rad) + 360) % 360 -} +/** Converts an angle in radians to degrees */ +@Suppress("MagicNumber") +fun radToBearing(rad: Double): Double = (Math.toDegrees(rad) + 360) % 360 /** * Calculates the zoom level required to fit the entire [BoundingBox] inside the map view. + * * @return The zoom level as a Double value. */ +@Suppress("MagicNumber") fun BoundingBox.requiredZoomLevel(): Double { val topLeft = GeoPoint(this.latNorth, this.lonWest) 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]. + * * @return A new [BoundingBox] with added [zoomFactor]. Example: * ``` * // Setting the zoom level directly using setZoom() @@ -322,6 +284,6 @@ fun BoundingBox.zoomIn(zoomFactor: Double): BoundingBox { center.latitude + newLatDiff / 2, center.longitude + newLonDiff / 2, center.latitude - newLatDiff / 2, - center.longitude - newLonDiff / 2 + center.longitude - newLonDiff / 2, ) } diff --git a/mesh_service_example/src/main/kotlin/com/meshtastic/android/meshserviceexample/MainActivity.kt b/mesh_service_example/src/main/kotlin/com/meshtastic/android/meshserviceexample/MainActivity.kt index 79b8164f8..119b74f48 100644 --- a/mesh_service_example/src/main/kotlin/com/meshtastic/android/meshserviceexample/MainActivity.kt +++ b/mesh_service_example/src/main/kotlin/com/meshtastic/android/meshserviceexample/MainActivity.kt @@ -50,6 +50,7 @@ class MainActivity : AppCompatActivity() { private var isMeshServiceBound = false @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) + @Suppress("TooGenericExceptionCaught", "LongMethod") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) this.enableEdgeToEdge() @@ -109,6 +110,7 @@ class MainActivity : AppCompatActivity() { val meshtasticReceiver: BroadcastReceiver = object : BroadcastReceiver() { @SuppressLint("SetTextI18n") + @Suppress("ReturnCount") override fun onReceive(context: Context?, intent: Intent?) { if (intent == null) { Log.w(TAG, "Received null intent") @@ -166,7 +168,7 @@ class MainActivity : AppCompatActivity() { Log.d(TAG, "Position App NodeInfo: $ni") mainTextView.text = "Position App NodeInfo: $ni" } catch (e: Exception) { - e.printStackTrace() + Log.e(TAG, "onReceive: $e") return } } @@ -189,7 +191,8 @@ class MainActivity : AppCompatActivity() { while (!bindMeshService()) { try { - Thread.sleep(1000) + @Suppress("MagicNumber") + Thread.sleep(1_000) } catch (e: InterruptedException) { Log.e(TAG, "Binding interrupted", e) break