Skip to content

Commit 40d4e32

Browse files
fix(android): show specific gateway auth-recovery reason instead of generic label (#98698)
* fix(android): distinguish gateway auth-recovery reasons instead of one generic label gatewaySummary()/gatewayStatusLabel() collapsed every auth failure (expired setup QR, missing/invalid token, missing/invalid password, stale device identity) into "Authentication needed", discarding the already-computed MainViewModel.gatewayConnectionProblem signal consumed elsewhere in the app (OnboardingFlow's recoveryGatewayAuthDetail). Thread it into both status labels via a shared gatewayAuthNeededSummary() helper so the Overview and Settings screens tell the user which recovery action applies. Fixes #98046 * test(android): lock gateway auth-needed labels to the real unauthorized message format Verified against src/gateway/server/ws-connection/auth-messages.ts: formatGatewayAuthFailureMessage always returns strings starting with "unauthorized", which contains the "auth" substring the status-text gate checks for. Add tests using the exact real-world message text (not just synthetic "auth failed" strings) so this stays regression-locked. * fix(android): widen the auth-needed status gate to cover device-identity failures CONTROL_UI_DEVICE_IDENTITY_REQUIRED/DEVICE_IDENTITY_REQUIRED real gateway messages ("device identity required", "control ui requires device identity...") don't contain "auth", so the status.contains("auth") gate never reached their specific label. Add "device identity" as an additional substring the gate checks for those two codes, with regression tests using the exact real message text (message-handler.ts). Verified via GitHub-style codex review round 2 (round 1's "unauthorized doesn't contain auth" claim was checked against source and rejected as false — "unauthorized" does contain "auth" — but this second, narrower finding about device-identity codes held up under the same source check). * fix(android): centralize gateway auth status labels * fix(android): correlate gateway connection diagnostics * chore(android): align native i18n inventory after rebase * fix(android): preserve retryable pairing guidance --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent 0ccdef5 commit 40d4e32

17 files changed

Lines changed: 773 additions & 364 deletions

apps/.i18n/native-source.json

Lines changed: 247 additions & 247 deletions
Large diffs are not rendered by default.

apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class MainViewModel(
115115
runtimeState(initial = GatewayNodeApprovalState.Loading) { it.nodeCapabilityApprovalState }
116116
val statusText: StateFlow<String> = runtimeState(initial = "Offline") { it.statusText }
117117
val gatewayConnectionProblem: StateFlow<GatewayConnectionProblem?> = runtimeState(initial = null) { it.gatewayConnectionProblem }
118+
val gatewayConnectionDisplay: StateFlow<GatewayConnectionDisplay> =
119+
runtimeState(initial = GatewayConnectionDisplay(false, "Offline", null)) { it.gatewayConnectionDisplay }
118120
val serverName: StateFlow<String?> = runtimeState(initial = null) { it.serverName }
119121
val remoteAddress: StateFlow<String?> = runtimeState(initial = null) { it.remoteAddress }
120122
val gatewayVersion: StateFlow<String?> = runtimeState(initial = null) { it.gatewayVersion }

apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,20 @@ class NodeForegroundService : Service() {
3636
stopSelf()
3737
return
3838
}
39-
// Split connection and capture flows before combining so notification text
39+
// Keep the connection tuple atomic, then split connection and capture work so notification text
4040
// can update without restarting runtime-owned connection work.
4141
notificationJob =
4242
scope.launch {
4343
combine(
4444
combine(
45-
runtime.statusText,
45+
runtime.gatewayConnectionDisplay,
4646
runtime.serverName,
47-
runtime.isConnected,
4847
runtime.voiceCaptureMode,
49-
) { status, server, connected, mode ->
48+
) { connection, server, mode ->
5049
VoiceNotificationBase(
51-
status = status,
50+
status = connection.statusText,
5251
server = server,
53-
connected = connected,
52+
connected = connection.isConnected,
5453
mode = mode,
5554
)
5655
},

0 commit comments

Comments
 (0)