diff --git a/app/src/main/java/com/rtbishop/look4sat/AprsForegroundService.kt b/app/src/main/java/com/rtbishop/look4sat/AprsForegroundService.kt
index c9e67028..d9591d96 100644
--- a/app/src/main/java/com/rtbishop/look4sat/AprsForegroundService.kt
+++ b/app/src/main/java/com/rtbishop/look4sat/AprsForegroundService.kt
@@ -120,6 +120,11 @@ class AprsForegroundService : Service() {
// problem is the passcode - and APRS-IS is dropping every packet meanwhile.
val msg = when {
report.ok -> getString(R.string.aprs_toast_ok)
+ // Receive-only first: it logs in with -1 exactly as a wrong passcode does and
+ // the server answers "unverified" to both, so without this branch the one safe
+ // way to test a setup reported itself as a configuration error.
+ !report.verified && report.receiveOnly ->
+ getString(R.string.aprs_toast_receive_only)
!report.verified -> getString(R.string.aprs_toast_unverified)
else -> getString(R.string.aprs_toast_fail, report.detail)
}
@@ -147,7 +152,13 @@ class AprsForegroundService : Service() {
try {
val notif = buildNotification(cfg)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- startForeground(NOTIF_ID, notif, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
+ // Must match the manifest attribute or the platform refuses the call: AOSP checks the
+ // passed type is a subset of the declared one, and location (0x08) does not contain
+ // dataSync (0x01). Changing the manifest without changing this line stopped the
+ // service dead on Android 10 and later - the IllegalArgumentException was caught
+ // below and turned into stopSelf(), so APRS did nothing and reported nothing while
+ // the settings switch stayed on.
+ startForeground(NOTIF_ID, notif, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION)
} else {
startForeground(NOTIF_ID, notif)
}
diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/aprs/AprsReporter.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/aprs/AprsReporter.kt
index a8dfdb45..5a2cd0e7 100644
--- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/aprs/AprsReporter.kt
+++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/aprs/AprsReporter.kt
@@ -43,7 +43,16 @@ data class AprsReport(
* nothing reaching the network. A login whose response we simply could not parse leaves this
* true, since the packets may be landing and the passcode is not at fault.
*/
- val verified: Boolean = true
+ val verified: Boolean = true,
+ /**
+ * True when the operator asked for a receive-only connection.
+ *
+ * Distinguished from a refused login because both log in with -1 and the server answers
+ * "unverified" to each: without this, deliberately choosing receive-only - the one way to
+ * test a setup without putting anything on the network - was reported as a wrong passcode
+ * and sent the operator to fix something they had set on purpose.
+ */
+ val receiveOnly: Boolean = false
)
/** Report scheduler (periodic + manual trigger); connection management lives in the foreground service */
@@ -94,19 +103,9 @@ class AprsReporter(
if (!cfg.enabled || cfg.callsign.isBlank()) return
onState(AprsState.Connecting)
try {
- val c = client ?: AprsIsClient(
- host = cfg.server,
- port = cfg.port,
- callsign = cfg.callsign,
- ssid = cfg.ssid,
- // Never derives one: a blank or wrong entry logs in receive-only rather than
- // transmitting under a passcode the app invented for an unchecked licence.
- passcode = AprsPasscode.loginValue(cfg.callsign, cfg.passcode),
- version = "Look4Sat 4.5.4"
- ).also { client = it }
- if (!c.isConnected) c.connect()
- onState(AprsState.Connected)
-
+ // The packet is built BEFORE connecting: there is no reason to open a session and log
+ // in only to discover there is nothing to send, which happened every five minutes for
+ // an operator whose QTH was unset.
val pos = positionProvider()
val beacon = AprsBeacon.build(
callsign = cfg.callsign,
@@ -127,6 +126,23 @@ class AprsReporter(
return
}
val packetLine = (beacon as AprsBeacon.Result.Line).text
+
+ // Receive-only is a deliberate choice, not a mistake, and has to be carried through:
+ // it logs in with -1 exactly as a wrong passcode does, and the server answers
+ // "unverified" to both.
+ val wantsReceiveOnly = !AprsPasscode.canTransmit(cfg.callsign, cfg.passcode)
+ val c = client ?: AprsIsClient(
+ host = cfg.server,
+ port = cfg.port,
+ callsign = cfg.callsign,
+ ssid = cfg.ssid,
+ // Never derives one: a blank or wrong entry logs in receive-only rather than
+ // transmitting under a passcode the app invented for an unchecked licence.
+ passcode = AprsPasscode.loginValue(cfg.callsign, cfg.passcode),
+ version = "Look4Sat 4.5.4"
+ ).also { client = it }
+ if (!c.isConnected) c.connect()
+ onState(AprsState.Connected)
val result = c.sendPacket(packetLine)
val sent = result?.first == true
val detail = result?.second ?: "no connection"
@@ -137,7 +153,21 @@ class AprsReporter(
// the operator to fix something that is not broken.
val refused = c.isRefusedByServer
val ok = sent && !refused
- onReport(AprsReport(System.currentTimeMillis(), packetLine, ok, detail, !refused))
+ // "sent" is the write's own verdict and reads as nonsense next to a failure - the card
+ // showed "failed - sent" for a refused login. When the refusal is what failed the
+ // report, say that instead.
+ val reported = when {
+ ok -> detail
+ refused && wantsReceiveOnly -> "receive-only, not forwarded"
+ refused -> "login not verified"
+ else -> detail
+ }
+ onReport(
+ AprsReport(
+ System.currentTimeMillis(), packetLine, ok, reported,
+ verified = !refused, receiveOnly = wantsReceiveOnly
+ )
+ )
if (ok) onState(AprsState.Connected) else onState(AprsState.Error)
} catch (e: Exception) {
runCatching { client?.disconnect() }
diff --git a/core/presentation/src/main/res/values-id/strings.xml b/core/presentation/src/main/res/values-id/strings.xml
index ebaf0a91..0994afe7 100644
--- a/core/presentation/src/main/res/values-id/strings.xml
+++ b/core/presentation/src/main/res/values-id/strings.xml
@@ -39,6 +39,7 @@
APRS: laporan terkirim
APRS: laporan gagal - %1$s
APRS-IS tidak memverifikasi passcode Anda. Laporan Anda tidak diteruskan - periksa tanda panggil dan passcode di Pengaturan.
+ APRS-IS menerima koneksi dalam mode terima-saja, laporan Anda tidak diteruskan. Masukkan passcode untuk mengirim.
APRS belum dikonfigurasi - isi panggilan dulu
Laporan terakhir: %1$s %2$s
OK
diff --git a/core/presentation/src/main/res/values-in/strings.xml b/core/presentation/src/main/res/values-in/strings.xml
index add9bf6b..e76ae75e 100644
--- a/core/presentation/src/main/res/values-in/strings.xml
+++ b/core/presentation/src/main/res/values-in/strings.xml
@@ -39,6 +39,7 @@
APRS: laporan terkirim
APRS: laporan gagal - %1$s
APRS-IS tidak memverifikasi passcode Anda. Laporan Anda tidak diteruskan - periksa tanda panggil dan passcode di Pengaturan.
+ APRS-IS menerima koneksi dalam mode terima-saja, laporan Anda tidak diteruskan. Masukkan passcode untuk mengirim.
APRS belum dikonfigurasi - isi panggilan dulu
Laporan terakhir: %1$s %2$s
OK
diff --git a/core/presentation/src/main/res/values-tr/strings.xml b/core/presentation/src/main/res/values-tr/strings.xml
index b294c23d..cc3cf9ef 100644
--- a/core/presentation/src/main/res/values-tr/strings.xml
+++ b/core/presentation/src/main/res/values-tr/strings.xml
@@ -40,6 +40,7 @@
APRS: rapor gönderildi
APRS: rapor başarısız - %1$s
APRS-IS passcode bilginizi doğrulamadı. Raporlarınız iletilmiyor - Ayarlar bölümünde çağrı işareti ve passcode bilgisini kontrol edin.
+ APRS-IS baglantiyi yalnizca alma modunda kabul etti, raporlariniz iletilmiyor. Gondermek icin passcode girin.
APRS yapılandırılmadı - önce çağrı girin
Son rapor: %1$s %2$s
OK
diff --git a/core/presentation/src/main/res/values-zh/strings.xml b/core/presentation/src/main/res/values-zh/strings.xml
index 4b794948..8093fcb6 100644
--- a/core/presentation/src/main/res/values-zh/strings.xml
+++ b/core/presentation/src/main/res/values-zh/strings.xml
@@ -41,6 +41,7 @@
APRS: 上报成功
APRS: 上报失败 - %1$s
APRS-IS 未验证你的 passcode, 上报不会被转发 - 请在设置里检查呼号与 passcode。
+ APRS-IS 以只收模式接受了连接, 上报不会被转发。填入 passcode 才能发射。
APRS 未配置,请先填呼号
上次上报: %1$s %2$s
成功
diff --git a/core/presentation/src/main/res/values/strings.xml b/core/presentation/src/main/res/values/strings.xml
index 0199b181..8b9fd427 100644
--- a/core/presentation/src/main/res/values/strings.xml
+++ b/core/presentation/src/main/res/values/strings.xml
@@ -42,6 +42,7 @@
APRS: report sent OK
APRS: report failed - %1$s
APRS-IS did not verify your passcode. Your reports are not being passed on - check the callsign and passcode in Settings.
+ APRS-IS accepted the connection in receive-only mode, so your reports are not forwarded. Enter your passcode to transmit.
APRS not configured - set callsign first
Last report: %1$s %2$s
OK