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