From 532da7ed3e7e93c9fb5f5f01aa8afab4e7cb60fc Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 3 Jul 2026 01:00:47 +0000 Subject: [PATCH 1/2] fix(migration): handle plain-text success response from migrateHostname JNI The native migrateHostname() returns a plain-text string on success ("Migrated hostname for N bucket(s)") but a JSON error object on failure ({"error": "..."}). The Kotlin code was incorrectly trying to parse the success response as JSON, which always failed, so setHostnameMigrated() was never called and migration would retry on every app start. This also caused two spurious logcat warnings on fresh install: W Migration result was not valid JSON; will retry on next start W Hostname migration reported failure; will retry on next start Fix: check for the known plain-text success prefix first. Only parse JSON when the result doesn't match success, and extract the "error" field for a single, informative warning instead of two misleading ones. Fixes: ActivityWatch/aw-android#171 --- .../android/BackgroundService.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt b/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt index 204f9b4a..038e9441 100644 --- a/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt +++ b/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt @@ -64,19 +64,23 @@ class BackgroundService : Service() { val hostname = rustInterface.getDeviceName(this@BackgroundService) val result = rustInterface.migrateHostname(hostname) Log.i(TAG, "Hostname migration result: $result") - // Conservative defaults: treat ambiguous responses (non-JSON or absent "success" key) - // as failures so the migration is retried on the next start rather than being - // permanently silenced before the server was actually ready. - val migrationSucceeded = try { - JSONObject(result).optBoolean("success", false) - } catch (e: JSONException) { - Log.w(TAG, "Migration result was not valid JSON; will retry on next start") + // The native migrateHostname() returns a plain-text success string + // ("Migrated hostname for N bucket(s)") or a JSON error object + // ({"error": "..."}). Treat the plain-text prefix as success; only + // retry when the native lib explicitly reports an error. + val migrationSucceeded = if (result.startsWith("Migrated hostname for")) { + true + } else { + val errorMsg = try { + JSONObject(result).optString("error", null) + } catch (e: JSONException) { + result.ifEmpty { "empty response" } + } + Log.w(TAG, "Hostname migration failed ($errorMsg); will retry on next start") false } if (migrationSucceeded) { prefs.setHostnameMigrated() - } else { - Log.w(TAG, "Hostname migration reported failure; will retry on next start") } } } From ad07391462c49f742a8f85c54340b25304bd76d3 Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 3 Jul 2026 01:09:32 +0000 Subject: [PATCH 2/2] fix(migration): use raw result as fallback in error log When the JSON doesn't contain an 'error' key, optString('error', null) logged '(null)'. Use result as fallback so the raw payload is always visible for debugging. --- .../main/java/net/activitywatch/android/BackgroundService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt b/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt index 038e9441..c0588e7c 100644 --- a/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt +++ b/mobile/src/main/java/net/activitywatch/android/BackgroundService.kt @@ -72,7 +72,7 @@ class BackgroundService : Service() { true } else { val errorMsg = try { - JSONObject(result).optString("error", null) + JSONObject(result).optString("error", result) } catch (e: JSONException) { result.ifEmpty { "empty response" } }