diff --git a/apps/.i18n/native-source.json b/apps/.i18n/native-source.json
index 1ce7cb78a289..422b474afefb 100644
--- a/apps/.i18n/native-source.json
+++ b/apps/.i18n/native-source.json
@@ -539,7 +539,7 @@
},
{
"kind": "ui-state-text",
- "line": 274,
+ "line": 278,
"path": "apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt",
"source": "Searching…",
"surface": "android",
@@ -547,7 +547,7 @@
},
{
"kind": "ui-state-text",
- "line": 385,
+ "line": 398,
"path": "apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt",
"source": "Mic off",
"surface": "android",
@@ -555,7 +555,7 @@
},
{
"kind": "ui-state-text",
- "line": 399,
+ "line": 412,
"path": "apps/android/app/src/main/java/ai/openclaw/app/MainViewModel.kt",
"source": "Off",
"surface": "android",
@@ -691,7 +691,7 @@
},
{
"kind": "ui-call",
- "line": 141,
+ "line": 150,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Resolution outcome unknown. Actions stay disabled until the Gateway record is verified.",
"surface": "android",
@@ -699,7 +699,7 @@
},
{
"kind": "ui-call",
- "line": 143,
+ "line": 152,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "The Gateway still shows this approval as pending. Review it before trying again.",
"surface": "android",
@@ -707,7 +707,7 @@
},
{
"kind": "ui-call",
- "line": 145,
+ "line": 154,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load approval details. Refresh and try again.",
"surface": "android",
@@ -715,7 +715,7 @@
},
{
"kind": "ui-call",
- "line": 147,
+ "line": 156,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load approvals.",
"surface": "android",
@@ -723,7 +723,7 @@
},
{
"kind": "ui-call",
- "line": 149,
+ "line": 158,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not resolve approval. Refresh and try again.",
"surface": "android",
@@ -731,7 +731,7 @@
},
{
"kind": "ui-call",
- "line": 164,
+ "line": 173,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Proposal applied.",
"surface": "android",
@@ -739,7 +739,7 @@
},
{
"kind": "ui-call",
- "line": 164,
+ "line": 173,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "apply",
"surface": "android",
@@ -747,7 +747,7 @@
},
{
"kind": "ui-call",
- "line": 165,
+ "line": 174,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Proposal rejected.",
"surface": "android",
@@ -755,7 +755,7 @@
},
{
"kind": "ui-call",
- "line": 165,
+ "line": 174,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "reject",
"surface": "android",
@@ -763,7 +763,7 @@
},
{
"kind": "ui-call",
- "line": 166,
+ "line": 175,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Proposal quarantined.",
"surface": "android",
@@ -771,7 +771,7 @@
},
{
"kind": "ui-call",
- "line": 166,
+ "line": 175,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "quarantine",
"surface": "android",
@@ -779,7 +779,7 @@
},
{
"kind": "ui-call",
- "line": 173,
+ "line": 182,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "unknown",
"surface": "android",
@@ -787,7 +787,7 @@
},
{
"kind": "ui-call",
- "line": 174,
+ "line": 183,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Gateway returned status '$statusLabel' after ${action.verb}.",
"surface": "android",
@@ -795,7 +795,7 @@
},
{
"kind": "ui-call",
- "line": 182,
+ "line": 191,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not ${action.verb} Skill Workshop proposal.",
"surface": "android",
@@ -803,7 +803,7 @@
},
{
"kind": "ui-call",
- "line": 364,
+ "line": 373,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connected (node offline)",
"surface": "android",
@@ -811,7 +811,7 @@
},
{
"kind": "ui-call",
- "line": 365,
+ "line": 374,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connected (operator offline)",
"surface": "android",
@@ -819,7 +819,7 @@
},
{
"kind": "ui-call",
- "line": 367,
+ "line": 376,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Reconnecting…",
"surface": "android",
@@ -827,7 +827,7 @@
},
{
"kind": "ui-call",
- "line": 375,
+ "line": 384,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connected (operator: $operator)",
"surface": "android",
@@ -835,7 +835,7 @@
},
{
"kind": "ui-call",
- "line": 1681,
+ "line": 1751,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "This automation already has a queued run.",
"surface": "android",
@@ -843,7 +843,7 @@
},
{
"kind": "ui-call",
- "line": 1711,
+ "line": 1781,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Automation run queued.",
"surface": "android",
@@ -851,7 +851,7 @@
},
{
"kind": "ui-call",
- "line": 1711,
+ "line": 1781,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Automation started.",
"surface": "android",
@@ -859,7 +859,7 @@
},
{
"kind": "ui-call",
- "line": 1724,
+ "line": 1794,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Gateway rejected the automation run.",
"surface": "android",
@@ -867,7 +867,7 @@
},
{
"kind": "ui-call",
- "line": 1755,
+ "line": 1825,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Automation enabled.",
"surface": "android",
@@ -875,7 +875,7 @@
},
{
"kind": "ui-call",
- "line": 1755,
+ "line": 1825,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Automation paused.",
"surface": "android",
@@ -883,7 +883,7 @@
},
{
"kind": "ui-call",
- "line": 1777,
+ "line": 1847,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "This automation changed on the gateway. Review the latest version before saving again.",
"surface": "android",
@@ -891,7 +891,7 @@
},
{
"kind": "ui-call",
- "line": 1783,
+ "line": 1853,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Automation updated.",
"surface": "android",
@@ -899,7 +899,7 @@
},
{
"kind": "ui-call",
- "line": 1798,
+ "line": 1868,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Automation deleted.",
"surface": "android",
@@ -907,7 +907,7 @@
},
{
"kind": "ui-call",
- "line": 2003,
+ "line": 2073,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Node offline. Reconnect and retry.",
"surface": "android",
@@ -915,7 +915,7 @@
},
{
"kind": "ui-named-argument-concatenated",
- "line": 2014,
+ "line": 2084,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Restore canvas now for session=$sessionKey source=$source. If existing A2UI state exists, replay it immediately. If not, create and render a compact mobile-friendly dashboard in Canvas.",
"surface": "android",
@@ -923,7 +923,7 @@
},
{
"kind": "ui-call",
- "line": 2035,
+ "line": 2105,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Failed to request restore. Tap to retry.",
"surface": "android",
@@ -931,7 +931,7 @@
},
{
"kind": "ui-call",
- "line": 2046,
+ "line": 2116,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "No canvas update yet. Tap to retry.",
"surface": "android",
@@ -939,7 +939,31 @@
},
{
"kind": "ui-call",
- "line": 3434,
+ "line": 3007,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
+ "source": "Connect to a Gateway to save wake words",
+ "surface": "android",
+ "id": "native.android.00a2531a39904d08"
+ },
+ {
+ "kind": "ui-call",
+ "line": 3035,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
+ "source": "Wake words saved",
+ "surface": "android",
+ "id": "native.android.538201c75b85068f"
+ },
+ {
+ "kind": "ui-call",
+ "line": 3044,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
+ "source": "Could not save wake words",
+ "surface": "android",
+ "id": "native.android.b367e85de3a7148f"
+ },
+ {
+ "kind": "ui-call",
+ "line": 3728,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
"surface": "android",
@@ -947,7 +971,7 @@
},
{
"kind": "ui-call",
- "line": 3438,
+ "line": 3732,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Failed: secure endpoint reached, but TLS fingerprint verification timed out. Check Tailscale Serve or gateway TLS and retry.",
"surface": "android",
@@ -955,7 +979,7 @@
},
{
"kind": "ui-call",
- "line": 3442,
+ "line": 3736,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Failed: couldn't reach the secure gateway endpoint for this host.",
"surface": "android",
@@ -963,7 +987,7 @@
},
{
"kind": "ui-named-argument",
- "line": 3486,
+ "line": 3780,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connecting…",
"surface": "android",
@@ -971,7 +995,7 @@
},
{
"kind": "ui-named-argument",
- "line": 3666,
+ "line": 3961,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Offline",
"surface": "android",
@@ -979,7 +1003,7 @@
},
{
"kind": "ui-call",
- "line": 4188,
+ "line": 4610,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load provider catalog.",
"surface": "android",
@@ -987,7 +1011,7 @@
},
{
"kind": "ui-call",
- "line": 4219,
+ "line": 4641,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Update your Gateway to view provider model config.",
"surface": "android",
@@ -995,7 +1019,7 @@
},
{
"kind": "ui-call",
- "line": 4221,
+ "line": 4643,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load provider model config.",
"surface": "android",
@@ -1003,7 +1027,7 @@
},
{
"kind": "ui-call",
- "line": 4237,
+ "line": 4659,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Provider models loaded, but readiness is unavailable.",
"surface": "android",
@@ -1011,7 +1035,7 @@
},
{
"kind": "ui-call",
- "line": 4324,
+ "line": 4746,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load automations.",
"surface": "android",
@@ -1019,7 +1043,7 @@
},
{
"kind": "ui-call",
- "line": 4410,
+ "line": 4832,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to inspect automations.",
"surface": "android",
@@ -1027,7 +1051,7 @@
},
{
"kind": "ui-call",
- "line": 4420,
+ "line": 4842,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Gateway returned an invalid automation.",
"surface": "android",
@@ -1035,7 +1059,7 @@
},
{
"kind": "ui-call",
- "line": 4424,
+ "line": 4846,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load automation.",
"surface": "android",
@@ -1043,7 +1067,7 @@
},
{
"kind": "ui-call",
- "line": 4436,
+ "line": 4858,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to inspect automation run history.",
"surface": "android",
@@ -1051,7 +1075,7 @@
},
{
"kind": "ui-call",
- "line": 4467,
+ "line": 4889,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load automation run history.",
"surface": "android",
@@ -1059,7 +1083,7 @@
},
{
"kind": "ui-call",
- "line": 4484,
+ "line": 4906,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Cron changes require operator.admin access.",
"surface": "android",
@@ -1067,7 +1091,7 @@
},
{
"kind": "ui-call",
- "line": 4493,
+ "line": 4915,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to manage automations.",
"surface": "android",
@@ -1075,7 +1099,7 @@
},
{
"kind": "ui-call",
- "line": 4505,
+ "line": 4927,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Another cron action is still finishing.",
"surface": "android",
@@ -1083,7 +1107,7 @@
},
{
"kind": "ui-call",
- "line": 4552,
+ "line": 4974,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Cron action failed.",
"surface": "android",
@@ -1091,7 +1115,7 @@
},
{
"kind": "ui-call",
- "line": 4679,
+ "line": 5101,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load usage.",
"surface": "android",
@@ -1099,7 +1123,7 @@
},
{
"kind": "ui-call",
- "line": 4714,
+ "line": 5136,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load skills.",
"surface": "android",
@@ -1107,7 +1131,7 @@
},
{
"kind": "ui-call",
- "line": 4727,
+ "line": 5149,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to update skills.",
"surface": "android",
@@ -1115,7 +1139,7 @@
},
{
"kind": "ui-call",
- "line": 4731,
+ "line": 5153,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "This gateway connection needs operator.admin to update skills.",
"surface": "android",
@@ -1123,7 +1147,7 @@
},
{
"kind": "conditional-branch",
- "line": 4746,
+ "line": 5168,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not disable skill.",
"surface": "android",
@@ -1131,7 +1155,7 @@
},
{
"kind": "conditional-branch",
- "line": 4746,
+ "line": 5168,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not enable skill.",
"surface": "android",
@@ -1139,7 +1163,7 @@
},
{
"kind": "ui-call",
- "line": 4764,
+ "line": 5186,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to search ClawHub skills.",
"surface": "android",
@@ -1147,7 +1171,7 @@
},
{
"kind": "ui-call",
- "line": 4810,
+ "line": 5232,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not search ClawHub skills.",
"surface": "android",
@@ -1155,7 +1179,7 @@
},
{
"kind": "ui-call",
- "line": 4823,
+ "line": 5245,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to inspect ClawHub skills.",
"surface": "android",
@@ -1163,7 +1187,7 @@
},
{
"kind": "conditional-branch",
- "line": 4856,
+ "line": 5278,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "ClawHub did not return an installable version for ${skill.slug}.",
"surface": "android",
@@ -1171,7 +1195,7 @@
},
{
"kind": "ui-call",
- "line": 4872,
+ "line": 5294,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load ClawHub details for ${skill.slug}.",
"surface": "android",
@@ -1179,7 +1203,7 @@
},
{
"kind": "ui-call",
- "line": 4888,
+ "line": 5310,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to install ClawHub skills.",
"surface": "android",
@@ -1187,7 +1211,7 @@
},
{
"kind": "ui-call",
- "line": 4904,
+ "line": 5326,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "This gateway connection needs operator.admin to install ClawHub skills.",
"surface": "android",
@@ -1195,7 +1219,7 @@
},
{
"kind": "conditional-branch",
- "line": 4994,
+ "line": 5416,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Installed $slug.",
"surface": "android",
@@ -1203,7 +1227,7 @@
},
{
"kind": "ui-call",
- "line": 5001,
+ "line": 5423,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not install ${slug} from ClawHub.",
"surface": "android",
@@ -1211,7 +1235,7 @@
},
{
"kind": "ui-call",
- "line": 5041,
+ "line": 5463,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to load Skill Workshop proposals.",
"surface": "android",
@@ -1219,7 +1243,7 @@
},
{
"kind": "ui-call",
- "line": 5081,
+ "line": 5503,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load Skill Workshop proposals.",
"surface": "android",
@@ -1227,7 +1251,7 @@
},
{
"kind": "ui-call",
- "line": 5101,
+ "line": 5523,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to inspect Skill Workshop proposals.",
"surface": "android",
@@ -1235,7 +1259,7 @@
},
{
"kind": "ui-call",
- "line": 5153,
+ "line": 5575,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not inspect Skill Workshop proposal.",
"surface": "android",
@@ -1243,7 +1267,7 @@
},
{
"kind": "ui-call",
- "line": 5173,
+ "line": 5595,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Skill Workshop proposal actions require operator.admin scope.",
"surface": "android",
@@ -1251,7 +1275,7 @@
},
{
"kind": "ui-call",
- "line": 5178,
+ "line": 5600,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect the gateway to update Skill Workshop proposals.",
"surface": "android",
@@ -1259,7 +1283,7 @@
},
{
"kind": "ui-named-argument",
- "line": 5337,
+ "line": 5759,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connected",
"surface": "android",
@@ -1267,7 +1291,7 @@
},
{
"kind": "ui-call",
- "line": 5363,
+ "line": 5785,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load nodes and devices.",
"surface": "android",
@@ -1275,7 +1299,7 @@
},
{
"kind": "ui-call",
- "line": 6021,
+ "line": 6443,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load channels.",
"surface": "android",
@@ -1283,7 +1307,7 @@
},
{
"kind": "ui-call",
- "line": 6051,
+ "line": 6473,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load dreaming.",
"surface": "android",
@@ -1291,7 +1315,7 @@
},
{
"kind": "ui-call",
- "line": 6088,
+ "line": 6510,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Could not load gateway logs.",
"surface": "android",
@@ -1299,7 +1323,7 @@
},
{
"kind": "ui-call",
- "line": 6545,
+ "line": 6967,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "One time",
"surface": "android",
@@ -1307,7 +1331,7 @@
},
{
"kind": "ui-call",
- "line": 6554,
+ "line": 6976,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Cron",
"surface": "android",
@@ -1315,7 +1339,7 @@
},
{
"kind": "ui-call",
- "line": 6555,
+ "line": 6977,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Scheduled",
"surface": "android",
@@ -1323,7 +1347,7 @@
},
{
"kind": "ui-call",
- "line": 6563,
+ "line": 6985,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Every ${days}d",
"surface": "android",
@@ -1331,7 +1355,7 @@
},
{
"kind": "ui-call",
- "line": 6564,
+ "line": 6986,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Every ${hours}h",
"surface": "android",
@@ -1339,7 +1363,7 @@
},
{
"kind": "ui-call",
- "line": 6565,
+ "line": 6987,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Every ${minutes}m",
"surface": "android",
@@ -1347,7 +1371,7 @@
},
{
"kind": "ui-call",
- "line": 6566,
+ "line": 6988,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Repeating",
"surface": "android",
@@ -1355,7 +1379,7 @@
},
{
"kind": "ui-call",
- "line": 6582,
+ "line": 7004,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "No prompt",
"surface": "android",
@@ -1363,7 +1387,7 @@
},
{
"kind": "ui-call",
- "line": 6599,
+ "line": 7021,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Gateway",
"surface": "android",
@@ -1371,7 +1395,7 @@
},
{
"kind": "ui-call",
- "line": 6607,
+ "line": 7029,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connected to $gatewayLabel",
"surface": "android",
@@ -1379,7 +1403,7 @@
},
{
"kind": "ui-call",
- "line": 6608,
+ "line": 7030,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Your agents are ready",
"surface": "android",
@@ -1387,7 +1411,7 @@
},
{
"kind": "ui-call",
- "line": 6610,
+ "line": 7032,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "This phone stays dormant until the gateway needs it, then wakes, syncs, and goes back to sleep.",
"surface": "android",
@@ -1395,7 +1419,7 @@
},
{
"kind": "ui-call",
- "line": 6614,
+ "line": 7036,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Selected on this phone",
"surface": "android",
@@ -1403,7 +1427,7 @@
},
{
"kind": "ui-call",
- "line": 6617,
+ "line": 7039,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "The overview refreshes on reconnect and when this screen opens.",
"surface": "android",
@@ -1411,7 +1435,7 @@
},
{
"kind": "ui-call",
- "line": 6622,
+ "line": 7044,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Reconnecting",
"surface": "android",
@@ -1419,7 +1443,7 @@
},
{
"kind": "ui-call",
- "line": 6623,
+ "line": 7045,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "OpenClaw is syncing back up",
"surface": "android",
@@ -1427,7 +1451,7 @@
},
{
"kind": "ui-call",
- "line": 6625,
+ "line": 7047,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "The gateway session is coming back online. Agent shortcuts should settle automatically in a moment.",
"surface": "android",
@@ -1435,7 +1459,7 @@
},
{
"kind": "ui-call",
- "line": 6629,
+ "line": 7051,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Gateway session in progress",
"surface": "android",
@@ -1443,7 +1467,7 @@
},
{
"kind": "ui-call",
- "line": 6632,
+ "line": 7054,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "If the gateway is reachable, reconnect should complete without intervention.",
"surface": "android",
@@ -1451,7 +1475,7 @@
},
{
"kind": "ui-call",
- "line": 6637,
+ "line": 7059,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Welcome to OpenClaw",
"surface": "android",
@@ -1459,7 +1483,7 @@
},
{
"kind": "ui-call",
- "line": 6638,
+ "line": 7060,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Your phone stays quiet until it is needed",
"surface": "android",
@@ -1467,7 +1491,7 @@
},
{
"kind": "ui-call",
- "line": 6640,
+ "line": 7062,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Pair this device to your gateway to wake it only for real work, keep a live agent overview handy, and avoid battery-draining background loops.",
"surface": "android",
@@ -1475,7 +1499,7 @@
},
{
"kind": "ui-call",
- "line": 6644,
+ "line": 7066,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Connect to load your agents",
"surface": "android",
@@ -1483,7 +1507,7 @@
},
{
"kind": "ui-call",
- "line": 6647,
+ "line": 7069,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "When connected, the gateway can wake the phone with a silent push instead of holding an always-on session.",
"surface": "android",
@@ -1491,7 +1515,7 @@
},
{
"kind": "ui-call",
- "line": 6679,
+ "line": 7101,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Main",
"surface": "android",
@@ -1499,7 +1523,7 @@
},
{
"kind": "ui-call",
- "line": 6694,
+ "line": 7116,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Active on this phone",
"surface": "android",
@@ -1507,7 +1531,7 @@
},
{
"kind": "ui-call",
- "line": 6695,
+ "line": 7117,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Default agent",
"surface": "android",
@@ -1515,7 +1539,7 @@
},
{
"kind": "ui-call",
- "line": 6696,
+ "line": 7118,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Ready",
"surface": "android",
@@ -1523,7 +1547,7 @@
},
{
"kind": "ui-call",
- "line": 7255,
+ "line": 7677,
"path": "apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt",
"source": "Dream",
"surface": "android",
@@ -1819,7 +1843,7 @@
},
{
"kind": "conditional-branch",
- "line": 1396,
+ "line": 1404,
"path": "apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt",
"source": "Connecting…",
"surface": "android",
@@ -1827,7 +1851,7 @@
},
{
"kind": "conditional-branch",
- "line": 1396,
+ "line": 1404,
"path": "apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt",
"source": "Reconnecting…",
"surface": "android",
@@ -6147,7 +6171,7 @@
},
{
"kind": "ui-call",
- "line": 247,
+ "line": 250,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Provider limits and quota health.",
"surface": "android",
@@ -6155,7 +6179,7 @@
},
{
"kind": "ui-call",
- "line": 247,
+ "line": 250,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Usage",
"surface": "android",
@@ -6163,7 +6187,7 @@
},
{
"kind": "ui-call",
- "line": 251,
+ "line": 254,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Providers",
"surface": "android",
@@ -6171,7 +6195,7 @@
},
{
"kind": "ui-call",
- "line": 267,
+ "line": 270,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connect the gateway to load usage.",
"surface": "android",
@@ -6179,7 +6203,7 @@
},
{
"kind": "ui-call",
- "line": 272,
+ "line": 275,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No usage data yet.",
"surface": "android",
@@ -6187,7 +6211,7 @@
},
{
"kind": "ui-call",
- "line": 273,
+ "line": 276,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Provider limits will appear here when your gateway reports them.",
"surface": "android",
@@ -6195,7 +6219,7 @@
},
{
"kind": "ui-call",
- "line": 312,
+ "line": 315,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Scheduled OpenClaw work from your gateway.",
"surface": "android",
@@ -6203,7 +6227,7 @@
},
{
"kind": "ui-call",
- "line": 317,
+ "line": 320,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Automations",
"surface": "android",
@@ -6211,7 +6235,7 @@
},
{
"kind": "ui-call",
- "line": 325,
+ "line": 328,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Search automations",
"surface": "android",
@@ -6219,7 +6243,7 @@
},
{
"kind": "ui-call",
- "line": 326,
+ "line": 329,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Search",
"surface": "android",
@@ -6227,7 +6251,7 @@
},
{
"kind": "ui-call",
- "line": 342,
+ "line": 345,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Open an automation to inspect its configuration and run history. Admin-scoped connections can also run, edit, enable, disable, or delete it.",
"surface": "android",
@@ -6235,7 +6259,7 @@
},
{
"kind": "ui-call",
- "line": 352,
+ "line": 355,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connect the gateway to load automations.",
"surface": "android",
@@ -6243,7 +6267,7 @@
},
{
"kind": "ui-call",
- "line": 357,
+ "line": 360,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No automations yet.",
"surface": "android",
@@ -6251,7 +6275,7 @@
},
{
"kind": "ui-call",
- "line": 358,
+ "line": 361,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Scheduled work created on the gateway will appear here.",
"surface": "android",
@@ -6259,7 +6283,7 @@
},
{
"kind": "ui-call",
- "line": 363,
+ "line": 366,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No matching automations.",
"surface": "android",
@@ -6267,7 +6291,7 @@
},
{
"kind": "ui-call",
- "line": 462,
+ "line": 465,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Automation",
"surface": "android",
@@ -6275,7 +6299,7 @@
},
{
"kind": "ui-call",
- "line": 463,
+ "line": 466,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Inspect and manage scheduled gateway work.",
"surface": "android",
@@ -6283,7 +6307,7 @@
},
{
"kind": "ui-call",
- "line": 484,
+ "line": 487,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connect the gateway to inspect automations.",
"surface": "android",
@@ -6291,7 +6315,7 @@
},
{
"kind": "ui-call",
- "line": 492,
+ "line": 495,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Automation not loaded.",
"surface": "android",
@@ -6299,7 +6323,7 @@
},
{
"kind": "ui-call",
- "line": 492,
+ "line": 495,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Loading automation…",
"surface": "android",
@@ -6307,7 +6331,7 @@
},
{
"kind": "ui-call",
- "line": 543,
+ "line": 546,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Choose and inspect the assistants available on this gateway.",
"surface": "android",
@@ -6315,7 +6339,7 @@
},
{
"kind": "ui-call",
- "line": 547,
+ "line": 550,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Available",
"surface": "android",
@@ -6323,7 +6347,7 @@
},
{
"kind": "ui-call",
- "line": 554,
+ "line": 557,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connect the gateway to load agents.",
"surface": "android",
@@ -6331,7 +6355,7 @@
},
{
"kind": "ui-call",
- "line": 558,
+ "line": 561,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No agents loaded yet.",
"surface": "android",
@@ -6339,7 +6363,7 @@
},
{
"kind": "ui-call",
- "line": 585,
+ "line": 588,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Approvals",
"surface": "android",
@@ -6347,7 +6371,7 @@
},
{
"kind": "ui-call",
- "line": 585,
+ "line": 588,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Review actions that need your attention.",
"surface": "android",
@@ -6355,7 +6379,7 @@
},
{
"kind": "ui-call",
- "line": 589,
+ "line": 592,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Gateway Pending",
"surface": "android",
@@ -6363,7 +6387,7 @@
},
{
"kind": "ui-call",
- "line": 590,
+ "line": 593,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Session Activity",
"surface": "android",
@@ -6371,7 +6395,7 @@
},
{
"kind": "ui-call",
- "line": 591,
+ "line": 594,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Issues",
"surface": "android",
@@ -6379,7 +6403,7 @@
},
{
"kind": "ui-call",
- "line": 592,
+ "line": 595,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Active Runs",
"surface": "android",
@@ -6387,7 +6411,7 @@
},
{
"kind": "ui-call",
- "line": 596,
+ "line": 599,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Refresh",
"surface": "android",
@@ -6395,7 +6419,7 @@
},
{
"kind": "ui-call",
- "line": 596,
+ "line": 599,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Refreshing",
"surface": "android",
@@ -6403,7 +6427,7 @@
},
{
"kind": "ui-call",
- "line": 614,
+ "line": 617,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Gateway disconnected.",
"surface": "android",
@@ -6411,7 +6435,7 @@
},
{
"kind": "ui-call",
- "line": 615,
+ "line": 618,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connect the gateway to load approval requests in the app.",
"surface": "android",
@@ -6419,7 +6443,7 @@
},
{
"kind": "ui-call",
- "line": 621,
+ "line": 624,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No gateway approvals.",
"surface": "android",
@@ -6427,7 +6451,7 @@
},
{
"kind": "ui-call",
- "line": 622,
+ "line": 625,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Exec approval requests will appear here while this phone is connected.",
"surface": "android",
@@ -6435,7 +6459,7 @@
},
{
"kind": "ui-call",
- "line": 632,
+ "line": 635,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Session activity",
"surface": "android",
@@ -6443,7 +6467,7 @@
},
{
"kind": "ui-call",
- "line": 633,
+ "line": 636,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Chat tool calls waiting in the active session remain visible here.",
"surface": "android",
@@ -6451,7 +6475,7 @@
},
{
"kind": "ui-call",
- "line": 647,
+ "line": 650,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "How this phone appears to OpenClaw.",
"surface": "android",
@@ -6459,7 +6483,7 @@
},
{
"kind": "ui-call",
- "line": 647,
+ "line": 650,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Profile",
"surface": "android",
@@ -6467,7 +6491,7 @@
},
{
"kind": "ui-call",
- "line": 650,
+ "line": 653,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Device name",
"surface": "android",
@@ -6475,7 +6499,7 @@
},
{
"kind": "ui-call",
- "line": 651,
+ "line": 654,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Save Profile",
"surface": "android",
@@ -6483,15 +6507,143 @@
},
{
"kind": "ui-call",
- "line": 670,
+ "line": 702,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
- "source": "Configure voice, transport, and playback.",
+ "source": "Configure wake words, talk, and playback.",
"surface": "android",
- "id": "native.android.19f0834b4dbcc85a"
+ "id": "native.android.deda55df7ca328fc"
},
{
"kind": "ui-call",
- "line": 670,
+ "line": 702,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Voice",
+ "surface": "android",
+ "id": "native.android.2ae2282617282586"
+ },
+ {
+ "kind": "ui-call",
+ "line": 704,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Voice Wake",
+ "surface": "android",
+ "id": "native.android.3f54d9356234744e"
+ },
+ {
+ "kind": "ui-call",
+ "line": 709,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Listen for wake words",
+ "surface": "android",
+ "id": "native.android.34ec8a3bc017cbd5"
+ },
+ {
+ "kind": "ui-call",
+ "line": 712,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "surface": "android",
+ "id": "native.android.6e58157abced395f"
+ },
+ {
+ "kind": "ui-call",
+ "line": 714,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "On-device speech recognition is unavailable.",
+ "surface": "android",
+ "id": "native.android.6464166ab71fde3f"
+ },
+ {
+ "kind": "ui-call",
+ "line": 724,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Wake listener",
+ "surface": "android",
+ "id": "native.android.35d996c1bc693bb9"
+ },
+ {
+ "kind": "ui-call",
+ "line": 726,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Last command: $command",
+ "surface": "android",
+ "id": "native.android.12fd2cd4e7d1d778"
+ },
+ {
+ "kind": "ui-call",
+ "line": 727,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Pauses during other voice activity.",
+ "surface": "android",
+ "id": "native.android.a36f052c5f1691d6"
+ },
+ {
+ "kind": "ui-call",
+ "line": 734,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Wake words",
+ "surface": "android",
+ "id": "native.android.a5272caac136694c"
+ },
+ {
+ "kind": "ui-call",
+ "line": 736,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "surface": "android",
+ "id": "native.android.37e7e27c16eca7fe"
+ },
+ {
+ "kind": "ui-call",
+ "line": 751,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Wake word or phrase",
+ "surface": "android",
+ "id": "native.android.95e42f0b4b6d4092"
+ },
+ {
+ "kind": "ui-call",
+ "line": 758,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Remove wake phrase",
+ "surface": "android",
+ "id": "native.android.0b35023a9220d572"
+ },
+ {
+ "kind": "ui-call",
+ "line": 767,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Add wake phrase",
+ "surface": "android",
+ "id": "native.android.0bff8c1428b32178"
+ },
+ {
+ "kind": "ui-call",
+ "line": 774,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Save wake words",
+ "surface": "android",
+ "id": "native.android.dfb84902f6a483d0"
+ },
+ {
+ "kind": "ui-call",
+ "line": 774,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Saving…",
+ "surface": "android",
+ "id": "native.android.5ab6829fa57f662d"
+ },
+ {
+ "kind": "ui-call",
+ "line": 779,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "Connect to a Gateway to save wake words",
+ "surface": "android",
+ "id": "native.android.672382a4b7900ee6"
+ },
+ {
+ "kind": "ui-call",
+ "line": 784,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Talk Provider Setup",
"surface": "android",
@@ -6499,7 +6651,7 @@
},
{
"kind": "ui-call",
- "line": 673,
+ "line": 786,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Audio Test",
"surface": "android",
@@ -6507,7 +6659,7 @@
},
{
"kind": "ui-call",
- "line": 674,
+ "line": 787,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Check that OpenClaw can speak clearly on this phone.",
"surface": "android",
@@ -6515,7 +6667,7 @@
},
{
"kind": "ui-call",
- "line": 677,
+ "line": 790,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Enable speaker",
"surface": "android",
@@ -6523,7 +6675,7 @@
},
{
"kind": "ui-call",
- "line": 677,
+ "line": 790,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Mute speaker",
"surface": "android",
@@ -6531,7 +6683,7 @@
},
{
"kind": "ui-call",
- "line": 678,
+ "line": 791,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Assistant speech muted",
"surface": "android",
@@ -6539,7 +6691,7 @@
},
{
"kind": "ui-call",
- "line": 678,
+ "line": 791,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Replies play aloud",
"surface": "android",
@@ -6547,7 +6699,7 @@
},
{
"kind": "ui-call",
- "line": 680,
+ "line": 793,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Muted",
"surface": "android",
@@ -6555,7 +6707,7 @@
},
{
"kind": "ui-call",
- "line": 680,
+ "line": 793,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "On",
"surface": "android",
@@ -6563,7 +6715,7 @@
},
{
"kind": "ui-call",
- "line": 684,
+ "line": 797,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Done",
"surface": "android",
@@ -6571,7 +6723,7 @@
},
{
"kind": "ui-call",
- "line": 694,
+ "line": 807,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Realtime Talk",
"surface": "android",
@@ -6579,7 +6731,7 @@
},
{
"kind": "ui-call",
- "line": 695,
+ "line": 808,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Dictation",
"surface": "android",
@@ -6587,7 +6739,7 @@
},
{
"kind": "ui-call",
- "line": 865,
+ "line": 978,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Choose what reaches OpenClaw.",
"surface": "android",
@@ -6595,7 +6747,7 @@
},
{
"kind": "ui-call",
- "line": 865,
+ "line": 978,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Notifications",
"surface": "android",
@@ -6603,7 +6755,7 @@
},
{
"kind": "ui-call",
- "line": 869,
+ "line": 982,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Alerts stay on this phone.",
"surface": "android",
@@ -6611,7 +6763,7 @@
},
{
"kind": "ui-call",
- "line": 869,
+ "line": 982,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Forward Notifications",
"surface": "android",
@@ -6619,7 +6771,7 @@
},
{
"kind": "ui-call",
- "line": 869,
+ "line": 982,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw can receive selected alerts.",
"surface": "android",
@@ -6627,15 +6779,7 @@
},
{
"kind": "ui-call",
- "line": 870,
- "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
- "source": "$quietStart to $quietEnd",
- "surface": "android",
- "id": "native.android.fef97bfb2cd5d228"
- },
- {
- "kind": "ui-call",
- "line": 870,
+ "line": 984,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Quiet Hours",
"surface": "android",
@@ -6643,7 +6787,15 @@
},
{
"kind": "ui-call",
- "line": 878,
+ "line": 985,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
+ "source": "$quietStart to $quietEnd",
+ "surface": "android",
+ "id": "native.android.fef97bfb2cd5d228"
+ },
+ {
+ "kind": "ui-call",
+ "line": 997,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Policy",
"surface": "android",
@@ -6651,7 +6803,7 @@
},
{
"kind": "ui-call",
- "line": 879,
+ "line": 998,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Selected Apps",
"surface": "android",
@@ -6659,7 +6811,7 @@
},
{
"kind": "ui-call",
- "line": 880,
+ "line": 999,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Rate Limit",
"surface": "android",
@@ -6667,7 +6819,7 @@
},
{
"kind": "ui-call",
- "line": 881,
+ "line": 1000,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Granted",
"surface": "android",
@@ -6675,7 +6827,7 @@
},
{
"kind": "ui-call",
- "line": 881,
+ "line": 1000,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Setup",
"surface": "android",
@@ -6683,7 +6835,7 @@
},
{
"kind": "ui-call",
- "line": 886,
+ "line": 1005,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Check Access",
"surface": "android",
@@ -6691,7 +6843,7 @@
},
{
"kind": "ui-call",
- "line": 886,
+ "line": 1005,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Open System Access",
"surface": "android",
@@ -6699,7 +6851,7 @@
},
{
"kind": "ui-call",
- "line": 895,
+ "line": 1014,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Forwarding Mode",
"surface": "android",
@@ -6707,7 +6859,7 @@
},
{
"kind": "ui-call",
- "line": 897,
+ "line": 1016,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Blocklist",
"surface": "android",
@@ -6715,7 +6867,7 @@
},
{
"kind": "ui-call",
- "line": 901,
+ "line": 1020,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allowlist",
"surface": "android",
@@ -6723,7 +6875,7 @@
},
{
"kind": "ui-call",
- "line": 950,
+ "line": 1069,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "App Filter",
"surface": "android",
@@ -6731,7 +6883,7 @@
},
{
"kind": "ui-call",
- "line": 957,
+ "line": 1076,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Close App Picker",
"surface": "android",
@@ -6739,7 +6891,7 @@
},
{
"kind": "ui-call",
- "line": 957,
+ "line": 1076,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Open App Picker",
"surface": "android",
@@ -6747,7 +6899,7 @@
},
{
"kind": "ui-call",
- "line": 962,
+ "line": 1081,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Search apps",
"surface": "android",
@@ -6755,7 +6907,7 @@
},
{
"kind": "ui-call",
- "line": 965,
+ "line": 1084,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Show System Apps",
"surface": "android",
@@ -6763,7 +6915,7 @@
},
{
"kind": "ui-call",
- "line": 966,
+ "line": 1085,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Include Android and background packages.",
"surface": "android",
@@ -6771,7 +6923,7 @@
},
{
"kind": "ui-call",
- "line": 973,
+ "line": 1092,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No matching apps.",
"surface": "android",
@@ -6779,7 +6931,7 @@
},
{
"kind": "ui-call",
- "line": 984,
+ "line": 1103,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Showing ${visibleApps.size} of ${apps.size}. Refine search for more.",
"surface": "android",
@@ -6787,7 +6939,7 @@
},
{
"kind": "ui-call",
- "line": 1231,
+ "line": 1350,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Choose what this phone can share.",
"surface": "android",
@@ -6795,7 +6947,7 @@
},
{
"kind": "ui-call",
- "line": 1231,
+ "line": 1350,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Phone Capabilities",
"surface": "android",
@@ -6803,7 +6955,7 @@
},
{
"kind": "ui-call",
- "line": 1235,
+ "line": 1354,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allow camera tools when requested.",
"surface": "android",
@@ -6811,7 +6963,7 @@
},
{
"kind": "ui-call",
- "line": 1235,
+ "line": 1354,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Camera",
"surface": "android",
@@ -6819,7 +6971,7 @@
},
{
"kind": "ui-call",
- "line": 1236,
+ "line": 1355,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Precise Location",
"surface": "android",
@@ -6827,7 +6979,7 @@
},
{
"kind": "ui-call",
- "line": 1236,
+ "line": 1355,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Share precise location while location is enabled.",
"surface": "android",
@@ -6835,7 +6987,7 @@
},
{
"kind": "ui-call",
- "line": 1239,
+ "line": 1358,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Photos",
"surface": "android",
@@ -6843,7 +6995,7 @@
},
{
"kind": "ui-call",
- "line": 1240,
+ "line": 1359,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allow photo library access.",
"surface": "android",
@@ -6851,7 +7003,7 @@
},
{
"kind": "ui-call",
- "line": 1240,
+ "line": 1359,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Selected or full photo access granted.",
"surface": "android",
@@ -6859,7 +7011,7 @@
},
{
"kind": "ui-call",
- "line": 1249,
+ "line": 1368,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Installed Apps",
"surface": "android",
@@ -6867,7 +7019,7 @@
},
{
"kind": "ui-call",
- "line": 1250,
+ "line": 1369,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "App list stays on this phone.",
"surface": "android",
@@ -6875,7 +7027,7 @@
},
{
"kind": "ui-call",
- "line": 1250,
+ "line": 1369,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw can list launcher-visible apps.",
"surface": "android",
@@ -6883,7 +7035,7 @@
},
{
"kind": "ui-call",
- "line": 1255,
+ "line": 1374,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Keep Awake",
"surface": "android",
@@ -6891,7 +7043,7 @@
},
{
"kind": "ui-call",
- "line": 1255,
+ "line": 1374,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Keep the node available during active work.",
"surface": "android",
@@ -6899,7 +7051,7 @@
},
{
"kind": "ui-call",
- "line": 1256,
+ "line": 1375,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Canvas Status",
"surface": "android",
@@ -6907,7 +7059,7 @@
},
{
"kind": "ui-call",
- "line": 1256,
+ "line": 1375,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Show screen-sharing debug state.",
"surface": "android",
@@ -6915,7 +7067,7 @@
},
{
"kind": "ui-call",
- "line": 1261,
+ "line": 1380,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Location",
"surface": "android",
@@ -6923,7 +7075,7 @@
},
{
"kind": "ui-call",
- "line": 1269,
+ "line": 1388,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Always allows requested location checks while OpenClaw is in the background; Android shows this in the persistent node notification.",
"surface": "android",
@@ -6931,7 +7083,7 @@
},
{
"kind": "ui-call",
- "line": 1304,
+ "line": 1423,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allow background location?",
"surface": "android",
@@ -6939,7 +7091,7 @@
},
{
"kind": "ui-call",
- "line": 1307,
+ "line": 1426,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw only checks location when your paired Gateway requests it. On the next Android screen, choose $backgroundPermissionLabel to allow checks while the app is in the background.",
"surface": "android",
@@ -6947,7 +7099,7 @@
},
{
"kind": "ui-call",
- "line": 1321,
+ "line": 1440,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Open Settings",
"surface": "android",
@@ -6955,7 +7107,7 @@
},
{
"kind": "ui-call",
- "line": 1340,
+ "line": 1459,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Share installed app information?",
"surface": "android",
@@ -6963,7 +7115,7 @@
},
{
"kind": "ui-call",
- "line": 1344,
+ "line": 1463,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw collects and sends the names, package IDs, and status of apps visible on this phone when your paired OpenClaw Gateway asks for them. This lets your assistant answer questions and take actions using installed apps.",
"surface": "android",
@@ -6971,7 +7123,7 @@
},
{
"kind": "ui-call",
- "line": 1347,
+ "line": 1466,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Your phone sends this information to your Gateway, not to a server run by OpenClaw. Your Gateway may include it in requests to the AI provider you chose.",
"surface": "android",
@@ -6979,7 +7131,7 @@
},
{
"kind": "ui-call",
- "line": 1353,
+ "line": 1472,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Agree and Enable",
"surface": "android",
@@ -6987,7 +7139,7 @@
},
{
"kind": "ui-call",
- "line": 1358,
+ "line": 1477,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Not Now",
"surface": "android",
@@ -6995,7 +7147,7 @@
},
{
"kind": "ui-call",
- "line": 1411,
+ "line": 1530,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Replace gateway setup?",
"surface": "android",
@@ -7003,7 +7155,7 @@
},
{
"kind": "ui-call",
- "line": 1426,
+ "line": 1545,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Replace setup",
"surface": "android",
@@ -7011,7 +7163,7 @@
},
{
"kind": "ui-call",
- "line": 1440,
+ "line": 1559,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "this gateway",
"surface": "android",
@@ -7019,7 +7171,7 @@
},
{
"kind": "ui-call",
- "line": 1443,
+ "line": 1562,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Forget gateway?",
"surface": "android",
@@ -7027,7 +7179,7 @@
},
{
"kind": "ui-call",
- "line": 1446,
+ "line": 1565,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Remove $gatewayName and its saved credentials from this phone?",
"surface": "android",
@@ -7035,7 +7187,7 @@
},
{
"kind": "ui-call",
- "line": 1463,
+ "line": 1582,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Cancel",
"surface": "android",
@@ -7043,7 +7195,7 @@
},
{
"kind": "ui-call",
- "line": 1501,
+ "line": 1620,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connection between this phone and OpenClaw.",
"surface": "android",
@@ -7051,7 +7203,7 @@
},
{
"kind": "ui-call",
- "line": 1515,
+ "line": 1634,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connected",
"surface": "android",
@@ -7059,7 +7211,7 @@
},
{
"kind": "ui-call",
- "line": 1515,
+ "line": 1634,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connection",
"surface": "android",
@@ -7067,7 +7219,7 @@
},
{
"kind": "ui-call",
- "line": 1515,
+ "line": 1634,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Offline",
"surface": "android",
@@ -7075,7 +7227,7 @@
},
{
"kind": "ui-call",
- "line": 1516,
+ "line": 1635,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Not paired",
"surface": "android",
@@ -7083,7 +7235,7 @@
},
{
"kind": "ui-call",
- "line": 1516,
+ "line": 1635,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Online",
"surface": "android",
@@ -7091,7 +7243,7 @@
},
{
"kind": "ui-call",
- "line": 1518,
+ "line": 1637,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Access",
"surface": "android",
@@ -7099,7 +7251,7 @@
},
{
"kind": "ui-call",
- "line": 1525,
+ "line": 1644,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Address",
"surface": "android",
@@ -7107,7 +7259,7 @@
},
{
"kind": "ui-call",
- "line": 1530,
+ "line": 1649,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Discovered",
"surface": "android",
@@ -7115,7 +7267,7 @@
},
{
"kind": "ui-call",
- "line": 1531,
+ "line": 1650,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Default Agent",
"surface": "android",
@@ -7123,7 +7275,7 @@
},
{
"kind": "ui-call",
- "line": 1532,
+ "line": 1651,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Agents",
"surface": "android",
@@ -7131,7 +7283,7 @@
},
{
"kind": "ui-call",
- "line": 1533,
+ "line": 1652,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Instance ID",
"surface": "android",
@@ -7139,7 +7291,7 @@
},
{
"kind": "ui-call",
- "line": 1539,
+ "line": 1658,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Scan QR to Pair",
"surface": "android",
@@ -7147,7 +7299,7 @@
},
{
"kind": "ui-call",
- "line": 1549,
+ "line": 1668,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Limited Gateway access",
"surface": "android",
@@ -7155,7 +7307,7 @@
},
{
"kind": "ui-call",
- "line": 1562,
+ "line": 1681,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Reconnect",
"surface": "android",
@@ -7163,7 +7315,7 @@
},
{
"kind": "ui-call",
- "line": 1563,
+ "line": 1682,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Disconnect",
"surface": "android",
@@ -7171,7 +7323,7 @@
},
{
"kind": "ui-call",
- "line": 1566,
+ "line": 1685,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Diagnose",
"surface": "android",
@@ -7179,7 +7331,7 @@
},
{
"kind": "ui-call",
- "line": 1579,
+ "line": 1698,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Add Gateway",
"surface": "android",
@@ -7187,7 +7339,7 @@
},
{
"kind": "ui-call",
- "line": 1581,
+ "line": 1700,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Scan or paste a setup code to add another gateway.",
"surface": "android",
@@ -7195,7 +7347,7 @@
},
{
"kind": "ui-call",
- "line": 1587,
+ "line": 1706,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Scan QR",
"surface": "android",
@@ -7203,7 +7355,7 @@
},
{
"kind": "ui-call",
- "line": 1588,
+ "line": 1707,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Setup code",
"surface": "android",
@@ -7211,7 +7363,7 @@
},
{
"kind": "ui-call",
- "line": 1591,
+ "line": 1710,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Where do I get a setup code?",
"surface": "android",
@@ -7219,7 +7371,7 @@
},
{
"kind": "ui-call",
- "line": 1595,
+ "line": 1714,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Android can scan or paste an existing setup code, but this gateway does not expose setup-code generation to the app yet. Generate the QR/code on the gateway host with openclaw qr, then scan it here or paste the setup code below.",
"surface": "android",
@@ -7227,7 +7379,7 @@
},
{
"kind": "ui-call",
- "line": 1602,
+ "line": 1721,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No gateways found yet. Use manual setup if discovery is blocked.",
"surface": "android",
@@ -7235,7 +7387,7 @@
},
{
"kind": "ui-call",
- "line": 1615,
+ "line": 1734,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connect",
"surface": "android",
@@ -7243,7 +7395,7 @@
},
{
"kind": "ui-call",
- "line": 1626,
+ "line": 1745,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Gateways",
"surface": "android",
@@ -7251,7 +7403,7 @@
},
{
"kind": "ui-call",
- "line": 1628,
+ "line": 1747,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No paired gateways.",
"surface": "android",
@@ -7259,7 +7411,7 @@
},
{
"kind": "ui-call",
- "line": 1648,
+ "line": 1767,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Forget",
"surface": "android",
@@ -7267,7 +7419,7 @@
},
{
"kind": "ui-call",
- "line": 1664,
+ "line": 1783,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Manual Gateway",
"surface": "android",
@@ -7275,7 +7427,7 @@
},
{
"kind": "ui-call",
- "line": 1666,
+ "line": 1785,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Host",
"surface": "android",
@@ -7283,7 +7435,7 @@
},
{
"kind": "ui-call",
- "line": 1667,
+ "line": 1786,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Port",
"surface": "android",
@@ -7291,7 +7443,7 @@
},
{
"kind": "ui-call",
- "line": 1669,
+ "line": 1788,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connection security",
"surface": "android",
@@ -7299,7 +7451,7 @@
},
{
"kind": "ui-call",
- "line": 1673,
+ "line": 1792,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Unencrypted",
"surface": "android",
@@ -7307,7 +7459,7 @@
},
{
"kind": "ui-call",
- "line": 1677,
+ "line": 1796,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Secure (TLS)",
"surface": "android",
@@ -7315,7 +7467,7 @@
},
{
"kind": "ui-call",
- "line": 1690,
+ "line": 1809,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Token",
"surface": "android",
@@ -7323,7 +7475,7 @@
},
{
"kind": "ui-call",
- "line": 1691,
+ "line": 1810,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Bootstrap",
"surface": "android",
@@ -7331,7 +7483,7 @@
},
{
"kind": "ui-call",
- "line": 1693,
+ "line": 1812,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Password",
"surface": "android",
@@ -7339,7 +7491,7 @@
},
{
"kind": "ui-call",
- "line": 1698,
+ "line": 1817,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Save & Connect",
"surface": "android",
@@ -7347,7 +7499,7 @@
},
{
"kind": "ui-call",
- "line": 1715,
+ "line": 1834,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Enter a valid setup code or gateway address.",
"surface": "android",
@@ -7355,7 +7507,7 @@
},
{
"kind": "ui-call",
- "line": 1736,
+ "line": 1855,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Not available",
"surface": "android",
@@ -7363,7 +7515,7 @@
},
{
"kind": "ui-call",
- "line": 1737,
+ "line": 1856,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Full",
"surface": "android",
@@ -7371,7 +7523,7 @@
},
{
"kind": "ui-call",
- "line": 1738,
+ "line": 1857,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Limited",
"surface": "android",
@@ -7379,7 +7531,7 @@
},
{
"kind": "ui-call",
- "line": 1742,
+ "line": 1861,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Use a secure wss:// or Tailscale Serve Gateway, generate a full-access setup code in the Control UI or with openclaw qr, then scan or paste it below and reconnect to enable settings and upgrades.",
"surface": "android",
@@ -7387,7 +7539,7 @@
},
{
"kind": "ui-call",
- "line": 1756,
+ "line": 1875,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Appearance",
"surface": "android",
@@ -7395,7 +7547,7 @@
},
{
"kind": "ui-call",
- "line": 1756,
+ "line": 1875,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Theme and translated Android text.",
"surface": "android",
@@ -7403,7 +7555,7 @@
},
{
"kind": "ui-call",
- "line": 1761,
+ "line": 1880,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Language",
"surface": "android",
@@ -7411,7 +7563,7 @@
},
{
"kind": "ui-call",
- "line": 1762,
+ "line": 1881,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Contrast",
"surface": "android",
@@ -7419,7 +7571,7 @@
},
{
"kind": "ui-call",
- "line": 1762,
+ "line": 1881,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "High",
"surface": "android",
@@ -7427,7 +7579,7 @@
},
{
"kind": "ui-call",
- "line": 1763,
+ "line": 1882,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Readable",
"surface": "android",
@@ -7435,7 +7587,7 @@
},
{
"kind": "ui-call",
- "line": 1763,
+ "line": 1882,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Typography",
"surface": "android",
@@ -7443,7 +7595,7 @@
},
{
"kind": "ui-call",
- "line": 1768,
+ "line": 1887,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Theme",
"surface": "android",
@@ -7451,7 +7603,7 @@
},
{
"kind": "ui-call",
- "line": 1778,
+ "line": 1897,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "App language",
"surface": "android",
@@ -7459,7 +7611,7 @@
},
{
"kind": "ui-call",
- "line": 1812,
+ "line": 1931,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Selected",
"surface": "android",
@@ -7467,7 +7619,7 @@
},
{
"kind": "ui-call",
- "line": 1824,
+ "line": 1943,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "System",
"surface": "android",
@@ -7475,7 +7627,7 @@
},
{
"kind": "ui-call",
- "line": 1852,
+ "line": 1971,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "While Using",
"surface": "android",
@@ -7483,7 +7635,7 @@
},
{
"kind": "ui-call",
- "line": 1853,
+ "line": 1972,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Always",
"surface": "android",
@@ -7491,7 +7643,7 @@
},
{
"kind": "ui-call",
- "line": 1865,
+ "line": 1984,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Connecting...",
"surface": "android",
@@ -7499,7 +7651,7 @@
},
{
"kind": "ui-call",
- "line": 1866,
+ "line": 1985,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Pairing needed",
"surface": "android",
@@ -7507,7 +7659,7 @@
},
{
"kind": "ui-call",
- "line": 1867,
+ "line": 1986,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Authentication needed",
"surface": "android",
@@ -7515,7 +7667,7 @@
},
{
"kind": "ui-call",
- "line": 1868,
+ "line": 1987,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "TLS timed out",
"surface": "android",
@@ -7523,7 +7675,7 @@
},
{
"kind": "ui-call",
- "line": 1869,
+ "line": 1988,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No TLS endpoint",
"surface": "android",
@@ -7531,7 +7683,7 @@
},
{
"kind": "ui-call",
- "line": 1870,
+ "line": 1989,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Certificate review needed",
"surface": "android",
@@ -7539,7 +7691,7 @@
},
{
"kind": "ui-call",
- "line": 1871,
+ "line": 1990,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Cannot reach gateway",
"surface": "android",
@@ -7547,7 +7699,7 @@
},
{
"kind": "ui-call",
- "line": 1892,
+ "line": 2011,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "About",
"surface": "android",
@@ -7555,7 +7707,7 @@
},
{
"kind": "ui-call",
- "line": 1892,
+ "line": 2011,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw for Android.",
"surface": "android",
@@ -7563,7 +7715,7 @@
},
{
"kind": "ui-call",
- "line": 1904,
+ "line": 2023,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Channel",
"surface": "android",
@@ -7571,7 +7723,7 @@
},
{
"kind": "ui-call",
- "line": 1905,
+ "line": 2024,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Not connected",
"surface": "android",
@@ -7579,7 +7731,7 @@
},
{
"kind": "ui-call",
- "line": 1910,
+ "line": 2029,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Home Gateway",
"surface": "android",
@@ -7587,7 +7739,7 @@
},
{
"kind": "ui-call",
- "line": 1912,
+ "line": 2031,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Runtime",
"surface": "android",
@@ -7595,7 +7747,7 @@
},
{
"kind": "ui-call",
- "line": 1912,
+ "line": 2031,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Waiting",
"surface": "android",
@@ -7603,7 +7755,7 @@
},
{
"kind": "ui-call",
- "line": 1915,
+ "line": 2034,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Update",
"surface": "android",
@@ -7611,7 +7763,7 @@
},
{
"kind": "ui-call",
- "line": 1916,
+ "line": 2035,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Up to date",
"surface": "android",
@@ -7619,7 +7771,7 @@
},
{
"kind": "ui-call",
- "line": 1916,
+ "line": 2035,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "v$it available",
"surface": "android",
@@ -7627,7 +7779,7 @@
},
{
"kind": "ui-call",
- "line": 1926,
+ "line": 2045,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "© 2026 OpenClaw Foundation — MIT License.",
"surface": "android",
@@ -7635,7 +7787,7 @@
},
{
"kind": "ui-call",
- "line": 1943,
+ "line": 2062,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw logo",
"surface": "android",
@@ -7643,7 +7795,7 @@
},
{
"kind": "ui-call",
- "line": 1945,
+ "line": 2064,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw",
"surface": "android",
@@ -7651,7 +7803,7 @@
},
{
"kind": "ui-call",
- "line": 1946,
+ "line": 2065,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Personal AI on your devices",
"surface": "android",
@@ -7659,7 +7811,7 @@
},
{
"kind": "ui-call",
- "line": 2005,
+ "line": 2124,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Licenses",
"surface": "android",
@@ -7667,7 +7819,7 @@
},
{
"kind": "ui-call",
- "line": 2006,
+ "line": 2125,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw appreciates its partners in the open-source community.",
"surface": "android",
@@ -7675,7 +7827,7 @@
},
{
"kind": "ui-call",
- "line": 2015,
+ "line": 2134,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No license notices are packaged in this build.",
"surface": "android",
@@ -7683,7 +7835,7 @@
},
{
"kind": "ui-call",
- "line": 2041,
+ "line": 2160,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Open ${license.title}",
"surface": "android",
@@ -7691,7 +7843,7 @@
},
{
"kind": "ui-call",
- "line": 2052,
+ "line": 2171,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Third-party",
"surface": "android",
@@ -7699,7 +7851,7 @@
},
{
"kind": "ui-call",
- "line": 2053,
+ "line": 2172,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Unknown",
"surface": "android",
@@ -7707,7 +7859,7 @@
},
{
"kind": "ui-call",
- "line": 2059,
+ "line": 2178,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Website",
"surface": "android",
@@ -7715,7 +7867,7 @@
},
{
"kind": "ui-call",
- "line": 2060,
+ "line": 2179,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Docs",
"surface": "android",
@@ -7723,7 +7875,7 @@
},
{
"kind": "ui-call",
- "line": 2064,
+ "line": 2183,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allow all the time",
"surface": "android",
@@ -7731,7 +7883,7 @@
},
{
"kind": "ui-call",
- "line": 2067,
+ "line": 2186,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Replacing the setup code clears this phone's saved setup credentials and device tokens before reconnecting. This phone may need node capability approval again; continue only when you mean to pair with a fresh gateway setup code.",
"surface": "android",
@@ -7739,7 +7891,7 @@
},
{
"kind": "ui-call",
- "line": 2086,
+ "line": 2205,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Check",
"surface": "android",
@@ -7747,7 +7899,7 @@
},
{
"kind": "ui-call",
- "line": 2093,
+ "line": 2212,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "OpenClaw turns this phone into a clean mobile command surface for sessions, voice, providers, and Gateway.",
"surface": "android",
@@ -7755,7 +7907,7 @@
},
{
"kind": "ui-call",
- "line": 2095,
+ "line": 2214,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "A Gateway update is available. Run the update from the Web UI or CLI when you are ready.",
"surface": "android",
@@ -7763,7 +7915,7 @@
},
{
"kind": "ui-call",
- "line": 2120,
+ "line": 2239,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Back",
"surface": "android",
@@ -7771,7 +7923,7 @@
},
{
"kind": "ui-call",
- "line": 2193,
+ "line": 2313,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Command approval",
"surface": "android",
@@ -7779,7 +7931,7 @@
},
{
"kind": "ui-call",
- "line": 2198,
+ "line": 2318,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Sending",
"surface": "android",
@@ -7787,7 +7939,7 @@
},
{
"kind": "ui-call",
- "line": 2258,
+ "line": 2378,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allow Once",
"surface": "android",
@@ -7795,7 +7947,7 @@
},
{
"kind": "ui-call",
- "line": 2259,
+ "line": 2379,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Allow Always",
"surface": "android",
@@ -7803,7 +7955,7 @@
},
{
"kind": "ui-call",
- "line": 2260,
+ "line": 2380,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Deny",
"surface": "android",
@@ -7811,7 +7963,7 @@
},
{
"kind": "ui-call",
- "line": 2281,
+ "line": 2401,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Approval ${notice.approvalId}",
"surface": "android",
@@ -7819,7 +7971,7 @@
},
{
"kind": "ui-call",
- "line": 2288,
+ "line": 2408,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Dismiss approval notice",
"surface": "android",
@@ -7827,7 +7979,7 @@
},
{
"kind": "ui-call",
- "line": 2307,
+ "line": 2427,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Review",
"surface": "android",
@@ -7835,7 +7987,7 @@
},
{
"kind": "ui-call",
- "line": 2347,
+ "line": 2467,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Open automation detail",
"surface": "android",
@@ -7843,7 +7995,7 @@
},
{
"kind": "ui-call",
- "line": 2390,
+ "line": 2510,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Enabled",
"surface": "android",
@@ -7851,7 +8003,7 @@
},
{
"kind": "ui-call",
- "line": 2390,
+ "line": 2510,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Status",
"surface": "android",
@@ -7859,7 +8011,7 @@
},
{
"kind": "ui-call",
- "line": 2391,
+ "line": 2511,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Schedule",
"surface": "android",
@@ -7867,7 +8019,7 @@
},
{
"kind": "ui-call",
- "line": 2392,
+ "line": 2512,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Next Wake",
"surface": "android",
@@ -7875,7 +8027,7 @@
},
{
"kind": "ui-call",
- "line": 2393,
+ "line": 2513,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Last Run",
"surface": "android",
@@ -7883,7 +8035,7 @@
},
{
"kind": "ui-call",
- "line": 2400,
+ "line": 2520,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Description",
"surface": "android",
@@ -7891,7 +8043,7 @@
},
{
"kind": "ui-call",
- "line": 2401,
+ "line": 2521,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Schedule Detail",
"surface": "android",
@@ -7899,7 +8051,7 @@
},
{
"kind": "ui-call",
- "line": 2402,
+ "line": 2522,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Session Target",
"surface": "android",
@@ -7907,7 +8059,7 @@
},
{
"kind": "ui-call",
- "line": 2403,
+ "line": 2523,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Wake Mode",
"surface": "android",
@@ -7915,7 +8067,7 @@
},
{
"kind": "ui-call",
- "line": 2404,
+ "line": 2524,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Delete After Run",
"surface": "android",
@@ -7923,7 +8075,7 @@
},
{
"kind": "ui-call",
- "line": 2404,
+ "line": 2524,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No",
"surface": "android",
@@ -7931,7 +8083,7 @@
},
{
"kind": "ui-call",
- "line": 2404,
+ "line": 2524,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Yes",
"surface": "android",
@@ -7939,7 +8091,7 @@
},
{
"kind": "ui-call",
- "line": 2405,
+ "line": 2525,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Payload",
"surface": "android",
@@ -7947,7 +8099,7 @@
},
{
"kind": "ui-call",
- "line": 2406,
+ "line": 2526,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Delivery",
"surface": "android",
@@ -7955,7 +8107,7 @@
},
{
"kind": "ui-call",
- "line": 2407,
+ "line": 2527,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Failure Alert",
"surface": "android",
@@ -7963,7 +8115,7 @@
},
{
"kind": "ui-call",
- "line": 2408,
+ "line": 2528,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Created",
"surface": "android",
@@ -7971,7 +8123,7 @@
},
{
"kind": "ui-call",
- "line": 2409,
+ "line": 2529,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Updated",
"surface": "android",
@@ -7979,7 +8131,7 @@
},
{
"kind": "ui-call",
- "line": 2410,
+ "line": 2530,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Running Since",
"surface": "android",
@@ -7987,7 +8139,7 @@
},
{
"kind": "ui-call",
- "line": 2411,
+ "line": 2531,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Last Status",
"surface": "android",
@@ -7995,7 +8147,7 @@
},
{
"kind": "ui-call",
- "line": 2413,
+ "line": 2533,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Last Duration",
"surface": "android",
@@ -8003,7 +8155,7 @@
},
{
"kind": "ui-call",
- "line": 2414,
+ "line": 2534,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${durationMs}ms",
"surface": "android",
@@ -8011,7 +8163,7 @@
},
{
"kind": "ui-call",
- "line": 2416,
+ "line": 2536,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Consecutive Errors",
"surface": "android",
@@ -8019,7 +8171,7 @@
},
{
"kind": "ui-call",
- "line": 2417,
+ "line": 2537,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Consecutive Skips",
"surface": "android",
@@ -8027,7 +8179,7 @@
},
{
"kind": "ui-call",
- "line": 2418,
+ "line": 2538,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Delivery Status",
"surface": "android",
@@ -8035,7 +8187,7 @@
},
{
"kind": "ui-call",
- "line": 2425,
+ "line": 2545,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Last Error",
"surface": "android",
@@ -8043,7 +8195,7 @@
},
{
"kind": "ui-call",
- "line": 2428,
+ "line": 2548,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Delivery Error",
"surface": "android",
@@ -8051,7 +8203,7 @@
},
{
"kind": "ui-call",
- "line": 2444,
+ "line": 2564,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Copy ${row.title}",
"surface": "android",
@@ -8059,7 +8211,7 @@
},
{
"kind": "ui-call",
- "line": 2469,
+ "line": 2589,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Tap to copy",
"surface": "android",
@@ -8067,7 +8219,7 @@
},
{
"kind": "ui-call",
- "line": 2484,
+ "line": 2604,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "$title copied",
"surface": "android",
@@ -8075,7 +8227,7 @@
},
{
"kind": "ui-call",
- "line": 2522,
+ "line": 2642,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Default assistant",
"surface": "android",
@@ -8083,7 +8235,7 @@
},
{
"kind": "ui-call",
- "line": 2528,
+ "line": 2648,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Default",
"surface": "android",
@@ -8091,7 +8243,7 @@
},
{
"kind": "conditional-branch",
- "line": 2536,
+ "line": 2656,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${endpoint.host}:${endpoint.port}",
"surface": "android",
@@ -8099,7 +8251,7 @@
},
{
"kind": "ui-call",
- "line": 2582,
+ "line": 2702,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Action Request",
"surface": "android",
@@ -8107,7 +8259,7 @@
},
{
"kind": "ui-call",
- "line": 2590,
+ "line": 2710,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Needs attention",
"surface": "android",
@@ -8115,7 +8267,7 @@
},
{
"kind": "ui-call",
- "line": 2593,
+ "line": 2713,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Waiting ${minutes}m",
"surface": "android",
@@ -8123,7 +8275,7 @@
},
{
"kind": "ui-call",
- "line": 2593,
+ "line": 2713,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Waiting for review",
"surface": "android",
@@ -8131,7 +8283,7 @@
},
{
"kind": "ui-call",
- "line": 2604,
+ "line": 2724,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Node ${nodeId}",
"surface": "android",
@@ -8139,7 +8291,7 @@
},
{
"kind": "ui-call",
- "line": 2606,
+ "line": 2726,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Node",
"surface": "android",
@@ -8147,7 +8299,7 @@
},
{
"kind": "ui-call",
- "line": 2609,
+ "line": 2729,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Gateway",
"surface": "android",
@@ -8155,7 +8307,7 @@
},
{
"kind": "ui-call",
- "line": 2614,
+ "line": 2734,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Agent ${agentId}",
"surface": "android",
@@ -8163,7 +8315,7 @@
},
{
"kind": "ui-call",
- "line": 2619,
+ "line": 2739,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Waiting ${duration}",
"surface": "android",
@@ -8171,7 +8323,7 @@
},
{
"kind": "ui-call",
- "line": 2624,
+ "line": 2744,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Expires ${duration}",
"surface": "android",
@@ -8179,7 +8331,7 @@
},
{
"kind": "ui-call",
- "line": 2634,
+ "line": 2754,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "soon",
"surface": "android",
@@ -8187,7 +8339,7 @@
},
{
"kind": "ui-call",
- "line": 2642,
+ "line": 2762,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Main",
"surface": "android",
@@ -8195,7 +8347,7 @@
},
{
"kind": "ui-call",
- "line": 2643,
+ "line": 2763,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Isolated",
"surface": "android",
@@ -8203,7 +8355,7 @@
},
{
"kind": "ui-call",
- "line": 2644,
+ "line": 2764,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Current",
"surface": "android",
@@ -8211,7 +8363,7 @@
},
{
"kind": "ui-call",
- "line": 2650,
+ "line": 2770,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${job.scheduleLabel} · ${formatCronWake(job.nextRunAtMs)} · ${job.promptPreview}",
"surface": "android",
@@ -8219,7 +8371,7 @@
},
{
"kind": "ui-call",
- "line": 2666,
+ "line": 2786,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "All",
"surface": "android",
@@ -8227,7 +8379,7 @@
},
{
"kind": "ui-call",
- "line": 2667,
+ "line": 2787,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Active",
"surface": "android",
@@ -8235,7 +8387,7 @@
},
{
"kind": "ui-call",
- "line": 2668,
+ "line": 2788,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Paused",
"surface": "android",
@@ -8243,7 +8395,7 @@
},
{
"kind": "ui-call",
- "line": 2701,
+ "line": 2821,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${remaining}% left ${label}",
"surface": "android",
@@ -8251,7 +8403,7 @@
},
{
"kind": "ui-call",
- "line": 2704,
+ "line": 2824,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No limits reported",
"surface": "android",
@@ -8259,7 +8411,7 @@
},
{
"kind": "ui-call",
- "line": 2715,
+ "line": 2835,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Never",
"surface": "android",
@@ -8267,7 +8419,7 @@
},
{
"kind": "ui-call",
- "line": 2720,
+ "line": 2840,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Now",
"surface": "android",
@@ -8275,7 +8427,7 @@
},
{
"kind": "ui-call",
- "line": 2742,
+ "line": 2862,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Off",
"surface": "android",
@@ -8283,7 +8435,7 @@
},
{
"kind": "ui-call",
- "line": 2744,
+ "line": 2864,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Issue",
"surface": "android",
@@ -8291,7 +8443,7 @@
},
{
"kind": "ui-call",
- "line": 2746,
+ "line": 2866,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Skipped",
"surface": "android",
@@ -8299,7 +8451,7 @@
},
{
"kind": "ui-call",
- "line": 2747,
+ "line": 2867,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Ready",
"surface": "android",
@@ -8307,7 +8459,7 @@
},
{
"kind": "ui-call",
- "line": 2763,
+ "line": 2883,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "System Event Text",
"surface": "android",
@@ -8315,7 +8467,7 @@
},
{
"kind": "ui-call",
- "line": 2764,
+ "line": 2884,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Agent Prompt",
"surface": "android",
@@ -8323,7 +8475,7 @@
},
{
"kind": "ui-call",
- "line": 2765,
+ "line": 2885,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Command",
"surface": "android",
@@ -8331,7 +8483,7 @@
},
{
"kind": "ui-call",
- "line": 2766,
+ "line": 2886,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Payload Text",
"surface": "android",
@@ -8339,7 +8491,7 @@
},
{
"kind": "ui-call",
- "line": 2796,
+ "line": 2916,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No apps selected. Nothing forwards until you add apps.",
"surface": "android",
@@ -8347,7 +8499,7 @@
},
{
"kind": "ui-call",
- "line": 2798,
+ "line": 2918,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "$selectedCount app allowed to forward.",
"surface": "android",
@@ -8355,7 +8507,7 @@
},
{
"kind": "ui-call",
- "line": 2800,
+ "line": 2920,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "$selectedCount apps allowed to forward.",
"surface": "android",
@@ -8363,7 +8515,7 @@
},
{
"kind": "ui-call",
- "line": 2804,
+ "line": 2924,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "No apps blocked. Apps can forward unless you add blocks.",
"surface": "android",
@@ -8371,7 +8523,7 @@
},
{
"kind": "ui-call",
- "line": 2806,
+ "line": 2926,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "$selectedCount app blocked from forwarding.",
"surface": "android",
@@ -8379,7 +8531,7 @@
},
{
"kind": "ui-call",
- "line": 2808,
+ "line": 2928,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "$selectedCount apps blocked from forwarding.",
"surface": "android",
@@ -8387,7 +8539,7 @@
},
{
"kind": "ui-call",
- "line": 2834,
+ "line": 2954,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Due",
"surface": "android",
@@ -8395,7 +8547,7 @@
},
{
"kind": "ui-call",
- "line": 2839,
+ "line": 2959,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${days}d",
"surface": "android",
@@ -8403,7 +8555,7 @@
},
{
"kind": "ui-call",
- "line": 2840,
+ "line": 2960,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${hours}h",
"surface": "android",
@@ -8411,7 +8563,7 @@
},
{
"kind": "ui-call",
- "line": 2841,
+ "line": 2961,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "${minutes}m",
"surface": "android",
@@ -8419,7 +8571,7 @@
},
{
"kind": "ui-call",
- "line": 2842,
+ "line": 2962,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "Soon",
"surface": "android",
@@ -8427,7 +8579,7 @@
},
{
"kind": "ui-call",
- "line": 2847,
+ "line": 2967,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt",
"source": "None",
"surface": "android",
@@ -12609,6 +12761,86 @@
"surface": "android",
"id": "native.android.ea5d9621ef0f0482"
},
+ {
+ "kind": "ui-call",
+ "line": 374,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Off",
+ "surface": "android",
+ "id": "native.android.11d70a2e3419e346"
+ },
+ {
+ "kind": "ui-call",
+ "line": 375,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "On-device speech recognition unavailable",
+ "surface": "android",
+ "id": "native.android.b21cacf24f03d772"
+ },
+ {
+ "kind": "ui-call",
+ "line": 377,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Paused",
+ "surface": "android",
+ "id": "native.android.c379aa335b932db2"
+ },
+ {
+ "kind": "ui-call",
+ "line": 400,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Listening",
+ "surface": "android",
+ "id": "native.android.d0c22c4961346923"
+ },
+ {
+ "kind": "ui-call",
+ "line": 419,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Microphone permission required",
+ "surface": "android",
+ "id": "native.android.894062d81447a410"
+ },
+ {
+ "kind": "ui-call",
+ "line": 421,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Device language not supported",
+ "surface": "android",
+ "id": "native.android.d404b3d5f084f5d2"
+ },
+ {
+ "kind": "ui-call",
+ "line": 423,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "On-device language model unavailable",
+ "surface": "android",
+ "id": "native.android.d559a0a3f32701b8"
+ },
+ {
+ "kind": "ui-call",
+ "line": 443,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Triggered",
+ "surface": "android",
+ "id": "native.android.269915b38b1486c0"
+ },
+ {
+ "kind": "ui-call",
+ "line": 456,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Gateway unavailable",
+ "surface": "android",
+ "id": "native.android.9a0753f5ae9394ab"
+ },
+ {
+ "kind": "ui-call",
+ "line": 471,
+ "path": "apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt",
+ "source": "Starting…",
+ "surface": "android",
+ "id": "native.android.eef69ee3eb23cc1b"
+ },
{
"kind": "resource-item",
"line": 3,
diff --git a/apps/.i18n/native/ar.json b/apps/.i18n/native/ar.json
index 8532692f6503..04ee893c66c2 100644
--- a/apps/.i18n/native/ar.json
+++ b/apps/.i18n/native/ar.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "لا يوجد تحديث للوحة الرسم بعد. اضغط لإعادة المحاولة."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "اتصل بـ Gateway لحفظ كلمات التنبيه"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "تم حفظ كلمات التنبيه"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "تعذر حفظ كلمات التنبيه"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "حفظ الملف الشخصي"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "اضبط الصوت والنقل والتشغيل."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "اضبط كلمات التنبيه والتحدث والتشغيل."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "الصوت"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "التنبيه الصوتي"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "الاستماع إلى كلمات التنبيه"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "يعمل على الجهاز أثناء ظهور OpenClaw."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "ميزة التعرّف على الكلام على الجهاز غير متاحة."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "مستمع التنبيه"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "آخر أمر: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "يتوقف مؤقتًا أثناء الأنشطة الصوتية الأخرى."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "كلمات التنبيه"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "أضف كلمة تنبيه أو عبارة واحدة في كل حقل. ثم قل إحداها قبل أمرك."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "كلمة أو عبارة التنبيه"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "إزالة عبارة التنبيه"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "إضافة عبارة تنبيه"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "حفظ كلمات التنبيه"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "جارٍ الحفظ…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "اتصل بـ Gateway لحفظ كلمات التنبيه"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "يمكن لـ OpenClaw تلقي التنبيهات المحددة."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart إلى $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "ساعات الهدوء"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart إلى $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "خطأ في التعرّف على الكلام ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "إيقاف"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "التعرّف على الكلام على الجهاز غير متاح"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "متوقف مؤقتًا"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "جارٍ الاستماع"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "يلزم منح إذن الميكروفون"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "لغة الجهاز غير مدعومة"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "نموذج اللغة على الجهاز غير متاح"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "تم التشغيل"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway غير متاح"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "جارٍ البدء…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/de.json b/apps/.i18n/native/de.json
index a34d76cbe139..86310a401ab6 100644
--- a/apps/.i18n/native/de.json
+++ b/apps/.i18n/native/de.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Noch kein Canvas-Update. Tippen Sie, um es erneut zu versuchen."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Mit einem Gateway verbinden, um Aktivierungswörter zu speichern"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Aktivierungswörter gespeichert"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Aktivierungswörter konnten nicht gespeichert werden"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Profil speichern"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Sprache, Transport und Wiedergabe konfigurieren."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Aktivierungswörter, Spracheingabe und Wiedergabe konfigurieren."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Sprache"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Sprachaktivierung"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Auf Aktivierungswörter warten"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Wird auf dem Gerät ausgeführt, solange OpenClaw sichtbar ist."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Die Spracherkennung auf dem Gerät ist nicht verfügbar."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Aktivierungswort-Erkennung"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Letzter Befehl: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Wird bei anderen Sprachaktivitäten pausiert."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Aktivierungswörter"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Fügen Sie pro Feld ein Aktivierungswort oder eine Aktivierungsphrase hinzu. Sagen Sie anschließend eines davon vor Ihrem Befehl."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Aktivierungswort oder -phrase"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Aktivierungsphrase entfernen"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Aktivierungsphrase hinzufügen"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Aktivierungswörter speichern"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Wird gespeichert…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Mit einem Gateway verbinden, um Aktivierungswörter zu speichern"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw kann ausgewählte Hinweise empfangen."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart bis $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Ruhezeiten"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart bis $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Sprachfehler ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Aus"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Spracherkennung auf dem Gerät nicht verfügbar"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Pausiert"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Hört zu"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Mikrofonberechtigung erforderlich"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Gerätesprache wird nicht unterstützt"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Sprachmodell auf dem Gerät nicht verfügbar"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Ausgelöst"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway nicht verfügbar"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Wird gestartet…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/es.json b/apps/.i18n/native/es.json
index fb0196d2f2d5..73d6f70b69fb 100644
--- a/apps/.i18n/native/es.json
+++ b/apps/.i18n/native/es.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Aún no hay ninguna actualización del lienzo. Toca para volver a intentarlo."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Conéctate a un Gateway para guardar las palabras de activación"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Palabras de activación guardadas"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "No se pudieron guardar las palabras de activación"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Guardar perfil"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Configura la voz, el transporte y la reproducción."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Configura las palabras de activación, la conversación y la reproducción."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Voz"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Activación por voz"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Escuchar palabras de activación"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Se ejecuta en el dispositivo mientras OpenClaw está visible."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "El reconocimiento de voz en el dispositivo no está disponible."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Detector de activación"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Último comando: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Se pausa durante otra actividad de voz."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Palabras de activación"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Añade una palabra o frase de activación por campo. Después, di una antes de tu comando."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Palabra o frase de activación"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Eliminar frase de activación"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Añadir frase de activación"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Guardar palabras de activación"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Guardando…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Conéctate a un Gateway para guardar las palabras de activación"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw puede recibir alertas seleccionadas."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "De $quietStart a $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Horas de silencio"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "De $quietStart a $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Error de voz ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Desactivado"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "El reconocimiento de voz en el dispositivo no está disponible"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "En pausa"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Escuchando"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Se requiere permiso para usar el micrófono"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "El idioma del dispositivo no es compatible"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "El modelo de lenguaje en el dispositivo no está disponible"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Activado"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway no disponible"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Iniciando…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/fa.json b/apps/.i18n/native/fa.json
index 5a74411b9048..738cbac53cb2 100644
--- a/apps/.i18n/native/fa.json
+++ b/apps/.i18n/native/fa.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "هنوز بهروزرسانیای برای بوم وجود ندارد. برای تلاش مجدد ضربه بزنید."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "برای ذخیره واژههای بیدارباش به یک Gateway متصل شوید"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "واژههای بیدارباش ذخیره شدند"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "ذخیره واژههای بیدارباش ممکن نشد"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "ذخیره پروفایل"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "صدا، انتقال و پخش را پیکربندی کنید."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "واژههای بیدارباش، گفتوگو و پخش را پیکربندی کنید."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "صدا"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "بیدارباش صوتی"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "گوشدادن به واژههای بیدارباش"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "تا زمانی که OpenClaw قابل مشاهده است، روی دستگاه اجرا میشود."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "تشخیص گفتار روی دستگاه در دسترس نیست."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "شنونده بیدارباش"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "آخرین فرمان: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "هنگام سایر فعالیتهای صوتی متوقف میشود."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "واژههای بیدارباش"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "در هر فیلد یک واژه یا عبارت بیدارباش اضافه کنید. سپس پیش از فرمان خود یکی از آنها را بگویید."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "واژه یا عبارت بیدارباش"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "حذف عبارت بیدارباش"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "افزودن عبارت بیدارباش"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "ذخیره واژههای بیدارباش"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "در حال ذخیره…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "برای ذخیره واژههای بیدارباش به یک Gateway متصل شوید"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw میتواند هشدارهای انتخابشده را دریافت کند."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart تا $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "ساعات سکوت"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart تا $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "خطای گفتار ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "خاموش"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "تشخیص گفتار روی دستگاه در دسترس نیست"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "متوقف شده"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "در حال گوش دادن"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "مجوز میکروفون لازم است"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "زبان دستگاه پشتیبانی نمیشود"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "مدل زبانی روی دستگاه در دسترس نیست"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "فعال شد"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway در دسترس نیست"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "در حال راهاندازی…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/fr.json b/apps/.i18n/native/fr.json
index d8a28d2ae4bd..17288ec0a0f2 100644
--- a/apps/.i18n/native/fr.json
+++ b/apps/.i18n/native/fr.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Aucune mise à jour du canevas pour le moment. Appuyez pour réessayer."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Connectez-vous à un Gateway pour enregistrer les mots d’activation"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Mots d’activation enregistrés"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Impossible d’enregistrer les mots d’activation"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Enregistrer le profil"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Configurez la voix, le transport et la lecture."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Configurez les mots d’activation, la conversation et la lecture."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Voix"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Activation vocale"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Écouter les mots d’activation"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "S’exécute sur l’appareil tant qu’OpenClaw est visible."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "La reconnaissance vocale sur l’appareil n’est pas disponible."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Détection des mots d’activation"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Dernière commande : $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Se met en pause pendant les autres activités vocales."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Mots d’activation"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Ajoutez un mot ou une phrase d’activation par champ. Prononcez-en ensuite un avant votre commande."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Mot ou phrase d’activation"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Supprimer la phrase d’activation"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Ajouter une phrase d’activation"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Enregistrer les mots d’activation"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Enregistrement…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Connectez-vous à un Gateway pour enregistrer les mots d’activation"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw peut recevoir les alertes sélectionnées."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "De $quietStart à $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Heures de tranquillité"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "De $quietStart à $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Erreur de reconnaissance vocale ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Désactivé"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Reconnaissance vocale sur l’appareil indisponible"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "En pause"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Écoute en cours"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Autorisation d’accès au microphone requise"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Langue de l’appareil non prise en charge"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Modèle linguistique sur l’appareil indisponible"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Déclenché"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway indisponible"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Démarrage…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/hi.json b/apps/.i18n/native/hi.json
index 05355380455a..324aa19b1828 100644
--- a/apps/.i18n/native/hi.json
+++ b/apps/.i18n/native/hi.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "अभी तक कोई कैनवास अपडेट नहीं है। पुनः प्रयास करने के लिए टैप करें।"
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "वेक वर्ड सहेजने के लिए Gateway से कनेक्ट करें"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "वेक वर्ड सहेजे गए"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "वेक वर्ड सहेजे नहीं जा सके"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "प्रोफ़ाइल सेव करें"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "आवाज़, ट्रांसपोर्ट, और प्लेबैक कॉन्फ़िगर करें।"
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "वेक वर्ड, बातचीत और प्लेबैक कॉन्फ़िगर करें।"
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "वॉइस"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "वॉइस वेक"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "वेक वर्ड सुनें"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "OpenClaw दिखाई देने के दौरान डिवाइस पर चलता है।"
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "डिवाइस पर स्पीच रिकग्निशन उपलब्ध नहीं है।"
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "वेक लिसनर"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "पिछला कमांड: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "अन्य वॉइस गतिविधि के दौरान रुक जाता है।"
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "वेक वर्ड"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "हर फ़ील्ड में एक वेक वर्ड या वाक्यांश जोड़ें। फिर अपना कमांड देने से पहले उनमें से एक बोलें।"
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "वेक वर्ड या वाक्यांश"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "वेक वाक्यांश हटाएँ"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "वेक वाक्यांश जोड़ें"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "वेक वर्ड सहेजें"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "सहेजा जा रहा है…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "वेक वर्ड सहेजने के लिए Gateway से कनेक्ट करें"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw चयनित अलर्ट प्राप्त कर सकता है।"
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart से $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "शांत समय"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart से $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "वाक् त्रुटि ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "बंद"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "डिवाइस पर वाक् पहचान उपलब्ध नहीं है"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "रोका गया"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "सुना जा रहा है"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "माइक्रोफ़ोन की अनुमति आवश्यक है"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "डिवाइस की भाषा समर्थित नहीं है"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "डिवाइस पर भाषा मॉडल उपलब्ध नहीं है"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "ट्रिगर किया गया"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway उपलब्ध नहीं है"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "शुरू हो रहा है…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/id.json b/apps/.i18n/native/id.json
index 78ec0d3c008d..d10b77c2989d 100644
--- a/apps/.i18n/native/id.json
+++ b/apps/.i18n/native/id.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Belum ada pembaruan kanvas. Ketuk untuk mencoba lagi."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Hubungkan ke Gateway untuk menyimpan kata aktivasi"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Kata aktivasi disimpan"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Tidak dapat menyimpan kata aktivasi"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Simpan Profil"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Konfigurasikan suara, transport, dan pemutaran."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Konfigurasikan kata aktivasi, percakapan, dan pemutaran."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Suara"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Aktivasi Suara"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Dengarkan kata aktivasi"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Berjalan di perangkat saat OpenClaw terlihat."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Pengenalan ucapan di perangkat tidak tersedia."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Pendengar kata aktivasi"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Perintah terakhir: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Dijeda selama ada aktivitas suara lain."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Kata aktivasi"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Tambahkan satu kata atau frasa aktivasi per kolom. Kemudian ucapkan salah satunya sebelum perintah Anda."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Kata atau frasa aktivasi"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Hapus frasa aktivasi"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Tambahkan frasa aktivasi"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Simpan kata aktivasi"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Menyimpan…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Hubungkan ke Gateway untuk menyimpan kata aktivasi"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw dapat menerima peringatan yang dipilih."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart hingga $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Jam Tenang"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart hingga $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Kesalahan ucapan ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Nonaktif"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Pengenalan ucapan di perangkat tidak tersedia"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Dijeda"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Mendengarkan"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Izin mikrofon diperlukan"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Bahasa perangkat tidak didukung"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Model bahasa di perangkat tidak tersedia"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Terpicu"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway tidak tersedia"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Memulai…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/it.json b/apps/.i18n/native/it.json
index a29aacd7d6bb..064c3d71d6b4 100644
--- a/apps/.i18n/native/it.json
+++ b/apps/.i18n/native/it.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Nessun aggiornamento del canvas. Tocca per riprovare."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Connettiti a un Gateway per salvare le parole di attivazione"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Parole di attivazione salvate"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Impossibile salvare le parole di attivazione"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Salva profilo"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Configura voce, trasporto e riproduzione."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Configura le parole di attivazione, la conversazione e la riproduzione."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Voce"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Attivazione vocale"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Ascolta le parole di attivazione"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Viene eseguito sul dispositivo mentre OpenClaw è visibile."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Il riconoscimento vocale sul dispositivo non è disponibile."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Rilevamento dell'attivazione"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Ultimo comando: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Si mette in pausa durante altre attività vocali."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Parole di attivazione"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Aggiungi una parola o una frase di attivazione per campo. Quindi pronunciane una prima del comando."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Parola o frase di attivazione"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Rimuovi frase di attivazione"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Aggiungi frase di attivazione"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Salva le parole di attivazione"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Salvataggio…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Connettiti a un Gateway per salvare le parole di attivazione"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw può ricevere gli avvisi selezionati."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "Da $quietStart a $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Ore di silenzio"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "Da $quietStart a $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Errore di riconoscimento vocale ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Disattivato"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Riconoscimento vocale sul dispositivo non disponibile"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "In pausa"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "In ascolto"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Autorizzazione per il microfono necessaria"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Lingua del dispositivo non supportata"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Modello linguistico sul dispositivo non disponibile"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Attivato"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway non disponibile"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Avvio…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/ja-JP.json b/apps/.i18n/native/ja-JP.json
index e608bbfcfded..907af5630988 100644
--- a/apps/.i18n/native/ja-JP.json
+++ b/apps/.i18n/native/ja-JP.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "キャンバスはまだ更新されていません。タップして再試行してください。"
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "ウェイクワードを保存するには Gateway に接続してください"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "ウェイクワードを保存しました"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "ウェイクワードを保存できませんでした"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "プロフィールを保存"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "音声、転送、再生を設定します。"
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "ウェイクワード、会話、再生を設定します。"
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "音声"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "音声ウェイク"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "ウェイクワードを聞き取る"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "OpenClaw の表示中にデバイス上で動作します。"
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "デバイス上の音声認識は利用できません。"
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "ウェイクリスナー"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "最後のコマンド: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "他の音声アクティビティ中は一時停止します。"
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "ウェイクワード"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "各フィールドにウェイクワードまたはフレーズを1つずつ追加してください。その後、コマンドの前にそのいずれかを話してください。"
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "ウェイクワードまたはフレーズ"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "ウェイクフレーズを削除"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "ウェイクフレーズを追加"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "ウェイクワードを保存"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "保存中…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "ウェイクワードを保存するには Gateway に接続してください"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw は選択したアラートを受信できます。"
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart~$quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "通知休止時間"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart~$quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "音声認識エラー ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "オフ"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "デバイス上の音声認識は利用できません"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "一時停止中"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "聞き取り中"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "マイクの権限が必要です"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "デバイスの言語はサポートされていません"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "デバイス上の言語モデルは利用できません"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "トリガー済み"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gatewayは利用できません"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "起動中…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/ko.json b/apps/.i18n/native/ko.json
index ce9315f99856..b91255b1d341 100644
--- a/apps/.i18n/native/ko.json
+++ b/apps/.i18n/native/ko.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "아직 캔버스 업데이트가 없습니다. 탭하여 다시 시도하세요."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "호출어를 저장하려면 Gateway에 연결하세요"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "호출어가 저장되었습니다"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "호출어를 저장할 수 없습니다"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "프로필 저장"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "음성, 전송 및 재생을 구성하세요."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "호출어, 대화 및 재생을 설정합니다."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "음성"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "음성 호출"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "호출어 감지"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "OpenClaw가 표시되는 동안 기기에서 실행됩니다."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "기기 내 음성 인식을 사용할 수 없습니다."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "호출어 감지"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "마지막 명령: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "다른 음성 활동 중에는 일시 중지됩니다."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "호출어"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "필드마다 호출어나 문구를 하나씩 추가하세요. 그런 다음 명령 전에 하나를 말하세요."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "호출어 또는 문구"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "호출 문구 제거"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "호출 문구 추가"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "호출어 저장"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "저장 중…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "호출어를 저장하려면 Gateway에 연결하세요"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw에서 선택한 알림을 받을 수 있습니다."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart~$quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "방해 금지 시간"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart~$quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "음성 오류 ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "꺼짐"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "기기 내 음성 인식을 사용할 수 없음"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "일시 정지됨"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "듣는 중"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "마이크 권한 필요"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "기기 언어가 지원되지 않음"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "기기 내 언어 모델을 사용할 수 없음"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "트리거됨"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway를 사용할 수 없음"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "시작 중…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/nl.json b/apps/.i18n/native/nl.json
index 608d43f452f5..e1acb65b8a31 100644
--- a/apps/.i18n/native/nl.json
+++ b/apps/.i18n/native/nl.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Nog geen canvas-update. Tik om het opnieuw te proberen."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Maak verbinding met een Gateway om activeringswoorden op te slaan"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Activeringswoorden opgeslagen"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Kan activeringswoorden niet opslaan"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Profiel opslaan"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Configureer spraak, transport en afspelen."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Configureer activeringswoorden, spraak en afspelen."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Spraak"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Spraakactivering"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Luisteren naar activeringswoorden"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Wordt op het apparaat uitgevoerd zolang OpenClaw zichtbaar is."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Spraakherkenning op het apparaat is niet beschikbaar."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Activeringswoorddetectie"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Laatste opdracht: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Wordt gepauzeerd tijdens andere spraakactiviteit."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Activeringswoorden"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Voeg per veld één activeringswoord of één activeringszin toe. Zeg er vervolgens één vóór uw opdracht."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Activeringswoord of activeringszin"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Activeringszin verwijderen"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Activeringszin toevoegen"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Activeringswoorden opslaan"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Opslaan…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Maak verbinding met een Gateway om activeringswoorden op te slaan"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw kan geselecteerde waarschuwingen ontvangen."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart tot $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Stille uren"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart tot $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Spraakfout ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Uit"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Spraakherkenning op het apparaat niet beschikbaar"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Gepauzeerd"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Luisteren"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Microfoontoestemming vereist"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Apparaattaal wordt niet ondersteund"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Taalmodel op het apparaat niet beschikbaar"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Geactiveerd"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway niet beschikbaar"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Starten…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/pl.json b/apps/.i18n/native/pl.json
index 7fd754a7c940..ebee06c9e3c9 100644
--- a/apps/.i18n/native/pl.json
+++ b/apps/.i18n/native/pl.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Brak aktualizacji obszaru roboczego. Dotknij, aby spróbować ponownie."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Połącz się z Gateway, aby zapisać słowa aktywujące"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Słowa aktywujące zapisane"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Nie udało się zapisać słów aktywujących"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Zapisz profil"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Skonfiguruj głos, transport i odtwarzanie."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Skonfiguruj słowa aktywujące, rozmowę i odtwarzanie."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Głos"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Aktywacja głosowa"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Nasłuchuj słów aktywujących"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Działa na urządzeniu, gdy OpenClaw jest widoczny."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Rozpoznawanie mowy na urządzeniu jest niedostępne."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Nasłuchiwanie aktywacji"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Ostatnie polecenie: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Wstrzymuje działanie podczas innej aktywności głosowej."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Słowa aktywujące"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Dodaj w każdym polu jedno słowo lub wyrażenie aktywujące. Następnie wypowiedz je przed poleceniem."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Słowo lub wyrażenie aktywujące"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Usuń wyrażenie aktywujące"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Dodaj wyrażenie aktywujące"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Zapisz słowa aktywujące"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Zapisywanie…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Połącz się z Gateway, aby zapisać słowa aktywujące"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw może odbierać wybrane alerty."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart–$quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Godziny ciszy"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart–$quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Błąd rozpoznawania mowy ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Wyłączone"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Rozpoznawanie mowy na urządzeniu jest niedostępne"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Wstrzymano"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Nasłuchiwanie"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Wymagane jest uprawnienie do mikrofonu"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Język urządzenia nie jest obsługiwany"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Model językowy na urządzeniu jest niedostępny"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Uruchomiono"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway jest niedostępny"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Uruchamianie…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/pt-BR.json b/apps/.i18n/native/pt-BR.json
index 28896a00befe..0564453a9fc0 100644
--- a/apps/.i18n/native/pt-BR.json
+++ b/apps/.i18n/native/pt-BR.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Ainda não há atualização da tela. Toque para tentar novamente."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Conecte-se a um Gateway para salvar as palavras de ativação"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Palavras de ativação salvas"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Não foi possível salvar as palavras de ativação"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Salvar perfil"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Configure voz, transporte e reprodução."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Configure palavras de ativação, fala e reprodução."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Voz"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Ativação por voz"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Ouvir palavras de ativação"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "É executado no dispositivo enquanto o OpenClaw está visível."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "O reconhecimento de fala no dispositivo não está disponível."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Detector de ativação"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Último comando: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Pausa durante outras atividades de voz."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Palavras de ativação"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Adicione uma palavra ou frase de ativação por campo. Depois, diga uma delas antes do comando."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Palavra ou frase de ativação"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Remover frase de ativação"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Adicionar frase de ativação"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Salvar palavras de ativação"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Salvando…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Conecte-se a um Gateway para salvar as palavras de ativação"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "O OpenClaw pode receber alertas selecionados."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart a $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Horário de silêncio"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart a $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Erro de fala ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Desativado"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Reconhecimento de fala no dispositivo indisponível"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Pausado"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Ouvindo"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Permissão para usar o microfone necessária"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Idioma do dispositivo não compatível"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Modelo de linguagem no dispositivo indisponível"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Acionado"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway indisponível"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Iniciando…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/ru.json b/apps/.i18n/native/ru.json
index 085a796a0552..4d441855be1d 100644
--- a/apps/.i18n/native/ru.json
+++ b/apps/.i18n/native/ru.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Обновлений холста пока нет. Нажмите, чтобы повторить попытку."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Подключитесь к Gateway, чтобы сохранить фразы активации"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Фразы активации сохранены"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Не удалось сохранить фразы активации"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Сохранить профиль"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Настройте голос, транспорт и воспроизведение."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Настройте фразы активации, голосовое управление и воспроизведение."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Голос"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Голосовая активация"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Распознавать фразы активации"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Работает на устройстве, пока OpenClaw отображается на экране."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Распознавание речи на устройстве недоступно."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Распознавание фраз активации"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Последняя команда: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Приостанавливается во время другой голосовой активности."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Фразы активации"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Добавьте в каждое поле одно слово или фразу активации. Затем произнесите её перед командой."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Слово или фраза активации"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Удалить фразу активации"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Добавить фразу активации"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Сохранить фразы активации"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Сохранение…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Подключитесь к Gateway, чтобы сохранить фразы активации"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw может получать выбранные оповещения."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "с $quietStart до $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Часы тишины"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "с $quietStart до $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Ошибка распознавания речи ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Выкл."
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Распознавание речи на устройстве недоступно"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Приостановлено"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Прослушивание"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Требуется разрешение на доступ к микрофону"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Язык устройства не поддерживается"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Языковая модель на устройстве недоступна"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Активировано"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway недоступен"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Запуск…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/sv.json b/apps/.i18n/native/sv.json
index a682521f95ae..035f4f1099ec 100644
--- a/apps/.i18n/native/sv.json
+++ b/apps/.i18n/native/sv.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Ingen canvasuppdatering ännu. Tryck för att försöka igen."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Anslut till en Gateway för att spara aktiveringsord"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Aktiveringsorden har sparats"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Det gick inte att spara aktiveringsorden"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Spara profil"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Konfigurera röst, transport och uppspelning."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Konfigurera aktiveringsord, tal och uppspelning."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Röst"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Röstaktivering"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Lyssna efter aktiveringsord"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Körs på enheten medan OpenClaw är synligt."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Taligenkänning på enheten är inte tillgänglig."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Aktiveringslyssnare"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Senaste kommando: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Pausas under annan röstaktivitet."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Aktiveringsord"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Lägg till ett aktiveringsord eller en fras per fält. Säg sedan ett av dem före ditt kommando."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Aktiveringsord eller fras"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Ta bort aktiveringsfras"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Lägg till aktiveringsfras"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Spara aktiveringsord"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Sparar…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Anslut till en Gateway för att spara aktiveringsord"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw kan ta emot valda varningar."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart till $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Tysta timmar"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart till $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Talfel ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Av"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Taligenkänning på enheten är inte tillgänglig"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Pausad"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Lyssnar"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Mikrofonbehörighet krävs"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Enhetens språk stöds inte"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Språkmodellen på enheten är inte tillgänglig"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Utlöst"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway är inte tillgänglig"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Startar…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/th.json b/apps/.i18n/native/th.json
index 0f111b88f2ad..c9d379b9bea1 100644
--- a/apps/.i18n/native/th.json
+++ b/apps/.i18n/native/th.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "ยังไม่มีการอัปเดต Canvas แตะเพื่อลองอีกครั้ง"
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "เชื่อมต่อกับ Gateway เพื่อบันทึกคำปลุก"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "บันทึกคำปลุกแล้ว"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "ไม่สามารถบันทึกคำปลุกได้"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "บันทึกโปรไฟล์"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "กำหนดค่าเสียง การรับส่งข้อมูล และการเล่น"
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "กำหนดค่าคำปลุก การพูด และการเล่นเสียง"
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "เสียง"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "การปลุกด้วยเสียง"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "ฟังคำปลุก"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "ทำงานบนอุปกรณ์ขณะที่ OpenClaw แสดงอยู่"
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "การรู้จำเสียงพูดบนอุปกรณ์ไม่พร้อมใช้งาน"
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "ตัวฟังคำปลุก"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "คำสั่งล่าสุด: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "หยุดชั่วคราวเมื่อมีกิจกรรมเสียงอื่น"
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "คำปลุก"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "เพิ่มคำหรือวลีปลุกหนึ่งรายการต่อช่อง จากนั้นพูดคำหรือวลีดังกล่าวก่อนออกคำสั่ง"
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "คำหรือวลีปลุก"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "นำวลีปลุกออก"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "เพิ่มวลีปลุก"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "บันทึกคำปลุก"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "กำลังบันทึก…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "เชื่อมต่อกับ Gateway เพื่อบันทึกคำปลุก"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw สามารถรับการเตือนที่เลือกได้"
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart ถึง $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "ช่วงเวลาห้ามรบกวน"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart ถึง $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "ข้อผิดพลาดในการรู้จำเสียง ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "ปิด"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "ไม่สามารถใช้การรู้จำเสียงบนอุปกรณ์ได้"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "หยุดชั่วคราว"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "กำลังฟัง"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "ต้องได้รับสิทธิ์เข้าถึงไมโครโฟน"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "ไม่รองรับภาษาของอุปกรณ์"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "ไม่สามารถใช้โมเดลภาษาบนอุปกรณ์ได้"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "ทริกเกอร์แล้ว"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway ไม่พร้อมใช้งาน"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "กำลังเริ่มต้น…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/tr.json b/apps/.i18n/native/tr.json
index aa6d1274b330..4621704b6b45 100644
--- a/apps/.i18n/native/tr.json
+++ b/apps/.i18n/native/tr.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Henüz canvas güncellemesi yok. Yeniden denemek için dokunun."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Uyandırma sözcüklerini kaydetmek için bir Gateway'e bağlanın"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Uyandırma sözcükleri kaydedildi"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Uyandırma sözcükleri kaydedilemedi"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Profili Kaydet"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Ses, aktarım ve oynatmayı yapılandırın."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Uyandırma sözcüklerini, konuşmayı ve oynatmayı yapılandırın."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Ses"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Sesle Uyandırma"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Uyandırma sözcüklerini dinle"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "OpenClaw görünür durumdayken cihaz üzerinde çalışır."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Cihaz üzerinde konuşma tanıma kullanılamıyor."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Uyandırma dinleyicisi"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Son komut: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Diğer ses etkinlikleri sırasında duraklatılır."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Uyandırma sözcükleri"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Her alana bir uyandırma sözcüğü veya ifadesi ekleyin. Ardından komutunuzdan önce bunlardan birini söyleyin."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Uyandırma sözcüğü veya ifadesi"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Uyandırma ifadesini kaldır"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Uyandırma ifadesi ekle"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Uyandırma sözcüklerini kaydet"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Kaydediliyor…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Uyandırma sözcüklerini kaydetmek için bir Gateway'e bağlanın"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw seçilen uyarıları alabilir."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart - $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Sessiz Saatler"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart - $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Konuşma hatası ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Kapalı"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Cihaz üzerinde konuşma tanıma kullanılamıyor"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Duraklatıldı"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Dinleniyor"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Mikrofon izni gerekli"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Cihaz dili desteklenmiyor"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Cihaz üzerindeki dil modeli kullanılamıyor"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Tetiklendi"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway kullanılamıyor"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Başlatılıyor…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/uk.json b/apps/.i18n/native/uk.json
index bbbcfc3c4217..746e86ad90e3 100644
--- a/apps/.i18n/native/uk.json
+++ b/apps/.i18n/native/uk.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Оновлень полотна ще немає. Торкніться, щоб повторити спробу."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Підключіться до Gateway, щоб зберегти слова активації"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Слова активації збережено"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Не вдалося зберегти слова активації"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Зберегти профіль"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Налаштуйте голос, передавання та відтворення."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Налаштуйте слова активації, мовлення та відтворення."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Голос"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Голосова активація"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Слухати слова активації"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Працює на пристрої, поки OpenClaw відображається на екрані."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Розпізнавання мовлення на пристрої недоступне."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Прослуховування слів активації"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Остання команда: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Призупиняється під час іншої голосової активності."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Слова активації"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Додайте одне слово або фразу активації в кожне поле. Потім промовте його перед командою."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Слово або фраза активації"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Видалити фразу активації"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Додати фразу активації"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Зберегти слова активації"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Збереження…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Підключіться до Gateway, щоб зберегти слова активації"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw може отримувати вибрані оповіщення."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "з $quietStart до $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Тихі години"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "з $quietStart до $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Помилка розпізнавання мовлення ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Вимкнено"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Розпізнавання мовлення на пристрої недоступне"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Призупинено"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Прослуховування"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Потрібен дозвіл на використання мікрофона"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Мова пристрою не підтримується"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Мовна модель на пристрої недоступна"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Активовано"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway недоступний"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Запуск…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/vi.json b/apps/.i18n/native/vi.json
index 68fdddbbe78b..4f969e9a5747 100644
--- a/apps/.i18n/native/vi.json
+++ b/apps/.i18n/native/vi.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "Chưa có bản cập nhật canvas. Nhấn để thử lại."
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Kết nối với Gateway để lưu từ đánh thức"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "Đã lưu từ đánh thức"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "Không thể lưu từ đánh thức"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "Lưu hồ sơ"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "Cấu hình giọng nói, truyền tải và phát lại."
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "Thiết lập từ đánh thức, trò chuyện và phát âm thanh."
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "Giọng nói"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "Đánh thức bằng giọng nói"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "Lắng nghe từ đánh thức"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "Chạy trên thiết bị khi OpenClaw đang hiển thị."
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "Tính năng nhận dạng giọng nói trên thiết bị không khả dụng."
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "Trình nghe từ đánh thức"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "Lệnh gần nhất: $command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "Tạm dừng khi có hoạt động giọng nói khác."
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "Từ đánh thức"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "Thêm một từ hoặc cụm từ đánh thức vào mỗi trường. Sau đó, hãy nói một từ hoặc cụm từ đó trước lệnh của bạn."
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "Từ hoặc cụm từ đánh thức"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "Xóa cụm từ đánh thức"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "Thêm cụm từ đánh thức"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "Lưu từ đánh thức"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "Đang lưu…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "Kết nối với Gateway để lưu từ đánh thức"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw có thể nhận các cảnh báo đã chọn."
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart đến $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "Giờ yên lặng"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart đến $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "Lỗi giọng nói ($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "Tắt"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "Nhận dạng giọng nói trên thiết bị không khả dụng"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "Đã tạm dừng"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "Đang nghe"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "Cần quyền truy cập micrô"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "Ngôn ngữ của thiết bị không được hỗ trợ"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "Mô hình ngôn ngữ trên thiết bị không khả dụng"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "Đã kích hoạt"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway không khả dụng"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "Đang khởi động…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/zh-CN.json b/apps/.i18n/native/zh-CN.json
index e26a6e79777b..217c86d0dc68 100644
--- a/apps/.i18n/native/zh-CN.json
+++ b/apps/.i18n/native/zh-CN.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "尚无画布更新。点按以重试。"
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "连接到 Gateway 以保存唤醒词"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "唤醒词已保存"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "无法保存唤醒词"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "保存个人资料"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "配置语音、传输和播放。"
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "配置唤醒词、语音交互和播放。"
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "语音"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "语音唤醒"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "监听唤醒词"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "当 OpenClaw 可见时在设备上运行。"
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "设备端语音识别不可用。"
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "唤醒监听器"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "上一条命令:$command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "检测到其他语音活动时暂停。"
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "唤醒词"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "每个字段添加一个唤醒词或短语,然后在说出命令前先说出其中一个。"
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "唤醒词或短语"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "移除唤醒短语"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "添加唤醒短语"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "保存唤醒词"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "正在保存…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "连接到 Gateway 以保存唤醒词"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw 可以接收选定的提醒。"
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart 至 $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "免打扰时段"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart 至 $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "语音错误($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "关闭"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "设备端语音识别不可用"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "已暂停"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "正在聆听"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "需要麦克风权限"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "不支持设备语言"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "设备端语言模型不可用"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "已触发"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway 不可用"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "正在启动…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/.i18n/native/zh-TW.json b/apps/.i18n/native/zh-TW.json
index 4fd3ce00f242..f6bcf98a6c9a 100644
--- a/apps/.i18n/native/zh-TW.json
+++ b/apps/.i18n/native/zh-TW.json
@@ -588,6 +588,21 @@
"source": "No canvas update yet. Tap to retry.",
"translated": "尚無畫布更新。輕觸以重試。"
},
+ {
+ "id": "native.android.00a2531a39904d08",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "連線至 Gateway 以儲存喚醒詞"
+ },
+ {
+ "id": "native.android.538201c75b85068f",
+ "source": "Wake words saved",
+ "translated": "已儲存喚醒詞"
+ },
+ {
+ "id": "native.android.b367e85de3a7148f",
+ "source": "Could not save wake words",
+ "translated": "無法儲存喚醒詞"
+ },
{
"id": "native.android.4b07456682e725d9",
"source": "Failed: no secure gateway endpoint was detected. Enable gateway TLS or Tailscale Serve, or use a trusted private LAN address with Unencrypted selected.",
@@ -4054,9 +4069,89 @@
"translated": "儲存個人資料"
},
{
- "id": "native.android.19f0834b4dbcc85a",
- "source": "Configure voice, transport, and playback.",
- "translated": "設定語音、傳輸和播放。"
+ "id": "native.android.deda55df7ca328fc",
+ "source": "Configure wake words, talk, and playback.",
+ "translated": "設定喚醒詞、對話與播放。"
+ },
+ {
+ "id": "native.android.2ae2282617282586",
+ "source": "Voice",
+ "translated": "語音"
+ },
+ {
+ "id": "native.android.3f54d9356234744e",
+ "source": "Voice Wake",
+ "translated": "語音喚醒"
+ },
+ {
+ "id": "native.android.34ec8a3bc017cbd5",
+ "source": "Listen for wake words",
+ "translated": "聆聽喚醒詞"
+ },
+ {
+ "id": "native.android.6e58157abced395f",
+ "source": "Runs on-device while OpenClaw is visible.",
+ "translated": "當 OpenClaw 顯示於畫面時,會在裝置上執行。"
+ },
+ {
+ "id": "native.android.6464166ab71fde3f",
+ "source": "On-device speech recognition is unavailable.",
+ "translated": "無法使用裝置端語音辨識。"
+ },
+ {
+ "id": "native.android.35d996c1bc693bb9",
+ "source": "Wake listener",
+ "translated": "喚醒詞偵聽器"
+ },
+ {
+ "id": "native.android.12fd2cd4e7d1d778",
+ "source": "Last command: $command",
+ "translated": "上一個指令:$command"
+ },
+ {
+ "id": "native.android.a36f052c5f1691d6",
+ "source": "Pauses during other voice activity.",
+ "translated": "進行其他語音活動時會暫停。"
+ },
+ {
+ "id": "native.android.a5272caac136694c",
+ "source": "Wake words",
+ "translated": "喚醒詞"
+ },
+ {
+ "id": "native.android.37e7e27c16eca7fe",
+ "source": "Add one wake word or phrase per field. Then say one before your command.",
+ "translated": "每個欄位新增一個喚醒詞或詞組,然後在說出指令前先說出其中一個。"
+ },
+ {
+ "id": "native.android.95e42f0b4b6d4092",
+ "source": "Wake word or phrase",
+ "translated": "喚醒詞或詞組"
+ },
+ {
+ "id": "native.android.0b35023a9220d572",
+ "source": "Remove wake phrase",
+ "translated": "移除喚醒詞組"
+ },
+ {
+ "id": "native.android.0bff8c1428b32178",
+ "source": "Add wake phrase",
+ "translated": "新增喚醒詞組"
+ },
+ {
+ "id": "native.android.dfb84902f6a483d0",
+ "source": "Save wake words",
+ "translated": "儲存喚醒詞"
+ },
+ {
+ "id": "native.android.5ab6829fa57f662d",
+ "source": "Saving…",
+ "translated": "正在儲存…"
+ },
+ {
+ "id": "native.android.672382a4b7900ee6",
+ "source": "Connect to a Gateway to save wake words",
+ "translated": "連線至 Gateway 以儲存喚醒詞"
},
{
"id": "native.android.8d0458a4fe154e9b",
@@ -4143,16 +4238,16 @@
"source": "OpenClaw can receive selected alerts.",
"translated": "OpenClaw 可以接收所選提醒。"
},
- {
- "id": "native.android.fef97bfb2cd5d228",
- "source": "$quietStart to $quietEnd",
- "translated": "$quietStart 至 $quietEnd"
- },
{
"id": "native.android.a04ee29c0a3b68f5",
"source": "Quiet Hours",
"translated": "勿擾時段"
},
+ {
+ "id": "native.android.fef97bfb2cd5d228",
+ "source": "$quietStart to $quietEnd",
+ "translated": "$quietStart 至 $quietEnd"
+ },
{
"id": "native.android.db3ed951c0462727",
"source": "Policy",
@@ -7883,6 +7978,56 @@
"source": "Speech error ($error)",
"translated": "語音錯誤($error)"
},
+ {
+ "id": "native.android.11d70a2e3419e346",
+ "source": "Off",
+ "translated": "關閉"
+ },
+ {
+ "id": "native.android.b21cacf24f03d772",
+ "source": "On-device speech recognition unavailable",
+ "translated": "裝置端語音辨識無法使用"
+ },
+ {
+ "id": "native.android.c379aa335b932db2",
+ "source": "Paused",
+ "translated": "已暫停"
+ },
+ {
+ "id": "native.android.d0c22c4961346923",
+ "source": "Listening",
+ "translated": "正在聆聽"
+ },
+ {
+ "id": "native.android.894062d81447a410",
+ "source": "Microphone permission required",
+ "translated": "需要麥克風權限"
+ },
+ {
+ "id": "native.android.d404b3d5f084f5d2",
+ "source": "Device language not supported",
+ "translated": "不支援裝置語言"
+ },
+ {
+ "id": "native.android.d559a0a3f32701b8",
+ "source": "On-device language model unavailable",
+ "translated": "裝置端語言模型無法使用"
+ },
+ {
+ "id": "native.android.269915b38b1486c0",
+ "source": "Triggered",
+ "translated": "已觸發"
+ },
+ {
+ "id": "native.android.9a0753f5ae9394ab",
+ "source": "Gateway unavailable",
+ "translated": "Gateway 無法使用"
+ },
+ {
+ "id": "native.android.eef69ee3eb23cc1b",
+ "source": "Starting…",
+ "translated": "正在啟動…"
+ },
{
"id": "native.android.f392ee2d50d6b7ce",
"source": "ask OpenClaw $prompt",
diff --git a/apps/android/CHANGELOG.md b/apps/android/CHANGELOG.md
index 5d42ee8c60ce..86ed4b5f9de8 100644
--- a/apps/android/CHANGELOG.md
+++ b/apps/android/CHANGELOG.md
@@ -2,6 +2,8 @@
## Unreleased
+Adds foreground, on-device Voice Wake with editable Gateway-synced wake words and automatic pause during other voice activity.
+
## 2026.7.2 - 2026-07-13
Adds Automations and Skills management with search, filters, editing, run tracking, install safety, and ClawHub risk review.
diff --git a/apps/android/README.md b/apps/android/README.md
index 01fac2501e25..b192e4bda7fd 100644
--- a/apps/android/README.md
+++ b/apps/android/README.md
@@ -18,6 +18,7 @@ OpenClaw Android is the officially released Google Play app. It connects to an O
- [x] Security hardening (biometric lock, token handling, safer defaults)
- [x] Authenticated background presence beacons
- [x] Voice tab full functionality
+- [x] Foreground on-device Voice Wake with Gateway-synced wake words
- [x] Screen tab full functionality
- [x] Skill Workshop settings can filter proposals, inspect proposal content, and apply/reject/quarantine drafts through Gateway RPCs
- [x] Skills settings can search installed skills, enable or disable them, and install Gateway-verified ClawHub releases
diff --git a/apps/android/app/src/main/AndroidManifest.xml b/apps/android/app/src/main/AndroidManifest.xml
index ef313b2c5c4a..aa4acbe594b8 100644
--- a/apps/android/app/src/main/AndroidManifest.xml
+++ b/apps/android/app/src/main/AndroidManifest.xml
@@ -30,6 +30,9 @@
+
+
+
= prefs.canvasDebugStatusEnabled
val installedAppsSharingEnabled: StateFlow = prefs.installedAppsSharingEnabled
val speakerEnabled: StateFlow = prefs.speakerEnabled
+ val voiceWakeEnabled: StateFlow = prefs.voiceWakeEnabled
+ val voiceWakeWords: StateFlow> = prefs.voiceWakeWords
+ val voiceWakeAvailable: StateFlow = runtimeState(initial = false) { it.voiceWakeAvailable }
+ val voiceWakeIsListening: StateFlow = runtimeState(initial = false) { it.voiceWakeIsListening }
+ val voiceWakeStatusText: StateFlow = runtimeState(initial = "Off") { it.voiceWakeStatusText }
+ val voiceWakeLastTriggeredCommand: StateFlow =
+ runtimeState(initial = null) { it.voiceWakeLastTriggeredCommand }
+ val voiceWakeWordsSaving: StateFlow = runtimeState(initial = false) { it.voiceWakeWordsSaving }
+ val voiceWakeWordsNoticeText: StateFlow = runtimeState(initial = null) { it.voiceWakeWordsNoticeText }
val appearanceThemeMode: StateFlow = prefs.appearanceThemeMode
val voiceCaptureMode: StateFlow = runtimeState(initial = VoiceCaptureMode.Off) { it.voiceCaptureMode }
val micEnabled: StateFlow = runtimeState(initial = false) { it.micEnabled }
@@ -772,6 +785,18 @@ class MainViewModel private constructor(
ensureRuntime().setSpeakerEnabled(enabled)
}
+ fun setVoiceWakeEnabled(enabled: Boolean) {
+ ensureRuntime().setVoiceWakeEnabled(enabled)
+ }
+
+ fun setVoiceWakeWords(values: List) {
+ ensureRuntime().setVoiceWakeWords(values)
+ }
+
+ fun refreshVoiceWakePermission() {
+ ensureRuntime().refreshVoiceWakePermission()
+ }
+
fun setAppearanceThemeMode(mode: AppearanceThemeMode) {
prefs.setAppearanceThemeMode(mode)
}
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt b/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt
index a8a88c84e22a..778884896721 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt
@@ -24,6 +24,8 @@ import ai.openclaw.app.gateway.DeviceAuthStore
import ai.openclaw.app.gateway.DeviceIdentityStore
import ai.openclaw.app.gateway.GatewayDiscovery
import ai.openclaw.app.gateway.GatewayEndpoint
+import ai.openclaw.app.gateway.GatewayEvent
+import ai.openclaw.app.gateway.GatewayMethod
import ai.openclaw.app.gateway.GatewayRegistryEntry
import ai.openclaw.app.gateway.GatewayRegistryEntryKind
import ai.openclaw.app.gateway.GatewayRequestDefinitiveFailure
@@ -76,14 +78,20 @@ import ai.openclaw.app.node.asStringOrNull
import ai.openclaw.app.node.invokeErrorFromThrowable
import ai.openclaw.app.node.parseHexColorArgb
import ai.openclaw.app.protocol.OpenClawCanvasA2UIAction
+import ai.openclaw.app.voice.AndroidOnDeviceVoiceWakeRecognizer
import ai.openclaw.app.voice.GatewayTranscriptionSession
import ai.openclaw.app.voice.MicCaptureManager
+import ai.openclaw.app.voice.PreviewVoiceWakeRecognizer
import ai.openclaw.app.voice.TalkAudioPlayer
import ai.openclaw.app.voice.TalkModeManager
import ai.openclaw.app.voice.TalkPttOnceStart
import ai.openclaw.app.voice.TalkPttStopPayload
import ai.openclaw.app.voice.VoiceConversationEntry
import ai.openclaw.app.voice.VoiceConversationRole
+import ai.openclaw.app.voice.VoiceWakeManager
+import ai.openclaw.app.voice.VoiceWakeMatch
+import ai.openclaw.app.voice.VoiceWakePreferences
+import ai.openclaw.app.voice.VoiceWakeSuppressionReason
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
@@ -126,6 +134,7 @@ import kotlinx.serialization.json.contentOrNull
import java.util.Collections
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference
@@ -569,6 +578,33 @@ class NodeRuntime private constructor(
val sms = SmsManager(appContext)
private val json = Json { ignoreUnknownKeys = true }
+ private val voiceWakeManager =
+ VoiceWakeManager(
+ context = appContext,
+ scope = scope,
+ recognizer =
+ when (mode) {
+ NodeRuntimeMode.Live -> AndroidOnDeviceVoiceWakeRecognizer(appContext)
+ NodeRuntimeMode.ScreenshotFixture -> PreviewVoiceWakeRecognizer()
+ },
+ initialTriggerWords = VoiceWakePreferences.defaultTriggerWords,
+ onCommand = ::sendVoiceWakeCommand,
+ )
+ val voiceWakeAvailable: StateFlow = MutableStateFlow(voiceWakeManager.isAvailable).asStateFlow()
+ val voiceWakeEnabled: StateFlow = prefs.voiceWakeEnabled
+ val voiceWakeWords: StateFlow> = prefs.voiceWakeWords
+ val voiceWakeIsListening: StateFlow = voiceWakeManager.isListening
+ val voiceWakeStatusText: StateFlow = voiceWakeManager.statusText
+ val voiceWakeLastTriggeredCommand: StateFlow = voiceWakeManager.lastTriggeredCommand
+ private val voiceWakeWordsSaveSeq = AtomicLong(0)
+ private val voiceWakeWordsLock = Any()
+ private var voiceWakeWordsRevision = 0L
+ private var voiceWakeWordsGatewayStableId: String? = null
+ private val _voiceWakeWordsSaving = MutableStateFlow(false)
+ val voiceWakeWordsSaving: StateFlow = _voiceWakeWordsSaving.asStateFlow()
+ private val _voiceWakeWordsNoticeText = MutableStateFlow(null)
+ val voiceWakeWordsNoticeText: StateFlow = _voiceWakeWordsNoticeText.resolveOptionalNativeText()
+
private val externalAudioCaptureActive = MutableStateFlow(false)
private val _voiceCaptureMode = MutableStateFlow(VoiceCaptureMode.Off)
val voiceCaptureMode: StateFlow = _voiceCaptureMode.asStateFlow()
@@ -585,7 +621,7 @@ class NodeRuntime private constructor(
CameraHandler(
appContext = appContext,
camera = camera,
- externalAudioCaptureActive = externalAudioCaptureActive,
+ setCameraAudioCaptureActive = ::setCameraAudioCaptureActive,
showCameraHud = ::showCameraHud,
invokeErrorFromThrowable = { invokeErrorFromThrowable(it) },
)
@@ -673,12 +709,18 @@ class NodeRuntime private constructor(
callLogAvailable = { SensitiveFeatureConfig.callLogEnabled },
photosAvailable = { SensitiveFeatureConfig.photosEnabled },
installedAppsSharingEnabled = { installedAppsSharingEnabled.value },
+ voiceWakeAvailable = {
+ voiceWakeManager.isAvailable &&
+ hasRecordAudioPermission() &&
+ isVoiceWakeWordsReadyForCurrentGateway()
+ },
manualTls = { endpoint ->
prefs.gatewayRegistry.entries.value
.firstOrNull { it.stableId == endpoint.stableId }
?.tls ?: manualTls.value
},
)
+ private var lastVoiceWakeCapabilityEnabled = isVoiceWakeCapabilityEnabled()
private val invokeDispatcher: InvokeDispatcher =
InvokeDispatcher(
@@ -959,6 +1001,12 @@ class NodeRuntime private constructor(
val epoch: Long,
)
+ private data class VoiceWakeSuppressionUpdate(
+ val reason: VoiceWakeSuppressionReason,
+ val suppressed: Boolean,
+ val revision: Long,
+ )
+
private val voiceLifecycleEpoch = AtomicLong()
private val voiceCaptureOwnershipEpoch = AtomicLong()
private val talkPttCommandEpoch = AtomicLong()
@@ -967,7 +1015,10 @@ class NodeRuntime private constructor(
// Keep ownership epochs and their service/capture state transitions atomic.
// Otherwise stale PTT cleanup can pass its epoch check before a UI mode change.
private val voiceCaptureOwnershipLock = Any()
+ private var voiceWakeSuppressionRevision = 0L
private var voiceNoteOwnsMic = false
+ private var cameraAudioOwnsMic = false
+ private val voiceReplySpeechDepth = AtomicInteger(0)
private val voiceCapturePreparationMutex = Mutex()
private var didAutoRequestCanvasRehydrate = false
@@ -1009,6 +1060,7 @@ class NodeRuntime private constructor(
micCapture.onGatewayConnectionChanged(true)
scope.launch {
subscribeOperatorSessionEvents()
+ refreshWakeWordsFromGateway()
refreshExecApprovalsFromGateway()
refreshHomeCanvasOverviewIfConnected()
if (voiceReplySpeakerLazy.isInitialized()) {
@@ -1059,6 +1111,9 @@ class NodeRuntime private constructor(
_modelCatalogRefreshing.value = false
_modelCatalogErrorText.value = null
_talkSetupReadiness.value = GatewayTalkSetupReadiness.unverified()
+ voiceWakeWordsSaveSeq.incrementAndGet()
+ _voiceWakeWordsSaving.value = false
+ _voiceWakeWordsNoticeText.value = null
cronRefreshGuard.invalidate()
_cronStatus.value = GatewayCronStatus(enabled = false, jobs = 0, nextWakeAtMs = null)
_cronJobs.value = emptyList()
@@ -1171,7 +1226,7 @@ class NodeRuntime private constructor(
scope.launch { refreshNodesDevicesFromGateway() }
}
},
- onEvent = { _, _ -> },
+ onEvent = ::handleNodeGatewayEvent,
onInvoke = { req ->
invokeDispatcher.handleInvoke(req.command, req.paramsJson)
},
@@ -1281,7 +1336,13 @@ class NodeRuntime private constructor(
synthesizer = MessageSpeechClient(session = operatorSession, json = json),
player = TalkAudioPlayer(appContext),
localSpeech = SystemSpeechSpeaker(appContext),
- )
+ ).also { controller ->
+ scope.launch {
+ controller.state.collect { state ->
+ voiceWakeManager.setSuppressed(VoiceWakeSuppressionReason.MessageSpeech, state != null)
+ }
+ }
+ }
}
private val messageSpeechController: MessageSpeechController
get() = messageSpeechControllerLazy.value
@@ -1312,8 +1373,17 @@ class NodeRuntime private constructor(
session = operatorSession,
isConnected = { gatewayConnectionDisplay.value.isConnected },
gatewayStableId = { connectedEndpoint?.stableId },
- onBeforeSpeak = { micCapture.pauseForTts() },
- onAfterSpeak = { micCapture.resumeAfterTts() },
+ onBeforeSpeak = {
+ acquireVoiceReplySpeechSuppression()
+ micCapture.pauseForTts()
+ },
+ onAfterSpeak = {
+ try {
+ micCapture.resumeAfterTts()
+ } finally {
+ releaseVoiceReplySpeechSuppression()
+ }
+ },
).also { speaker ->
speaker.setPlaybackEnabled(prefs.speakerEnabled.value)
}
@@ -2253,6 +2323,20 @@ class NodeRuntime private constructor(
applyScreenshotFixture()
}
+ if (mode == NodeRuntimeMode.Live) {
+ invalidateVoiceWakeWordsForGateway()
+ }
+ reconcileVoiceWakeCaptureSuppression()
+ voiceWakeManager.setForeground(initialForeground)
+ voiceWakeManager.setEnabled(prefs.voiceWakeEnabled.value)
+ scope.launch {
+ micCapture.micCooldown.collect {
+ // Manual capture drains partial audio for two seconds after its toggle
+ // turns off. Resume Voice Wake only after that capture owner releases.
+ reconcileVoiceWakeCaptureSuppression()
+ }
+ }
+
scope.launch {
combine(
canvasDebugStatusEnabled,
@@ -2281,11 +2365,13 @@ class NodeRuntime private constructor(
/** Updates foreground state and triggers reconnect/presence behavior on app visibility changes. */
fun setForeground(value: Boolean) {
_isForeground.value = value
+ voiceWakeManager.setForeground(value)
if (mode == NodeRuntimeMode.ScreenshotFixture) return
if (!value) {
voiceLifecycleEpoch.incrementAndGet()
}
if (value) {
+ refreshVoiceWakeCapabilitySurfaceIfChanged()
reconnectPreferredGatewayOnForeground()
scope.launch {
refreshExecApprovalsFromGateway()
@@ -2590,17 +2676,24 @@ class NodeRuntime private constructor(
setVoiceCaptureMode(if (value) VoiceCaptureMode.ManualMic else VoiceCaptureMode.Off)
}
- internal fun tryAcquireVoiceNoteMic(): Boolean =
- synchronized(voiceCaptureOwnershipLock) {
- if (voiceNoteOwnsMic || !isVoiceCaptureModeActive(VoiceCaptureMode.Off)) return@synchronized false
- voiceNoteOwnsMic = true
- true
- }
+ internal fun tryAcquireVoiceNoteMic(): Boolean {
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ if (voiceNoteOwnsMic || !isVoiceCaptureModeActive(VoiceCaptureMode.Off)) return false
+ voiceNoteOwnsMic = true
+ createVoiceWakeSuppressionUpdateLocked(VoiceWakeSuppressionReason.VoiceNote, true)
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
+ return true
+ }
internal fun releaseVoiceNoteMic() {
- synchronized(voiceCaptureOwnershipLock) {
- voiceNoteOwnsMic = false
- }
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ voiceNoteOwnsMic = false
+ createVoiceWakeSuppressionUpdateLocked(VoiceWakeSuppressionReason.VoiceNote, false)
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
}
fun cancelMicCapture() {
@@ -2752,7 +2845,7 @@ class NodeRuntime private constructor(
): Long {
// Publish preparation on Main with lifecycle shutdown. After this block
// yields, preparation must not write capture state that backgrounding cleared.
- val ownershipEpoch =
+ val (ownershipEpoch, suppressionUpdate) =
withContext(Dispatchers.Main) {
synchronized(voiceCaptureOwnershipLock) {
if (
@@ -2765,19 +2858,23 @@ class NodeRuntime private constructor(
if (voiceNoteOwnsMic) {
throw IllegalStateException("MIC_BUSY: voice note recording is active")
}
+ if (cameraAudioOwnsMic) {
+ throw IllegalStateException("MIC_BUSY: camera audio recording is active")
+ }
if (!hasRecordAudioPermission()) {
throw IllegalStateException("MIC_PERMISSION_REQUIRED: grant Microphone permission")
}
val epoch = voiceCaptureOwnershipEpoch.incrementAndGet()
+ val update = setExternalAudioCaptureActiveLocked(true)
micCapture.setMicEnabled(false)
stopVoicePlayback()
NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.TalkMode)
talkMode.ttsOnAllResponses = true
talkMode.setPlaybackEnabled(speakerEnabled.value)
- externalAudioCaptureActive.value = true
- epoch
+ epoch to update
}
}
+ applyVoiceWakeSuppression(suppressionUpdate)
try {
talkMode.refreshConfig()
return ownershipEpoch
@@ -2788,19 +2885,21 @@ class NodeRuntime private constructor(
}
private fun cleanupFailedTalkCapture(ownershipEpoch: Long) {
- synchronized(voiceCaptureOwnershipLock) {
- // TalkModeManager owns capture-scoped cancellation. A stale invoke must not
- // tear down a newer capture after a background/foreground transition.
- if (voiceCaptureOwnershipEpoch.get() == ownershipEpoch) {
- talkMode.activePushToTalkCaptureId?.let { captureId ->
- // An idempotent retry can fail while the original capture remains live.
- // Transfer preparation ownership so its eventual stop still cleans up.
- talkPttOwnership.set(TalkPttOwnership(captureId = captureId, epoch = ownershipEpoch))
- return
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ // TalkModeManager owns capture-scoped cancellation. A stale invoke must not
+ // tear down a newer capture after a background/foreground transition.
+ if (voiceCaptureOwnershipEpoch.get() == ownershipEpoch) {
+ talkMode.activePushToTalkCaptureId?.let { captureId ->
+ // An idempotent retry can fail while the original capture remains live.
+ // Transfer preparation ownership so its eventual stop still cleans up.
+ talkPttOwnership.set(TalkPttOwnership(captureId = captureId, epoch = ownershipEpoch))
+ return
+ }
}
+ finishTalkCaptureIfIdleUnderOwnershipLock(ownershipEpoch)
}
- finishTalkCaptureIfIdleUnderOwnershipLock(ownershipEpoch)
- }
+ applyVoiceWakeSuppression(suppressionUpdate)
}
private fun recordTalkPttOwnership(
@@ -2838,32 +2937,37 @@ class NodeRuntime private constructor(
}
private fun finishTalkCaptureIfIdleLocked(captureId: String) {
- synchronized(voiceCaptureOwnershipLock) {
- val ownership = talkPttOwnership.get()
- if (ownership?.captureId != captureId || !talkPttOwnership.compareAndSet(ownership, null)) return
- finishTalkCaptureIfIdleUnderOwnershipLock(ownership.epoch)
- }
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ val ownership = talkPttOwnership.get()
+ if (ownership?.captureId != captureId || !talkPttOwnership.compareAndSet(ownership, null)) return
+ finishTalkCaptureIfIdleUnderOwnershipLock(ownership.epoch)
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
}
- private fun finishTalkCaptureIfIdleUnderOwnershipLock(ownershipEpoch: Long) {
- if (ownershipEpoch == 0L || voiceCaptureOwnershipEpoch.get() != ownershipEpoch) return
+ private fun finishTalkCaptureIfIdleUnderOwnershipLock(ownershipEpoch: Long): VoiceWakeSuppressionUpdate? {
+ if (ownershipEpoch == 0L || voiceCaptureOwnershipEpoch.get() != ownershipEpoch) return null
if (!talkMode.isEnabled.value && !talkMode.isListening.value && !talkMode.isSpeaking.value) {
talkMode.ttsOnAllResponses = false
NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
- externalAudioCaptureActive.value = false
+ return setExternalAudioCaptureActiveLocked(false)
}
+ return null
}
private fun finishTalkModeAfterRelayClose() {
- synchronized(voiceCaptureOwnershipLock) {
- if (_voiceCaptureMode.value != VoiceCaptureMode.TalkMode) return
- talkPttCommandEpoch.incrementAndGet()
- voiceCaptureOwnershipEpoch.incrementAndGet()
- _voiceCaptureMode.value = VoiceCaptureMode.Off
- talkMode.ttsOnAllResponses = false
- NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
- externalAudioCaptureActive.value = false
- }
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ if (_voiceCaptureMode.value != VoiceCaptureMode.TalkMode) return
+ talkPttCommandEpoch.incrementAndGet()
+ voiceCaptureOwnershipEpoch.incrementAndGet()
+ _voiceCaptureMode.value = VoiceCaptureMode.Off
+ talkMode.ttsOnAllResponses = false
+ NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
+ setExternalAudioCaptureActiveLocked(false)
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
}
val speakerEnabled: StateFlow
@@ -2878,6 +2982,94 @@ class NodeRuntime private constructor(
talkMode.setPlaybackEnabled(value)
}
+ fun setVoiceWakeEnabled(value: Boolean) {
+ if (value && !voiceWakeManager.isAvailable) return
+ if (prefs.voiceWakeEnabled.value == value) return
+ prefs.setVoiceWakeEnabled(value)
+ voiceWakeManager.setEnabled(value)
+ refreshVoiceWakeCapabilitySurfaceIfChanged()
+ }
+
+ fun setVoiceWakeWords(words: List) {
+ val sanitized = VoiceWakePreferences.sanitizeTriggerWords(words)
+ if (mode == NodeRuntimeMode.ScreenshotFixture) {
+ prefs.setVoiceWakeWords(sanitized)
+ voiceWakeManager.updateTriggerWords(sanitized)
+ _voiceWakeWordsNoticeText.value = nativeText("Wake words saved")
+ return
+ }
+ val gatewayScope = captureGatewayDataScope()
+ if (gatewayScope == null) {
+ _voiceWakeWordsNoticeText.value = nativeText("Connect to a Gateway to save wake words")
+ return
+ }
+ if (!isVoiceWakeWordsReadyFor(gatewayScope.stableId)) {
+ _voiceWakeWordsNoticeText.value = nativeText("Connect to a Gateway to save wake words")
+ return
+ }
+ val saveSeq = voiceWakeWordsSaveSeq.incrementAndGet()
+ val requestRevision = currentVoiceWakeWordsRevision()
+ _voiceWakeWordsSaving.value = true
+ _voiceWakeWordsNoticeText.value = null
+ scope.launch {
+ var published = false
+ try {
+ val response =
+ requestGatewayData(
+ gatewayScope,
+ GatewayMethod.VoicewakeSet.rawValue,
+ buildJsonObject {
+ put("triggers", JsonArray(sanitized.map(::JsonPrimitive)))
+ }.toString(),
+ )
+ val canonical = parseVoiceWakeWords(response) ?: error("voicewake.set returned invalid triggers")
+ published =
+ publishGatewayData(gatewayScope) {
+ if (saveSeq == voiceWakeWordsSaveSeq.get()) {
+ applyAuthoritativeVoiceWakeWords(
+ words = canonical,
+ gatewayStableId = gatewayScope.stableId,
+ expectedRevision = requestRevision,
+ )
+ _voiceWakeWordsSaving.value = false
+ _voiceWakeWordsNoticeText.value = nativeText("Wake words saved")
+ }
+ }
+ } catch (_: CancellationException) {
+ // Gateway-scope retirement owns state reset; never publish the old response.
+ } catch (err: Throwable) {
+ Log.d("OpenClawRuntime", "voicewake.set failed: ${err.message ?: err::class.java.simpleName}")
+ if (saveSeq == voiceWakeWordsSaveSeq.get() && isGatewayDataScopeCurrent(gatewayScope)) {
+ _voiceWakeWordsSaving.value = false
+ _voiceWakeWordsNoticeText.value = nativeText("Could not save wake words")
+ }
+ } finally {
+ if (!published && saveSeq == voiceWakeWordsSaveSeq.get() && !isGatewayDataScopeCurrent(gatewayScope)) {
+ _voiceWakeWordsSaving.value = false
+ _voiceWakeWordsNoticeText.value = null
+ }
+ }
+ }
+ }
+
+ fun refreshVoiceWakePermission() {
+ voiceWakeManager.refreshPermission()
+ refreshVoiceWakeCapabilitySurfaceIfChanged()
+ }
+
+ private fun isVoiceWakeCapabilityEnabled(): Boolean =
+ prefs.voiceWakeEnabled.value &&
+ voiceWakeManager.isAvailable &&
+ hasRecordAudioPermission() &&
+ isVoiceWakeWordsReadyForCurrentGateway()
+
+ private fun refreshVoiceWakeCapabilitySurfaceIfChanged() {
+ val enabled = isVoiceWakeCapabilityEnabled()
+ if (enabled == lastVoiceWakeCapabilityEnabled) return
+ lastVoiceWakeCapabilityEnabled = enabled
+ refreshNodeSurfaceAfterSettingsChange()
+ }
+
suspend fun runVoiceE2e(
mode: String,
transcript: String,
@@ -2991,56 +3183,77 @@ class NodeRuntime private constructor(
mode: VoiceCaptureMode,
persistManualMic: Boolean = true,
) {
+ var startAfterSuppression: VoiceCaptureMode? = null
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ if (mode != VoiceCaptureMode.Off && voiceNoteOwnsMic) return
+ if (mode != VoiceCaptureMode.Off && cameraAudioOwnsMic) return
+ talkPttCommandEpoch.incrementAndGet()
+ voiceCaptureOwnershipEpoch.incrementAndGet()
+ val permissionDenied = mode.requiresMicrophonePermission && !hasRecordAudioPermission()
+ val captureMode = if (permissionDenied) VoiceCaptureMode.Off else mode
+ if (permissionDenied) prefs.setVoiceMicEnabled(false)
+ if (_voiceCaptureMode.value == captureMode && isVoiceCaptureModeActive(captureMode)) return
+ talkPttOwnership.set(null)
+ _voiceCaptureMode.value = captureMode
+ when (captureMode) {
+ VoiceCaptureMode.Off -> {
+ talkMode.ttsOnAllResponses = false
+ talkMode.stopAllCapture()
+ stopVoicePlayback()
+ micCapture.setMicEnabled(false)
+ if (persistManualMic) {
+ prefs.setVoiceMicEnabled(false)
+ }
+ NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
+ setExternalAudioCaptureActiveLocked(false)
+ }
+
+ VoiceCaptureMode.ManualMic -> {
+ talkMode.ttsOnAllResponses = false
+ talkMode.stopAllCapture()
+ NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.ManualMic)
+ if (persistManualMic) {
+ prefs.setVoiceMicEnabled(true)
+ }
+ // Tapping mic on interrupts any active TTS (barge-in).
+ stopVoicePlayback()
+ scope.launch { talkMode.refreshConfig() }
+ startAfterSuppression = VoiceCaptureMode.ManualMic
+ setExternalAudioCaptureActiveLocked(true)
+ }
+
+ VoiceCaptureMode.TalkMode -> {
+ if (persistManualMic) {
+ prefs.setVoiceMicEnabled(false)
+ }
+ micCapture.setMicEnabled(false)
+ NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.TalkMode)
+ talkMode.ttsOnAllResponses = true
+ talkMode.setPlaybackEnabled(speakerEnabled.value)
+ scope.launch { talkMode.refreshConfig() }
+ talkMode.stopAllCapture()
+ startAfterSuppression = VoiceCaptureMode.TalkMode
+ setExternalAudioCaptureActiveLocked(true)
+ }
+ }
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
synchronized(voiceCaptureOwnershipLock) {
- if (mode != VoiceCaptureMode.Off && voiceNoteOwnsMic) return
- talkPttCommandEpoch.incrementAndGet()
- voiceCaptureOwnershipEpoch.incrementAndGet()
- val permissionDenied = mode.requiresMicrophonePermission && !hasRecordAudioPermission()
- val captureMode = if (permissionDenied) VoiceCaptureMode.Off else mode
- if (permissionDenied) prefs.setVoiceMicEnabled(false)
- if (_voiceCaptureMode.value == captureMode && isVoiceCaptureModeActive(captureMode)) return
- talkPttOwnership.set(null)
- _voiceCaptureMode.value = captureMode
- when (captureMode) {
- VoiceCaptureMode.Off -> {
- talkMode.ttsOnAllResponses = false
- talkMode.stopAllCapture()
- stopVoicePlayback()
- micCapture.setMicEnabled(false)
- if (persistManualMic) {
- prefs.setVoiceMicEnabled(false)
- }
- NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
- externalAudioCaptureActive.value = false
- }
-
+ when (startAfterSuppression) {
VoiceCaptureMode.ManualMic -> {
- talkMode.ttsOnAllResponses = false
- talkMode.stopAllCapture()
- NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.ManualMic)
- if (persistManualMic) {
- prefs.setVoiceMicEnabled(true)
+ if (_voiceCaptureMode.value == VoiceCaptureMode.ManualMic && externalAudioCaptureActive.value) {
+ micCapture.setMicEnabled(true)
}
- // Tapping mic on interrupts any active TTS (barge-in).
- stopVoicePlayback()
- scope.launch { talkMode.refreshConfig() }
- micCapture.setMicEnabled(true)
- externalAudioCaptureActive.value = true
}
-
VoiceCaptureMode.TalkMode -> {
- if (persistManualMic) {
- prefs.setVoiceMicEnabled(false)
+ if (_voiceCaptureMode.value == VoiceCaptureMode.TalkMode && externalAudioCaptureActive.value) {
+ talkMode.setEnabled(true)
}
- micCapture.setMicEnabled(false)
- NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.TalkMode)
- talkMode.ttsOnAllResponses = true
- talkMode.setPlaybackEnabled(speakerEnabled.value)
- scope.launch { talkMode.refreshConfig() }
- talkMode.stopAllCapture()
- talkMode.setEnabled(true)
- externalAudioCaptureActive.value = true
}
+ VoiceCaptureMode.Off,
+ null,
+ -> Unit
}
}
}
@@ -3051,21 +3264,100 @@ class NodeRuntime private constructor(
}
private fun stopActiveVoiceSession() {
- synchronized(voiceCaptureOwnershipLock) {
- talkPttCommandEpoch.incrementAndGet()
- voiceCaptureOwnershipEpoch.incrementAndGet()
- talkPttOwnership.set(null)
- talkMode.ttsOnAllResponses = false
- talkMode.stopAllCapture()
- stopVoicePlayback()
- micCapture.setMicEnabled(false)
- prefs.setVoiceMicEnabled(false)
- NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
- _voiceCaptureMode.value = VoiceCaptureMode.Off
- externalAudioCaptureActive.value = false
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ talkPttCommandEpoch.incrementAndGet()
+ voiceCaptureOwnershipEpoch.incrementAndGet()
+ talkPttOwnership.set(null)
+ talkMode.ttsOnAllResponses = false
+ talkMode.stopAllCapture()
+ stopVoicePlayback()
+ micCapture.setMicEnabled(false)
+ prefs.setVoiceMicEnabled(false)
+ NodeForegroundService.setVoiceCaptureMode(appContext, VoiceCaptureMode.Off)
+ _voiceCaptureMode.value = VoiceCaptureMode.Off
+ setExternalAudioCaptureActiveLocked(false)
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
+ }
+
+ private fun setExternalAudioCaptureActiveLocked(active: Boolean): VoiceWakeSuppressionUpdate {
+ externalAudioCaptureActive.value = active
+ return createVoiceCaptureSuppressionUpdateLocked()
+ }
+
+ internal fun setCameraAudioCaptureActive(active: Boolean): Boolean {
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ if (active) {
+ if (cameraAudioOwnsMic || voiceNoteOwnsMic || !isVoiceCaptureModeActive(VoiceCaptureMode.Off)) {
+ return false
+ }
+ cameraAudioOwnsMic = true
+ } else {
+ cameraAudioOwnsMic = false
+ }
+ createVoiceWakeSuppressionUpdateLocked(VoiceWakeSuppressionReason.Camera, active)
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
+ return true
+ }
+
+ private fun acquireVoiceReplySpeechSuppression() {
+ if (voiceReplySpeechDepth.incrementAndGet() == 1) {
+ voiceWakeManager.setSuppressed(VoiceWakeSuppressionReason.VoiceReplySpeech, true)
}
}
+ private fun releaseVoiceReplySpeechSuppression() {
+ while (true) {
+ val depth = voiceReplySpeechDepth.get()
+ if (depth == 0) return
+ if (!voiceReplySpeechDepth.compareAndSet(depth, depth - 1)) continue
+ if (depth == 1) {
+ voiceWakeManager.setSuppressed(VoiceWakeSuppressionReason.VoiceReplySpeech, false)
+ }
+ return
+ }
+ }
+
+ private fun reconcileVoiceWakeCaptureSuppression() {
+ val suppressionUpdate =
+ synchronized(voiceCaptureOwnershipLock) {
+ createVoiceCaptureSuppressionUpdateLocked()
+ }
+ applyVoiceWakeSuppression(suppressionUpdate)
+ }
+
+ private fun createVoiceCaptureSuppressionUpdateLocked(): VoiceWakeSuppressionUpdate =
+ createVoiceWakeSuppressionUpdateLocked(
+ reason = VoiceWakeSuppressionReason.VoiceCapture,
+ suppressed = externalAudioCaptureActive.value || micCapture.micCooldown.value,
+ )
+
+ private fun createVoiceWakeSuppressionUpdateLocked(
+ reason: VoiceWakeSuppressionReason,
+ suppressed: Boolean,
+ ): VoiceWakeSuppressionUpdate {
+ voiceWakeSuppressionRevision += 1
+ return VoiceWakeSuppressionUpdate(
+ reason = reason,
+ suppressed = suppressed,
+ revision = voiceWakeSuppressionRevision,
+ )
+ }
+
+ private fun applyVoiceWakeSuppression(update: VoiceWakeSuppressionUpdate?) {
+ if (update == null) return
+ // Versioned application happens after ownership unlock. This avoids a main
+ // looper lock inversion while preventing an older release from winning.
+ voiceWakeManager.setSuppressed(
+ reason = update.reason,
+ suppressed = update.suppressed,
+ revision = update.revision,
+ )
+ }
+
private fun stopVoicePlayback() {
talkMode.stopTts()
if (voiceReplySpeakerLazy.isInitialized()) {
@@ -3079,8 +3371,10 @@ class NodeRuntime private constructor(
private fun isVoiceCaptureModeActive(mode: VoiceCaptureMode): Boolean =
when (mode) {
VoiceCaptureMode.Off ->
- !externalAudioCaptureActive.value &&
+ !cameraAudioOwnsMic &&
+ !externalAudioCaptureActive.value &&
!micCapture.micEnabled.value &&
+ !micCapture.micCooldown.value &&
!talkMode.isEnabled.value &&
talkMode.activePushToTalkCaptureId == null
VoiceCaptureMode.ManualMic ->
@@ -3642,6 +3936,7 @@ class NodeRuntime private constructor(
gatewayDataGeneration += 1
clearOperatorGatewayState(retirePendingCronRuns = true)
}
+ invalidateVoiceWakeWordsForGateway()
chat.onGatewayScopeChanging(retireRunState)
stopMessageSpeech()
micCapture.onGatewayScopeChanging()
@@ -3888,12 +4183,139 @@ class NodeRuntime private constructor(
if (event == "update.available") {
_gatewayUpdateAvailable.value = parseGatewayUpdateAvailable(payloadJson)
}
+ if (event == GatewayEvent.VoicewakeChanged.rawValue) {
+ applyVoiceWakeWords(payloadJson)
+ }
handleExecApprovalGatewayEvent(event = event, payloadJson = payloadJson)
micCapture.handleGatewayEvent(event, payloadJson)
talkMode.handleGatewayEvent(event, payloadJson)
chat.handleGatewayEvent(event, payloadJson)
}
+ private fun handleNodeGatewayEvent(
+ event: String,
+ payloadJson: String?,
+ ) {
+ if (event != GatewayEvent.VoicewakeChanged.rawValue) return
+ val endpointStableId = nodeSession.currentEndpointStableId() ?: return
+ applyNodeVoiceWakeWords(endpointStableId, payloadJson) {
+ nodeSession.currentEndpointStableId() == endpointStableId
+ }
+ }
+
+ internal fun applyNodeVoiceWakeWords(
+ endpointStableId: String,
+ payloadJson: String?,
+ isCurrentConnection: () -> Boolean,
+ ) {
+ val gatewayScope = captureGatewayDataScope()?.takeIf { it.stableId == endpointStableId } ?: return
+ val words = parseVoiceWakeWords(payloadJson) ?: return
+ var applied = false
+ publishGatewayData(gatewayScope) {
+ if (isCurrentConnection()) {
+ applied = applyAuthoritativeVoiceWakeWords(words, gatewayStableId = gatewayScope.stableId)
+ }
+ }
+ if (applied) resumeVoiceWakeAfterGatewayWords(gatewayScope)
+ }
+
+ private suspend fun refreshWakeWordsFromGateway() {
+ val gatewayScope = captureGatewayDataScope() ?: return
+ val requestRevision = currentVoiceWakeWordsRevision()
+ try {
+ val words = parseVoiceWakeWords(requestGatewayData(gatewayScope, GatewayMethod.VoicewakeGet.rawValue, "{}")) ?: return
+ var applied = false
+ publishGatewayData(gatewayScope) {
+ applied =
+ applyAuthoritativeVoiceWakeWords(
+ words = words,
+ gatewayStableId = gatewayScope.stableId,
+ expectedRevision = requestRevision,
+ )
+ }
+ if (applied) resumeVoiceWakeAfterGatewayWords(gatewayScope)
+ } catch (_: CancellationException) {
+ // A replacement Gateway owns the next refresh.
+ } catch (err: Throwable) {
+ Log.d("OpenClawRuntime", "voicewake.get failed: ${err.message ?: err::class.java.simpleName}")
+ }
+ }
+
+ private fun applyVoiceWakeWords(payloadJson: String?) {
+ val gatewayScope = captureGatewayDataScope() ?: return
+ val words = parseVoiceWakeWords(payloadJson) ?: return
+ var applied = false
+ publishGatewayData(gatewayScope) {
+ applied = applyAuthoritativeVoiceWakeWords(words, gatewayStableId = gatewayScope.stableId)
+ }
+ if (applied) resumeVoiceWakeAfterGatewayWords(gatewayScope)
+ }
+
+ private fun currentVoiceWakeWordsRevision(): Long = synchronized(voiceWakeWordsLock) { voiceWakeWordsRevision }
+
+ private fun applyAuthoritativeVoiceWakeWords(
+ words: List,
+ gatewayStableId: String,
+ expectedRevision: Long? = null,
+ ): Boolean =
+ synchronized(voiceWakeWordsLock) {
+ if (expectedRevision != null && expectedRevision != voiceWakeWordsRevision) return@synchronized false
+ voiceWakeWordsRevision += 1
+ voiceWakeWordsGatewayStableId = gatewayStableId
+ prefs.setVoiceWakeWords(words)
+ voiceWakeManager.updateTriggerWords(words)
+ true
+ }
+
+ private fun invalidateVoiceWakeWordsForGateway() {
+ synchronized(voiceWakeWordsLock) {
+ voiceWakeWordsRevision += 1
+ voiceWakeWordsGatewayStableId = null
+ prefs.setVoiceWakeWords(VoiceWakePreferences.defaultTriggerWords)
+ voiceWakeManager.updateTriggerWords(VoiceWakePreferences.defaultTriggerWords)
+ }
+ voiceWakeManager.setSuppressed(VoiceWakeSuppressionReason.GatewaySync, true)
+ refreshVoiceWakeCapabilitySurfaceIfChanged()
+ }
+
+ private fun resumeVoiceWakeAfterGatewayWords(gatewayScope: GatewayDataScope) {
+ if (!isGatewayDataScopeCurrent(gatewayScope) || !isVoiceWakeWordsReadyFor(gatewayScope.stableId)) return
+ voiceWakeManager.setSuppressed(VoiceWakeSuppressionReason.GatewaySync, false)
+ refreshVoiceWakeCapabilitySurfaceIfChanged()
+ }
+
+ private fun isVoiceWakeWordsReadyForCurrentGateway(): Boolean = connectedEndpoint?.stableId?.let(::isVoiceWakeWordsReadyFor) == true
+
+ private fun isVoiceWakeWordsReadyFor(gatewayStableId: String): Boolean = synchronized(voiceWakeWordsLock) { voiceWakeWordsGatewayStableId == gatewayStableId }
+
+ private fun parseVoiceWakeWords(payloadJson: String?): List? =
+ runCatching {
+ payloadJson
+ ?.let(json::parseToJsonElement)
+ ?.asObjectOrNull()
+ ?.get("triggers")
+ ?.let { it as? JsonArray }
+ ?.mapNotNull { it.asStringOrNull() }
+ ?.let(VoiceWakePreferences::sanitizeTriggerWords)
+ }.getOrNull()
+
+ private suspend fun sendVoiceWakeCommand(match: VoiceWakeMatch): Boolean {
+ val gatewayId = connectedEndpoint?.stableId ?: return false
+ if (!isVoiceWakeWordsReadyFor(gatewayId)) return false
+ if (!_nodeConnected.value) return false
+ val payload =
+ buildJsonObject {
+ put("eventId", JsonPrimitive(UUID.randomUUID().toString()))
+ put("text", JsonPrimitive(match.command))
+ put("sessionKey", JsonPrimitive(resolveMainSessionKey()))
+ }
+ return nodeSession.sendNodeEventForEndpoint(
+ expectedEndpointStableId = gatewayId,
+ event = "voice.transcript",
+ payloadJson = payload.toString(),
+ )
+ }
+
private fun handleExecApprovalGatewayEvent(
event: String,
payloadJson: String?,
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/SecurePrefs.kt b/apps/android/app/src/main/java/ai/openclaw/app/SecurePrefs.kt
index a99b25f8f3de..6d73082e010b 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/SecurePrefs.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/SecurePrefs.kt
@@ -5,6 +5,7 @@ package ai.openclaw.app
import ai.openclaw.app.gateway.GatewayCustomHeaders
import ai.openclaw.app.gateway.GatewayRegistryStore
import ai.openclaw.app.gateway.GatewayStoreMigration
+import ai.openclaw.app.voice.VoiceWakePreferences
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
@@ -63,6 +64,8 @@ class SecurePrefs(
private const val currentInstalledAppsDisclosureConsentVersion = 1
private const val cameraEnabledKey = "camera.enabled"
private const val voiceMicEnabledKey = "voice.micEnabled"
+ private const val voiceWakeEnabledKey = "voiceWake.enabled"
+ private const val voiceWakeWordsKey = "voiceWake.triggerWords"
private const val appearanceThemeModeKey = "appearance.themeMode"
private const val chatModelFavoritesKey = "chat.modelFavorites"
private const val chatModelRecentsKey = "chat.modelRecents"
@@ -198,6 +201,12 @@ class SecurePrefs(
private val _voiceMicEnabled = MutableStateFlow(plainPrefs.getBoolean(voiceMicEnabledKey, false))
val voiceMicEnabled: StateFlow = _voiceMicEnabled
+ private val _voiceWakeEnabled = MutableStateFlow(plainPrefs.getBoolean(voiceWakeEnabledKey, false))
+ val voiceWakeEnabled: StateFlow = _voiceWakeEnabled
+
+ private val _voiceWakeWords = MutableStateFlow(loadVoiceWakeWords())
+ val voiceWakeWords: StateFlow> = _voiceWakeWords
+
private val _speakerEnabled = MutableStateFlow(plainPrefs.getBoolean("voice.speakerEnabled", true))
val speakerEnabled: StateFlow = _speakerEnabled
@@ -621,11 +630,32 @@ class SecurePrefs(
_voiceMicEnabled.value = value
}
+ fun setVoiceWakeEnabled(value: Boolean) {
+ plainPrefs.edit { putBoolean(voiceWakeEnabledKey, value) }
+ _voiceWakeEnabled.value = value
+ }
+
+ fun setVoiceWakeWords(words: List) {
+ val sanitized = VoiceWakePreferences.sanitizeTriggerWords(words)
+ plainPrefs.edit { putString(voiceWakeWordsKey, JsonArray(sanitized.map(::JsonPrimitive)).toString()) }
+ _voiceWakeWords.value = sanitized
+ }
+
fun setSpeakerEnabled(value: Boolean) {
plainPrefs.edit { putBoolean("voice.speakerEnabled", value) }
_speakerEnabled.value = value
}
+ private fun loadVoiceWakeWords(): List {
+ val stored = plainPrefs.getString(voiceWakeWordsKey, null) ?: return VoiceWakePreferences.defaultTriggerWords
+ val decoded =
+ runCatching {
+ (json.parseToJsonElement(stored) as? JsonArray)
+ ?.mapNotNull { (it as? JsonPrimitive)?.content }
+ }.getOrNull()
+ return VoiceWakePreferences.sanitizeTriggerWords(decoded.orEmpty())
+ }
+
fun setAppearanceThemeMode(mode: AppearanceThemeMode) {
plainPrefs.edit { putString(appearanceThemeModeKey, mode.rawValue) }
_appearanceThemeMode.value = mode
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt b/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt
index 44796bc8e177..08d64bba4708 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt
@@ -377,6 +377,9 @@ class GatewaySession(
internal fun isReady(): Boolean = readyConnection() != null
+ /** Current physical connection identity, including events sent during connect publication. */
+ internal fun currentEndpointStableId(): String? = currentConnection?.endpoint?.stableId
+
/** Sends a best-effort node.event and returns false instead of throwing on failure. */
suspend fun sendNodeEvent(
event: String,
@@ -411,6 +414,9 @@ class GatewaySession(
NodeEventSendOutcome.COMPLETED
} catch (_: GatewayRequestNotEnqueued) {
NodeEventSendOutcome.DISCONNECTED
+ } catch (err: CancellationException) {
+ // Voice/audio ownership takeover must cancel before a stale node event dispatches.
+ throw err
} catch (err: Throwable) {
Log.w("OpenClawGateway", "node.event failed: ${err::class.java.simpleName}")
NodeEventSendOutcome.FAILED
@@ -1251,6 +1257,8 @@ class GatewaySession(
}
return
}
+ // Retired sockets can still drain queued frames after reconnect. Never let them mutate current state.
+ if (currentConnection !== this) return
if (event == GatewayEvent.NodeInvokeRequest.rawValue && payloadJson != null && onInvoke != null) {
handleInvokeEvent(payloadJson)
return
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt b/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt
index e72af0c22736..ee504a07a98f 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/i18n/NativeStringResources.kt
@@ -115,6 +115,8 @@ internal val nativeStringResourceIds: Map =
"Active on this phone" to R.string.native_4cb394d648628e4d,
"Adaptive" to R.string.native_ceb6931ea57cc999,
"Add Gateway" to R.string.native_1a6b66544dcfe305,
+ "Add one wake word or phrase per field. Then say one before your command." to R.string.native_4aaa122fbdf16bac,
+ "Add wake phrase" to R.string.native_d8cb9e6d596bcb9d,
"Address" to R.string.native_56ef8f20955f2564,
"Admin" to R.string.native_c1c224b03cd9bc7b,
"Admin access required" to R.string.native_812fc837108361ba,
@@ -279,7 +281,7 @@ internal val nativeStringResourceIds: Map =
"Computer" to R.string.native_76ed42d22129dc35,
"Configure \${issue.providerLabel} on the Gateway" to R.string.native_f616dfac9815faea,
"Configure a \${issue.target.title} provider on the Gateway" to R.string.native_2bc8446b79ad43f2,
- "Configure voice, transport, and playback." to R.string.native_14d9bf289ff83113,
+ "Configure wake words, talk, and playback." to R.string.native_046cd59be9d4d081,
"Configured" to R.string.native_84aebc69a1bf739a,
"Connect" to R.string.native_1a2303ede07493ac,
"Connect Gateway" to R.string.native_d2e4d963ab64f29d,
@@ -310,6 +312,7 @@ internal val nativeStringResourceIds: Map =
"Connect the gateway to update Skill Workshop proposals." to R.string.native_db259fef5236a070,
"Connect the gateway to update skills." to R.string.native_769b53f3940fb9bd,
"Connect to a Gateway to load Skill Workshop proposals." to R.string.native_0ab0e1629576aecf,
+ "Connect to a Gateway to save wake words" to R.string.native_721ca8245ae89272,
"Connect to load your agents" to R.string.native_708b993dc20bf618,
"Connect to your Gateway" to R.string.native_262c897a1f408b0b,
"Connect to your gateway to open a shell in the agent workspace." to R.string.native_3d61e9d54ffa2d93,
@@ -370,6 +373,7 @@ internal val nativeStringResourceIds: Map =
"Could not read a QR code from that image. Choose a clearer image or enter the setup code manually." to R.string.native_e3f0caab85e62600,
"Could not read that image. Choose a clear screenshot or image of the QR from openclaw qr." to R.string.native_06ee275ccdbbf862,
"Could not resolve approval. Refresh and try again." to R.string.native_d93e2b7a15efbc1e,
+ "Could not save wake words" to R.string.native_6571f3b12432693a,
"Could not search ClawHub skills." to R.string.native_fcea13c79c2f85a6,
"Could not stage an attachment for sending." to R.string.native_002a6fcb30b2def4,
"Could not start the camera. Choose a QR image from gallery or enter the setup code manually." to R.string.native_abd1b2fa48abb83a,
@@ -414,6 +418,7 @@ internal val nativeStringResourceIds: Map =
"Details copied" to R.string.native_e2acabb2202be941,
"Device access; Gateway opt-in still required" to R.string.native_d10fc6ed5d221f2a,
"Device identity required" to R.string.native_2c9cce8250d746e3,
+ "Device language not supported" to R.string.native_7bac819e2197030d,
"Device name" to R.string.native_155106be1173d757,
"Devices" to R.string.native_4ba5121d4d1be174,
"Diagnose" to R.string.native_64dd65edfeaabd10,
@@ -534,6 +539,7 @@ internal val nativeStringResourceIds: Map =
"Gateway token is required. Enter it again or edit this connection." to R.string.native_0e21c3fd2dee2f6f,
"Gateway token needed" to R.string.native_b2d672f21eed539a,
"Gateway token not configured" to R.string.native_abb34924b54b502e,
+ "Gateway unavailable" to R.string.native_9b797864ba532a10,
"Gateway unreachable" to R.string.native_3a1f56623c408220,
"Gateway, voice, notifications, privacy" to R.string.native_f3753c0fe29b88db,
"Gateways" to R.string.native_9e4635769f0aaf0d,
@@ -592,6 +598,7 @@ internal val nativeStringResourceIds: Map =
"Last Error" to R.string.native_3fb8bbabfcedb87c,
"Last Run" to R.string.native_9c05e80faaf8a6c1,
"Last Status" to R.string.native_d68b1f4cc56c9546,
+ "Last command: \$command" to R.string.native_1c1174c05c1e6582,
"Layout: Compact" to R.string.native_619837a134285528,
"Layout: Detailed" to R.string.native_f2cb21c53a33f72c,
"Level" to R.string.native_1709305c9fa966d1,
@@ -601,6 +608,7 @@ internal val nativeStringResourceIds: Map =
"Linked" to R.string.native_bfda026e6c598dde,
"Linked phones and node hosts will appear here after pairing." to R.string.native_be969becb173e0c5,
"Listen" to R.string.native_225d29f6201e1a63,
+ "Listen for wake words" to R.string.native_695c03727ff0251f,
"Listening" to R.string.native_49c4605816cfbf30,
"Listening (PTT)" to R.string.native_049579fa8efbaa1b,
"Listening for one turn" to R.string.native_744883c7eb649f92,
@@ -775,6 +783,9 @@ internal val nativeStringResourceIds: Map =
"On" to R.string.native_130011756125313c,
"On command exit" to R.string.native_6386ffec7ad722df,
"On the Gateway computer, run:" to R.string.native_8cb2bab2ce6a17b2,
+ "On-device language model unavailable" to R.string.native_5a6db2a878731e8b,
+ "On-device speech recognition is unavailable." to R.string.native_40d04f6fb9437ff3,
+ "On-device speech recognition unavailable" to R.string.native_5542bc6a5f3ae4da,
"One time" to R.string.native_3043615848685c0d,
"Online" to R.string.native_0d21bd52022ca7f7,
"Online and ready" to R.string.native_92d01b120cacf65f,
@@ -852,6 +863,7 @@ internal val nativeStringResourceIds: Map =
"Paste setup code" to R.string.native_5ed0f26cd35a6420,
"Paste token" to R.string.native_67fa416afa64d304,
"Paused" to R.string.native_e159b06187d369a0,
+ "Pauses during other voice activity." to R.string.native_5e0e22c0a64f6823,
"Payload" to R.string.native_99733344956dde48,
"Payload Text" to R.string.native_37053dc1f680546b,
"Payload · \${cronPayloadKindLabel(payload)}" to R.string.native_f4cc820d308495c4,
@@ -952,6 +964,7 @@ internal val nativeStringResourceIds: Map =
"Remove attachment" to R.string.native_595b066a8838734a,
"Remove from group" to R.string.native_035edd9bd720fa18,
"Remove this automation after a successful one-shot run." to R.string.native_604e6d6faf8d0295,
+ "Remove wake phrase" to R.string.native_de2ae3a91cd112dd,
"Rename" to R.string.native_3064d79a295cefe4,
"Rename group" to R.string.native_98d254a311d0e820,
"Rename group…" to R.string.native_fe4e8d175e15f0a2,
@@ -990,14 +1003,17 @@ internal val nativeStringResourceIds: Map =
"Running Since" to R.string.native_6e8a74ada297ff53,
"Running tools..." to R.string.native_7cc20d4753b8fd45,
"Runs" to R.string.native_848f54e89660cea4,
+ "Runs on-device while OpenClaw is visible." to R.string.native_83e2faed20a3cda4,
"Runtime" to R.string.native_1093115897879aa3,
"SMS" to R.string.native_40b601a10ca536c1,
"Save & Connect" to R.string.native_a2f29836cda5ceb1,
"Save Changes" to R.string.native_35322b5bb5a218a1,
"Save Profile" to R.string.native_a4212f1e2fb0f506,
"Save or revert your edits before running, enabling, disabling, deleting, or refreshing this automation." to R.string.native_4c09c146861e92a9,
+ "Save wake words" to R.string.native_b8b90581b766682d,
"Saved auth invalid" to R.string.native_b860c709e9ba7e6f,
"Saved authentication is invalid. Re-authenticate or reset this gateway connection." to R.string.native_4408aaecc2b1470d,
+ "Saving…" to R.string.native_23e39291d6135814,
"Scan QR" to R.string.native_5a99f6fa7e98657a,
"Scan QR code" to R.string.native_e5c7478bbce26eb7,
"Scan QR or setup code" to R.string.native_8703f3dea42d2831,
@@ -1222,6 +1238,7 @@ internal val nativeStringResourceIds: Map =
"Transcription failed: \$message" to R.string.native_de67b9369f9812ea,
"Transcription unavailable: \$message" to R.string.native_1a9e3989a89e862b,
"Transcripts" to R.string.native_f584049cab5f523e,
+ "Triggered" to R.string.native_aeffb9182e3d7f3d,
"Trust" to R.string.native_ade9248e0132b411,
"Try Chat, Voice, Sessions, Providers, or Settings." to R.string.native_3d013d4e9cf973f9,
"Try a different search or clear the current query." to R.string.native_fa664b09af472ec4,
@@ -1267,6 +1284,7 @@ internal val nativeStringResourceIds: Map =
"View all" to R.string.native_30a64216eaeac5d3,
"View details" to R.string.native_d1bf045bb524dae5,
"Voice" to R.string.native_87bf2bc08589f0bd,
+ "Voice Wake" to R.string.native_666c8bc0319f3b54,
"Voice note" to R.string.native_8f54b0d1e30092d5,
"Voice note · \${formatVoiceNoteDuration(duration)}" to R.string.native_8d57374bc09c8756,
"Voice reply timed out; retrying queued turn" to R.string.native_f2bfed0b0c0055db,
@@ -1280,6 +1298,10 @@ internal val nativeStringResourceIds: Map =
"Waiting for pairing" to R.string.native_9193a6bd2430c6df,
"Waiting for review" to R.string.native_a61935d6be7b9f04,
"Wake Mode" to R.string.native_1e432ea5425e4a3a,
+ "Wake listener" to R.string.native_c156b9eaf502aabc,
+ "Wake word or phrase" to R.string.native_18f6e5973bc41268,
+ "Wake words" to R.string.native_f5f0563199a5b403,
+ "Wake words saved" to R.string.native_6e2c0963d056e104,
"We could not reach your Gateway.\nLet's fix this." to R.string.native_ed39201623824f4c,
"Web Fetch" to R.string.native_5c1acea9c9b0e704,
"Web Search" to R.string.native_d04fc7d7e19702f8,
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/node/CameraHandler.kt b/apps/android/app/src/main/java/ai/openclaw/app/node/CameraHandler.kt
index 7b2bb746ae0c..b36151617489 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/node/CameraHandler.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/node/CameraHandler.kt
@@ -6,7 +6,6 @@ import ai.openclaw.app.gateway.GatewaySession
import android.content.Context
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonArray
@@ -26,7 +25,7 @@ internal fun isCameraClipWithinPayloadLimit(rawBytes: Long): Boolean = rawBytes
class CameraHandler(
private val appContext: Context,
private val camera: CameraCaptureManager,
- private val externalAudioCaptureActive: MutableStateFlow,
+ private val setCameraAudioCaptureActive: (Boolean) -> Boolean,
private val showCameraHud: (message: String, kind: CameraHudKind, autoHideMs: Long?) -> Unit,
private val invokeErrorFromThrowable: (err: Throwable) -> Pair,
) {
@@ -113,7 +112,13 @@ class CameraHandler(
android.util.Log.w("openclaw", "camera.clip: $msg")
}
val includeAudio = parseIncludeAudio(paramsJson) ?: true
- if (includeAudio) externalAudioCaptureActive.value = true
+ val ownsAudioCapture = includeAudio && setCameraAudioCaptureActive(true)
+ if (includeAudio && !ownsAudioCapture) {
+ return GatewaySession.InvokeResult.error(
+ code = "MIC_BUSY",
+ message = "MIC_BUSY: another audio capture is active",
+ )
+ }
try {
clipLogFile?.writeText("") // clear
clipLog("starting, params=$paramsJson includeAudio=$includeAudio")
@@ -169,7 +174,7 @@ class CameraHandler(
return GatewaySession.InvokeResult.error(code = "UNAVAILABLE", message = err.message ?: "camera clip failed")
} finally {
// Prevent talk/transcription capture from competing with camera audio after every exit path.
- if (includeAudio) externalAudioCaptureActive.value = false
+ if (ownsAudioCapture) setCameraAudioCaptureActive(false)
}
}
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/node/ConnectionManager.kt b/apps/android/app/src/main/java/ai/openclaw/app/node/ConnectionManager.kt
index 9ced069ea5cf..d29f6da0e222 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/node/ConnectionManager.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/node/ConnectionManager.kt
@@ -26,6 +26,7 @@ class ConnectionManager(
private val callLogAvailable: () -> Boolean,
private val photosAvailable: () -> Boolean,
private val installedAppsSharingEnabled: () -> Boolean,
+ private val voiceWakeAvailable: () -> Boolean,
private val manualTls: (GatewayEndpoint) -> Boolean,
) {
companion object {
@@ -141,6 +142,7 @@ class ConnectionManager(
motionPedometerAvailable = motionPedometerAvailable(),
installedAppsSharingEnabled = installedAppsSharingEnabled(),
debugBuild = BuildConfig.DEBUG,
+ voiceWakeEnabled = prefs.voiceWakeEnabled.value && voiceWakeAvailable(),
)
/** Builds the gateway-advertised node.invoke command list from current permission and feature state. */
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/node/InvokeCommandRegistry.kt b/apps/android/app/src/main/java/ai/openclaw/app/node/InvokeCommandRegistry.kt
index 725cb3bf78c9..9b6f01478c39 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/node/InvokeCommandRegistry.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/node/InvokeCommandRegistry.kt
@@ -29,6 +29,7 @@ data class NodeRuntimeFlags(
val motionPedometerAvailable: Boolean,
val installedAppsSharingEnabled: Boolean,
val debugBuild: Boolean,
+ val voiceWakeEnabled: Boolean = false,
)
/** Per-command availability gates checked before advertising invoke methods. */
@@ -56,6 +57,7 @@ enum class NodeCapabilityAvailability {
CallLogAvailable,
PhotosAvailable,
MotionAvailable,
+ VoiceWakeEnabled,
}
/** Capability entry reported to the gateway when its availability gate passes. */
@@ -106,6 +108,10 @@ object InvokeCommandRegistry {
name = OpenClawCapability.CallLog.rawValue,
availability = NodeCapabilityAvailability.CallLogAvailable,
),
+ NodeCapabilitySpec(
+ name = OpenClawCapability.VoiceWake.rawValue,
+ availability = NodeCapabilityAvailability.VoiceWakeEnabled,
+ ),
)
/** Complete Android node command catalog before runtime availability filtering. */
@@ -263,6 +269,7 @@ object InvokeCommandRegistry {
NodeCapabilityAvailability.CallLogAvailable -> flags.callLogAvailable
NodeCapabilityAvailability.PhotosAvailable -> flags.photosAvailable
NodeCapabilityAvailability.MotionAvailable -> flags.motionActivityAvailable || flags.motionPedometerAvailable
+ NodeCapabilityAvailability.VoiceWakeEnabled -> flags.voiceWakeEnabled
}
}.map { it.name }
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt b/apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt
index af03ecbac801..7e2aa751ac32 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/protocol/OpenClawProtocolConstants.kt
@@ -17,6 +17,7 @@ enum class OpenClawCapability(
Calendar("calendar"),
Motion("motion"),
CallLog("callLog"),
+ VoiceWake("voiceWake"),
}
enum class OpenClawCanvasCommand(
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt
index 9fe879c31564..ffdb5b991c92 100644
--- a/apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt
+++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/SettingsScreens.kt
@@ -64,6 +64,7 @@ import ai.openclaw.app.ui.design.OpenClawMascot
import ai.openclaw.app.ui.design.TalkWaveform
import ai.openclaw.app.ui.design.TalkWaveformPhase
import ai.openclaw.app.ui.design.agentAvatarSource
+import ai.openclaw.app.voice.VoiceWakePreferences
import android.Manifest
import android.content.ClipData
import android.content.ClipboardManager
@@ -110,12 +111,14 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.automirrored.filled.OpenInNew
import androidx.compose.material.icons.automirrored.filled.ScreenShare
import androidx.compose.material.icons.automirrored.filled.VolumeUp
+import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Bolt
import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Cloud
import androidx.compose.material.icons.filled.ContentCopy
+import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.GraphicEq
import androidx.compose.material.icons.filled.Image
import androidx.compose.material.icons.filled.Info
@@ -659,16 +662,126 @@ private fun VoiceSettingsScreen(
viewModel: MainViewModel,
onBack: () -> Unit,
) {
+ val context = LocalContext.current
val speakerEnabled by viewModel.speakerEnabled.collectAsState()
val isConnected by viewModel.isConnected.collectAsState()
val talkSetupReadiness by viewModel.talkSetupReadiness.collectAsState()
+ val voiceWakeEnabled by viewModel.voiceWakeEnabled.collectAsState()
+ val voiceWakeAvailable by viewModel.voiceWakeAvailable.collectAsState()
+ val voiceWakeIsListening by viewModel.voiceWakeIsListening.collectAsState()
+ val voiceWakeStatusText by viewModel.voiceWakeStatusText.collectAsState()
+ val voiceWakeWords by viewModel.voiceWakeWords.collectAsState()
+ val voiceWakeLastCommand by viewModel.voiceWakeLastTriggeredCommand.collectAsState()
+ val voiceWakeWordsSaving by viewModel.voiceWakeWordsSaving.collectAsState()
+ val voiceWakeWordsNoticeText by viewModel.voiceWakeWordsNoticeText.collectAsState()
+ var wakeWordDrafts by remember(voiceWakeWords) {
+ mutableStateOf(voiceWakeWords)
+ }
+
+ val microphonePermissionLauncher =
+ rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
+ viewModel.refreshVoiceWakePermission()
+ if (granted) viewModel.setVoiceWakeEnabled(true)
+ }
+
+ fun setVoiceWake(checked: Boolean) {
+ if (!checked) {
+ viewModel.setVoiceWakeEnabled(false)
+ } else if (hasPermission(context, Manifest.permission.RECORD_AUDIO)) {
+ viewModel.refreshVoiceWakePermission()
+ viewModel.setVoiceWakeEnabled(true)
+ } else {
+ microphonePermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
+ }
+ }
LaunchedEffect(isConnected) {
if (isConnected) viewModel.refreshTalkSetupReadiness()
}
- SettingsDetailFrame(title = nativeString("Talk Provider Setup"), subtitle = nativeString("Configure voice, transport, and playback."), icon = Icons.Default.Mic, onBack = onBack) {
+ SettingsDetailFrame(title = nativeString("Voice"), subtitle = nativeString("Configure wake words, talk, and playback."), icon = Icons.Default.Mic, onBack = onBack) {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
+ Text(text = nativeString("Voice Wake"), style = ClawTheme.type.section, color = ClawTheme.colors.text)
+ SettingsTogglePanel(
+ rows =
+ listOf(
+ SettingsToggleRow(
+ title = nativeString("Listen for wake words"),
+ subtitle =
+ if (voiceWakeAvailable) {
+ nativeString("Runs on-device while OpenClaw is visible.")
+ } else {
+ nativeString("On-device speech recognition is unavailable.")
+ },
+ icon = Icons.Default.Mic,
+ checked = voiceWakeEnabled,
+ onCheckedChange = ::setVoiceWake,
+ enabled = voiceWakeAvailable || voiceWakeEnabled,
+ ),
+ ),
+ )
+ VoiceSetupActionRow(
+ title = nativeString("Wake listener"),
+ subtitle =
+ voiceWakeLastCommand?.let { command -> nativeString("Last command: \$command", command) }
+ ?: nativeString("Pauses during other voice activity."),
+ icon = Icons.Default.GraphicEq,
+ statusText = voiceWakeStatusText,
+ ready = voiceWakeIsListening,
+ )
+ ClawPanel {
+ Column(verticalArrangement = Arrangement.spacedBy(9.dp)) {
+ Text(text = nativeString("Wake words"), style = ClawTheme.type.section, color = ClawTheme.colors.text)
+ Text(
+ text = nativeString("Add one wake word or phrase per field. Then say one before your command."),
+ style = ClawTheme.type.body,
+ color = ClawTheme.colors.textMuted,
+ )
+ wakeWordDrafts.forEachIndexed { index, value ->
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ ClawTextField(
+ value = value,
+ onValueChange = { updated ->
+ wakeWordDrafts = wakeWordDrafts.toMutableList().also { it[index] = updated }
+ },
+ placeholder = nativeString("Wake word or phrase"),
+ enabled = voiceWakeAvailable && !voiceWakeWordsSaving,
+ modifier = Modifier.weight(1f),
+ )
+ if (voiceWakeAvailable && !voiceWakeWordsSaving && wakeWordDrafts.size > 1) {
+ ClawPlainIconButton(
+ icon = Icons.Default.Delete,
+ contentDescription = nativeString("Remove wake phrase"),
+ onClick = {
+ wakeWordDrafts = wakeWordDrafts.filterIndexed { draftIndex, _ -> draftIndex != index }
+ },
+ )
+ }
+ }
+ }
+ ClawSecondaryButton(
+ text = nativeString("Add wake phrase"),
+ onClick = { wakeWordDrafts = wakeWordDrafts + "" },
+ enabled = voiceWakeAvailable && !voiceWakeWordsSaving && wakeWordDrafts.size < VoiceWakePreferences.maxWords,
+ icon = Icons.Default.Add,
+ modifier = Modifier.fillMaxWidth(),
+ )
+ ClawSecondaryButton(
+ text = if (voiceWakeWordsSaving) nativeString("Saving…") else nativeString("Save wake words"),
+ onClick = { viewModel.setVoiceWakeWords(wakeWordDrafts) },
+ enabled = voiceWakeAvailable && isConnected && !voiceWakeWordsSaving && wakeWordDrafts.any(String::isNotBlank),
+ modifier = Modifier.fillMaxWidth(),
+ )
+ (voiceWakeWordsNoticeText ?: if (!isConnected) nativeString("Connect to a Gateway to save wake words") else null)?.let { notice ->
+ Text(text = notice, style = ClawTheme.type.caption, color = ClawTheme.colors.textMuted)
+ }
+ }
+ }
+ Text(text = nativeString("Talk Provider Setup"), style = ClawTheme.type.section, color = ClawTheme.colors.text)
VoiceSetupPanel(talkSetupReadiness)
Text(text = nativeString("Audio Test"), style = ClawTheme.type.section, color = ClawTheme.colors.text)
Text(text = nativeString("Check that OpenClaw can speak clearly on this phone."), style = ClawTheme.type.body, color = ClawTheme.colors.textMuted)
@@ -867,9 +980,15 @@ private fun NotificationSettingsScreen(
rows =
listOf(
SettingsToggleRow(nativeString("Forward Notifications"), if (enabled) nativeString("OpenClaw can receive selected alerts.") else nativeString("Alerts stay on this phone."), Icons.Default.Notifications, enabled, ::setForwarding),
- SettingsToggleRow(nativeString("Quiet Hours"), nativeString("\$quietStart to \$quietEnd", quietStart, quietEnd), Icons.Default.Bolt, quietEnabled) { checked ->
- viewModel.setNotificationForwardingQuietHours(enabled = checked, start = quietStart, end = quietEnd)
- },
+ SettingsToggleRow(
+ nativeString("Quiet Hours"),
+ nativeString("\$quietStart to \$quietEnd", quietStart, quietEnd),
+ Icons.Default.Bolt,
+ quietEnabled,
+ onCheckedChange = { checked ->
+ viewModel.setNotificationForwardingQuietHours(enabled = checked, start = quietStart, end = quietEnd)
+ },
+ ),
),
)
SettingsMetricPanel(
@@ -2154,6 +2273,7 @@ private data class SettingsToggleRow(
val icon: ImageVector,
val checked: Boolean,
val onCheckedChange: (Boolean) -> Unit,
+ val enabled: Boolean = true,
)
/**
@@ -2864,7 +2984,7 @@ private fun SettingsToggleListRow(row: SettingsToggleRow) {
Modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
- .clickable { row.onCheckedChange(!row.checked) }
+ .clickable(enabled = row.enabled) { row.onCheckedChange(!row.checked) }
.padding(horizontal = 10.dp, vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(9.dp),
@@ -2874,7 +2994,7 @@ private fun SettingsToggleListRow(row: SettingsToggleRow) {
Text(text = row.title, style = ClawTheme.type.body, color = ClawTheme.colors.text, maxLines = 1)
Text(text = row.subtitle, style = ClawTheme.type.caption, color = ClawTheme.colors.textMuted, maxLines = 2, overflow = TextOverflow.Ellipsis)
}
- Switch(checked = row.checked, onCheckedChange = row.onCheckedChange)
+ Switch(checked = row.checked, onCheckedChange = row.onCheckedChange, enabled = row.enabled)
}
}
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt b/apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt
new file mode 100644
index 000000000000..ad10cd79ef9e
--- /dev/null
+++ b/apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakeManager.kt
@@ -0,0 +1,544 @@
+package ai.openclaw.app.voice
+
+import ai.openclaw.app.i18n.NativeText
+import ai.openclaw.app.i18n.nativeText
+import ai.openclaw.app.i18n.resolveNativeText
+import android.Manifest
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.speech.RecognitionListener
+import android.speech.RecognizerIntent
+import android.speech.SpeechRecognizer
+import androidx.core.content.ContextCompat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import java.util.Locale
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicLong
+import java.util.concurrent.atomic.AtomicReference
+
+internal sealed interface VoiceWakeRecognitionEvent {
+ data object Ready : VoiceWakeRecognitionEvent
+
+ data class Transcript(
+ val text: String,
+ val isFinal: Boolean,
+ ) : VoiceWakeRecognitionEvent
+
+ data class Error(
+ val code: Int,
+ ) : VoiceWakeRecognitionEvent
+}
+
+internal interface VoiceWakeRecognizer {
+ val isAvailable: Boolean
+
+ fun start(
+ operationId: Long,
+ onEvent: (VoiceWakeRecognitionEvent) -> Unit,
+ )
+
+ fun stop(operationId: Long)
+
+ fun destroy(operationId: Long)
+}
+
+internal class VoiceWakeRecognitionSession(
+ private val onEvent: (VoiceWakeRecognitionEvent) -> Unit,
+) {
+ private val active = AtomicBoolean(true)
+
+ fun emit(event: VoiceWakeRecognitionEvent) {
+ if (active.get()) onEvent(event)
+ }
+
+ fun retire() {
+ active.set(false)
+ }
+}
+
+internal class AndroidOnDeviceVoiceWakeRecognizer(
+ context: Context,
+) : VoiceWakeRecognizer {
+ private val appContext = context.applicationContext
+ private val mainHandler = Handler(Looper.getMainLooper())
+ override val isAvailable: Boolean =
+ runCatching { SpeechRecognizer.isOnDeviceRecognitionAvailable(appContext) }.getOrDefault(false)
+ private val latestOperationId = AtomicLong(0)
+ private val platformOwnerOperationId = AtomicLong(0)
+ private var recognizer: SpeechRecognizer? = null
+ private var recognitionSession: VoiceWakeRecognitionSession? = null
+
+ override fun start(
+ operationId: Long,
+ onEvent: (VoiceWakeRecognitionEvent) -> Unit,
+ ) {
+ if (!claimOperation(operationId)) return
+ platformOwnerOperationId.set(operationId)
+ if (operationId != latestOperationId.get()) {
+ platformOwnerOperationId.compareAndSet(operationId, 0)
+ return
+ }
+ runOnMain {
+ if (operationId != latestOperationId.get()) {
+ platformOwnerOperationId.compareAndSet(operationId, 0)
+ return@runOnMain
+ }
+ retireRecognizer()
+ platformOwnerOperationId.set(operationId)
+ if (!isAvailable) {
+ platformOwnerOperationId.compareAndSet(operationId, 0)
+ onEvent(VoiceWakeRecognitionEvent.Error(SpeechRecognizer.ERROR_SERVER_DISCONNECTED))
+ return@runOnMain
+ }
+ val session = VoiceWakeRecognitionSession(onEvent)
+ try {
+ val active = createRecognizer(session)
+ recognitionSession = session
+ recognizer = active
+ active.startListening(recognizerIntent())
+ } catch (_: Throwable) {
+ session.retire()
+ retireRecognizer()
+ if (operationId == latestOperationId.get()) {
+ onEvent(VoiceWakeRecognitionEvent.Error(SpeechRecognizer.ERROR_CLIENT))
+ }
+ }
+ }
+ }
+
+ override fun stop(operationId: Long) {
+ if (!claimOperation(operationId)) return
+ if (platformOwnerOperationId.get() == 0L) return
+ runOnMainSync {
+ if (operationId == latestOperationId.get()) retireRecognizer()
+ }
+ }
+
+ override fun destroy(operationId: Long) {
+ if (!claimOperation(operationId)) return
+ if (platformOwnerOperationId.get() == 0L) return
+ runOnMainSync {
+ if (operationId == latestOperationId.get()) retireRecognizer()
+ }
+ }
+
+ private fun claimOperation(operationId: Long): Boolean {
+ while (true) {
+ val current = latestOperationId.get()
+ if (operationId <= current) return false
+ if (latestOperationId.compareAndSet(current, operationId)) return true
+ }
+ }
+
+ private fun createRecognizer(session: VoiceWakeRecognitionSession): SpeechRecognizer =
+ SpeechRecognizer.createOnDeviceSpeechRecognizer(appContext).also { active ->
+ active.setRecognitionListener(
+ object : RecognitionListener {
+ override fun onReadyForSpeech(params: Bundle?) {
+ session.emit(VoiceWakeRecognitionEvent.Ready)
+ }
+
+ override fun onResults(results: Bundle?) {
+ bestTranscript(results)?.let { session.emit(VoiceWakeRecognitionEvent.Transcript(it, isFinal = true)) }
+ ?: session.emit(VoiceWakeRecognitionEvent.Error(SpeechRecognizer.ERROR_NO_MATCH))
+ }
+
+ override fun onPartialResults(partialResults: Bundle?) {
+ bestTranscript(partialResults)?.let {
+ session.emit(VoiceWakeRecognitionEvent.Transcript(it, isFinal = false))
+ }
+ }
+
+ override fun onError(error: Int) {
+ session.emit(VoiceWakeRecognitionEvent.Error(error))
+ }
+
+ override fun onBeginningOfSpeech() = Unit
+
+ override fun onRmsChanged(rmsdB: Float) = Unit
+
+ override fun onBufferReceived(buffer: ByteArray?) = Unit
+
+ override fun onEndOfSpeech() = Unit
+
+ override fun onEvent(
+ eventType: Int,
+ params: Bundle?,
+ ) = Unit
+ },
+ )
+ }
+
+ private fun retireRecognizer() {
+ // Retire callback ownership before cancel/destroy. Some recognizers emit a
+ // late result or error after cancellation; it must not enter a new session.
+ recognitionSession?.retire()
+ recognitionSession = null
+ platformOwnerOperationId.set(0)
+ val active = recognizer
+ recognizer = null
+ runCatching { active?.cancel() }
+ runCatching { active?.destroy() }
+ }
+
+ private fun runOnMain(action: () -> Unit) {
+ if (Looper.myLooper() == Looper.getMainLooper()) action() else mainHandler.post(action)
+ }
+
+ private fun runOnMainSync(action: () -> Unit) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ action()
+ return
+ }
+ val completed = CountDownLatch(1)
+ val failure = AtomicReference()
+ check(
+ mainHandler.post {
+ try {
+ action()
+ } catch (err: Throwable) {
+ failure.set(err)
+ } finally {
+ completed.countDown()
+ }
+ },
+ ) { "main looper unavailable" }
+ completed.await()
+ failure.get()?.let { throw it }
+ }
+
+ private fun recognizerIntent(): Intent =
+ Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
+ putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
+ putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault().toLanguageTag())
+ putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
+ putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE, true)
+ putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3)
+ }
+
+ private fun bestTranscript(bundle: Bundle?): String? =
+ bundle
+ ?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
+ ?.firstOrNull()
+ ?.trim()
+ ?.takeIf(String::isNotEmpty)
+}
+
+internal enum class VoiceWakeSuppressionReason {
+ Camera,
+ GatewaySync,
+ VoiceCapture,
+ VoiceNote,
+ VoiceReplySpeech,
+ MessageSpeech,
+}
+
+internal class VoiceWakeManager(
+ private val context: Context,
+ private val scope: CoroutineScope,
+ private val recognizer: VoiceWakeRecognizer,
+ initialTriggerWords: List,
+ private val onCommand: suspend (VoiceWakeMatch) -> Boolean,
+ private val restartDelayMs: Long = 350L,
+ private val hasRecordAudioPermission: () -> Boolean = {
+ ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
+ },
+) {
+ private sealed interface RecognizerAction {
+ val operationId: Long
+
+ data class Start(
+ override val operationId: Long,
+ val sessionGeneration: Long,
+ ) : RecognizerAction
+
+ data class Stop(
+ override val operationId: Long,
+ ) : RecognizerAction
+
+ data class Destroy(
+ override val operationId: Long,
+ ) : RecognizerAction
+ }
+
+ private val lock = Any()
+ private var enabled = false
+ private var foreground = false
+ private var sessionGeneration = 0L
+ private var sessionActive = false
+ private var commandInFlight = false
+ private var commandJob: Job? = null
+ private var restartJob: Job? = null
+ private var recognizerOperationId = 0L
+ private val suppressionReasons = mutableSetOf()
+ private val suppressionRevisions = mutableMapOf()
+ private var triggerWords = VoiceWakePreferences.sanitizeTriggerWords(initialTriggerWords)
+
+ private val _isListening = MutableStateFlow(false)
+ val isListening: StateFlow = _isListening.asStateFlow()
+
+ private val _statusText = MutableStateFlow(nativeText("Off"))
+ val statusText: StateFlow = _statusText.resolveNativeText()
+
+ private val _lastTriggeredCommand = MutableStateFlow(null)
+ val lastTriggeredCommand: StateFlow = _lastTriggeredCommand.asStateFlow()
+
+ val isAvailable: Boolean
+ get() = recognizer.isAvailable
+
+ fun setEnabled(value: Boolean) {
+ val action =
+ synchronized(lock) {
+ enabled = value
+ reconcileLocked()
+ }
+ performRecognizerAction(action)
+ }
+
+ fun setForeground(value: Boolean) {
+ val action =
+ synchronized(lock) {
+ foreground = value
+ reconcileLocked()
+ }
+ performRecognizerAction(action)
+ }
+
+ fun setSuppressed(
+ reason: VoiceWakeSuppressionReason,
+ suppressed: Boolean,
+ revision: Long? = null,
+ ) {
+ val action =
+ synchronized(lock) {
+ if (revision != null) {
+ val currentRevision = suppressionRevisions[reason] ?: 0L
+ if (revision <= currentRevision) return
+ suppressionRevisions[reason] = revision
+ }
+ if (suppressed) suppressionReasons += reason else suppressionReasons -= reason
+ reconcileLocked()
+ }
+ performRecognizerAction(action)
+ }
+
+ fun updateTriggerWords(words: List) {
+ synchronized(lock) {
+ triggerWords = VoiceWakePreferences.sanitizeTriggerWords(words)
+ }
+ }
+
+ fun refreshPermission() {
+ val action = synchronized(lock) { reconcileLocked() }
+ performRecognizerAction(action)
+ }
+
+ fun shutdown() {
+ val action =
+ synchronized(lock) {
+ enabled = false
+ foreground = false
+ val pendingAction = stopSessionLocked(destroy = true)
+ _statusText.value = nativeText("Off")
+ pendingAction
+ }
+ performRecognizerAction(action)
+ }
+
+ private fun reconcileLocked(): RecognizerAction? {
+ val blockedStatus = blockedStatusLocked()
+ if (blockedStatus != null) {
+ val action = stopSessionLocked(destroy = !enabled || !foreground)
+ _statusText.value = blockedStatus
+ return action
+ }
+ if (!sessionActive && !commandInFlight && restartJob?.isActive != true) {
+ return startSessionLocked()
+ }
+ return null
+ }
+
+ private fun blockedStatusLocked(): NativeText? =
+ when {
+ !enabled -> nativeText("Off")
+ !recognizer.isAvailable -> nativeText("On-device speech recognition unavailable")
+ !hasRecordAudioPermission() -> nativeText("Microphone permission required")
+ !foreground || suppressionReasons.isNotEmpty() -> nativeText("Paused")
+ else -> null
+ }
+
+ private fun startSessionLocked(): RecognizerAction {
+ sessionGeneration += 1
+ val generation = sessionGeneration
+ sessionActive = true
+ _isListening.value = false
+ _statusText.value = nativeText("Starting…")
+ return RecognizerAction.Start(nextRecognizerOperationIdLocked(), generation)
+ }
+
+ private fun handleRecognitionEvent(
+ generation: Long,
+ event: VoiceWakeRecognitionEvent,
+ ) {
+ val action =
+ synchronized(lock) {
+ if (generation != sessionGeneration || !sessionActive) return
+ when (event) {
+ VoiceWakeRecognitionEvent.Ready -> {
+ _isListening.value = true
+ _statusText.value = nativeText("Listening")
+ null
+ }
+ is VoiceWakeRecognitionEvent.Transcript -> {
+ // Android partials routinely stop mid-command. Only a final transcript
+ // has the recognizer's end-of-utterance boundary and is safe to dispatch.
+ if (!event.isFinal) return
+ val transcriptAction = handleTranscriptLocked(event.text)
+ if (transcriptAction == null) {
+ sessionActive = false
+ _isListening.value = false
+ scheduleRestartLocked()
+ }
+ transcriptAction
+ }
+ is VoiceWakeRecognitionEvent.Error -> {
+ sessionActive = false
+ _isListening.value = false
+ if (event.code == SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS) {
+ _statusText.value = nativeText("Microphone permission required")
+ } else if (event.code == SpeechRecognizer.ERROR_LANGUAGE_NOT_SUPPORTED) {
+ _statusText.value = nativeText("Device language not supported")
+ } else if (event.code == SpeechRecognizer.ERROR_LANGUAGE_UNAVAILABLE) {
+ _statusText.value = nativeText("On-device language model unavailable")
+ } else {
+ scheduleRestartLocked(delayMs = retryDelayMs(event.code))
+ }
+ null
+ }
+ }
+ }
+ performRecognizerAction(action)
+ }
+
+ private fun handleTranscriptLocked(transcript: String): RecognizerAction? {
+ if (commandInFlight) return null
+ val match = VoiceWakePhraseMatcher.match(transcript, triggerWords) ?: return null
+ sessionGeneration += 1
+ val commandGeneration = sessionGeneration
+ sessionActive = false
+ commandInFlight = true
+ _isListening.value = false
+ _lastTriggeredCommand.value = match.command
+ _statusText.value = nativeText("Triggered")
+ val action = RecognizerAction.Stop(nextRecognizerOperationIdLocked())
+ commandJob =
+ scope.launch {
+ var delivered = false
+ try {
+ delivered = onCommand(match)
+ } finally {
+ synchronized(lock) {
+ if (commandGeneration == sessionGeneration) {
+ commandJob = null
+ commandInFlight = false
+ scheduleRestartLocked()
+ if (!delivered) _statusText.value = nativeText("Gateway unavailable")
+ }
+ }
+ }
+ }
+ return action
+ }
+
+ private fun scheduleRestartLocked(delayMs: Long = restartDelayMs) {
+ restartJob?.cancel()
+ val blockedStatus = blockedStatusLocked()
+ if (blockedStatus != null) {
+ _statusText.value = blockedStatus
+ return
+ }
+ _statusText.value = nativeText("Starting…")
+ restartJob =
+ scope.launch {
+ delay(delayMs)
+ val action =
+ synchronized(lock) {
+ restartJob = null
+ reconcileLocked()
+ }
+ performRecognizerAction(action)
+ }
+ }
+
+ private fun retryDelayMs(errorCode: Int): Long =
+ when (errorCode) {
+ SpeechRecognizer.ERROR_TOO_MANY_REQUESTS -> 15_000L
+ SpeechRecognizer.ERROR_RECOGNIZER_BUSY,
+ SpeechRecognizer.ERROR_SERVER,
+ SpeechRecognizer.ERROR_SERVER_DISCONNECTED,
+ SpeechRecognizer.ERROR_AUDIO,
+ SpeechRecognizer.ERROR_CLIENT,
+ -> 1_500L
+ else -> restartDelayMs
+ }
+
+ private fun stopSessionLocked(destroy: Boolean): RecognizerAction? {
+ restartJob?.cancel()
+ restartJob = null
+ commandJob?.cancel()
+ commandJob = null
+ commandInFlight = false
+ sessionGeneration += 1
+ val wasActive = sessionActive
+ sessionActive = false
+ _isListening.value = false
+ return when {
+ destroy -> RecognizerAction.Destroy(nextRecognizerOperationIdLocked())
+ wasActive -> RecognizerAction.Stop(nextRecognizerOperationIdLocked())
+ else -> null
+ }
+ }
+
+ private fun nextRecognizerOperationIdLocked(): Long {
+ recognizerOperationId += 1
+ return recognizerOperationId
+ }
+
+ private fun performRecognizerAction(action: RecognizerAction?) {
+ when (action) {
+ is RecognizerAction.Start ->
+ recognizer.start(action.operationId) { event ->
+ handleRecognitionEvent(action.sessionGeneration, event)
+ }
+ is RecognizerAction.Stop -> recognizer.stop(action.operationId)
+ is RecognizerAction.Destroy -> recognizer.destroy(action.operationId)
+ null -> Unit
+ }
+ }
+}
+
+internal class PreviewVoiceWakeRecognizer : VoiceWakeRecognizer {
+ override val isAvailable: Boolean = true
+
+ override fun start(
+ operationId: Long,
+ onEvent: (VoiceWakeRecognitionEvent) -> Unit,
+ ) {
+ onEvent(VoiceWakeRecognitionEvent.Ready)
+ }
+
+ override fun stop(operationId: Long) = Unit
+
+ override fun destroy(operationId: Long) = Unit
+}
diff --git a/apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakePreferences.kt b/apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakePreferences.kt
new file mode 100644
index 000000000000..a404eb0c107f
--- /dev/null
+++ b/apps/android/app/src/main/java/ai/openclaw/app/voice/VoiceWakePreferences.kt
@@ -0,0 +1,172 @@
+package ai.openclaw.app.voice
+
+import ai.openclaw.app.takeUtf16Safe
+
+internal object VoiceWakePreferences {
+ val defaultTriggerWords: List = listOf("openclaw", "claude", "computer")
+ const val maxWords = 32
+ const val maxWordLength = 64
+
+ fun sanitizeTriggerWords(words: List): List {
+ val cleaned =
+ words
+ .asSequence()
+ .map(String::trim)
+ .filter(String::isNotEmpty)
+ .take(maxWords)
+ .map { it.takeUtf16Safe(maxWordLength) }
+ .toList()
+ return cleaned.ifEmpty { defaultTriggerWords }
+ }
+}
+
+internal data class VoiceWakeMatch(
+ val trigger: String,
+ val command: String,
+)
+
+internal object VoiceWakePhraseMatcher {
+ private val wakePrefixFillers =
+ setOf(
+ "a",
+ "ah",
+ "eh",
+ "er",
+ "erm",
+ "hey",
+ "hmm",
+ "huh",
+ "mhm",
+ "mm",
+ "oh",
+ "uh",
+ "um",
+ "yo",
+ "呃",
+ "嗯",
+ "啊",
+ "诶",
+ "欸",
+ )
+
+ fun match(
+ transcript: String,
+ triggers: List,
+ ): VoiceWakeMatch? {
+ val normalizedTranscript = normalizeSpokenText(transcript)
+ if (normalizedTranscript.value.isEmpty()) return null
+
+ return VoiceWakePreferences
+ .sanitizeTriggerWords(triggers)
+ .asSequence()
+ .mapNotNull { trigger -> matchTrigger(transcript, normalizedTranscript, trigger) }
+ .minByOrNull { it.first }
+ ?.second
+ }
+
+ private fun matchTrigger(
+ transcript: String,
+ normalizedTranscript: NormalizedSpokenText,
+ trigger: String,
+ ): Pair? {
+ val normalizedTrigger = normalizeSpokenText(trigger).value
+ if (normalizedTrigger.isEmpty()) return null
+ var start = normalizedTranscript.value.indexOf(normalizedTrigger)
+ while (start >= 0) {
+ val end = start + normalizedTrigger.length
+ if (
+ isBoundary(normalizedTranscript.value, start - 1, normalizedTrigger.codePointAt(0)) &&
+ isBoundary(normalizedTranscript.value, end, normalizedTrigger.codePointBefore(normalizedTrigger.length)) &&
+ hasOnlyWakeFillers(normalizedTranscript.value.substring(0, start))
+ ) {
+ val originalStart = normalizedTranscript.originalStarts[start]
+ val originalEnd = normalizedTranscript.originalEnds[end - 1]
+ val command = transcript.substring(originalEnd).trimStart { !it.isLetterOrDigit() }.trim()
+ if (command.isNotEmpty()) {
+ return originalStart to VoiceWakeMatch(trigger = transcript.substring(originalStart, originalEnd), command = command)
+ }
+ }
+ start = normalizedTranscript.value.indexOf(normalizedTrigger, startIndex = start + 1)
+ }
+ return null
+ }
+
+ private data class NormalizedSpokenText(
+ val value: String,
+ val originalStarts: IntArray,
+ val originalEnds: IntArray,
+ )
+
+ private fun normalizeSpokenText(source: String): NormalizedSpokenText {
+ val value = StringBuilder()
+ val originalStarts = mutableListOf()
+ val originalEnds = mutableListOf()
+ var sourceIndex = 0
+ var pendingSeparatorStart: Int? = null
+ var previousSpokenCodePoint: Int? = null
+ while (sourceIndex < source.length) {
+ val codePoint = source.codePointAt(sourceIndex)
+ val nextSourceIndex = sourceIndex + Character.charCount(codePoint)
+ if (Character.isLetterOrDigit(codePoint)) {
+ val separatorStart = pendingSeparatorStart
+ val previousCodePoint = previousSpokenCodePoint
+ if (
+ separatorStart != null &&
+ previousCodePoint != null &&
+ !doesNotUseWhitespaceWordBoundaries(previousCodePoint) &&
+ !doesNotUseWhitespaceWordBoundaries(codePoint)
+ ) {
+ value.append(' ')
+ originalStarts += separatorStart
+ originalEnds += sourceIndex
+ }
+ val folded = String(Character.toChars(codePoint)).lowercase()
+ folded.forEach {
+ value.append(it)
+ originalStarts += sourceIndex
+ originalEnds += nextSourceIndex
+ }
+ previousSpokenCodePoint = codePoint
+ pendingSeparatorStart = null
+ } else if (value.isNotEmpty() && pendingSeparatorStart == null) {
+ pendingSeparatorStart = sourceIndex
+ }
+ sourceIndex = nextSourceIndex
+ }
+ return NormalizedSpokenText(
+ value = value.toString(),
+ originalStarts = originalStarts.toIntArray(),
+ originalEnds = originalEnds.toIntArray(),
+ )
+ }
+
+ private fun isBoundary(
+ value: String,
+ index: Int,
+ triggerEdgeCodePoint: Int,
+ ): Boolean =
+ index !in value.indices ||
+ !value[index].isLetterOrDigit() ||
+ doesNotUseWhitespaceWordBoundaries(triggerEdgeCodePoint)
+
+ private fun doesNotUseWhitespaceWordBoundaries(codePoint: Int): Boolean =
+ when (Character.UnicodeScript.of(codePoint)) {
+ Character.UnicodeScript.BOPOMOFO,
+ Character.UnicodeScript.HAN,
+ Character.UnicodeScript.HANGUL,
+ Character.UnicodeScript.HIRAGANA,
+ Character.UnicodeScript.KATAKANA,
+ Character.UnicodeScript.KHMER,
+ Character.UnicodeScript.LAO,
+ Character.UnicodeScript.MYANMAR,
+ Character.UnicodeScript.THAI,
+ -> true
+ else -> false
+ }
+
+ private fun hasOnlyWakeFillers(prefix: String): Boolean =
+ prefix
+ .split(Regex("[^\\p{L}\\p{N}]+"))
+ .filter(String::isNotEmpty)
+ .all { it.lowercase() in wakePrefixFillers }
+}
diff --git a/apps/android/app/src/main/res/values-ar/strings.xml b/apps/android/app/src/main/res/values-ar/strings.xml
index de7d9a089d74..a1974baae4e7 100644
--- a/apps/android/app/src/main/res/values-ar/strings.xml
+++ b/apps/android/app/src/main/res/values-ar/strings.xml
@@ -46,6 +46,7 @@
"سيتحقق Gateway من هذا الإصدار بعينه عبر ClawHub قبل التنزيل. إذا كان الإصدار يتطلب إقرارًا صريحًا بالمخاطر، فسيعرض Android تحذير Gateway قبل إعادة المحاولة."
"يستخدم رمز الإعداد معرّف نطاق IPv6. استخدم عنوان IPv6 غير محدد النطاق أو اسم مضيف LAN."
"مرفق"
+ "اضبط كلمات التنبيه والتحدث والتشغيل."
"جارٍ الاستماع (PTT)"
"تم رفض المقترح."
"المستخدم"
@@ -126,7 +127,6 @@
"دليل إعداد Android"
"تم حظر %1$s تطبيقات من إعادة التوجيه."
"الأجهزة المقترنة"
- "اضبط الصوت والنقل والتشغيل."
"%1$s معلّقة"
"اسم الجهاز"
"الموقع"
@@ -151,6 +151,7 @@
"+%1$s أخرى"
"thread create"
"محظور"
+ "كلمة أو عبارة التنبيه"
"يتطلب Gateway الموافقة على الجهاز"
"%1$s/%2$s جاهزة"
"متصل (المشغّل غير متصل)"
@@ -163,6 +164,7 @@
"صورة"
"إغلاق معاينة الصورة"
"eval"
+ "آخر أمر: %1$s"
"اجعل نافذة طرفية مفتوحة على الجهاز الذي يشغّل OpenClaw."
"لا توجد عناصر مفقودة"
"يتطلب إخراج اللوحة اتصال Gateway نشطًا."
@@ -206,6 +208,7 @@
"جارٍ الاتصال بـ Gateway"
"يمكن للـ Gateway تغيير هذا المسار لكن لا يمكنه مسح مسار موجود."
"TTS"
+ "جارٍ الحفظ…"
"المرساة %1$s"
"search"
"افحص مهام Gateway المجدولة وأدِرها."
@@ -369,6 +372,7 @@
"فترة التهدئة %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"الرسائل القصيرة"
+ "ميزة التعرّف على الكلام على الجهاز غير متاحة."
"المرفقات كبيرة جدًا بحيث لا يمكن وضعها في قائمة الانتظار ضمن رسالة واحدة؛ أزل بعضها وحاول مجددًا."
"يوجد نموذج واحد مُعدّ. حدّث لإعادة التحقق من التوفر."
"يلزم اتصال آمن لهذا المضيف."
@@ -413,6 +417,7 @@
"قريبًا"
"لا توجد موافقات Gateway."
"المضيف"
+ "أضف كلمة تنبيه أو عبارة واحدة في كل حقل. ثم قل إحداها قبل أمرك."
"نسخ ثم إرسال"
"التشغيل في"
"الوصول إلى جهاز Gateway"
@@ -475,6 +480,7 @@
"البحث في OpenClaw"
"الجلسة الرئيسية"
"%1$s قيد الانتظار"
+ "التعرّف على الكلام على الجهاز غير متاح"
"لا يوجد تطبيق يمكنه مشاركة هذه الرسالة"
"إغلاق البحث"
"الأمر المراد مراقبته"
@@ -507,6 +513,7 @@
"لم يتم تحميل كتالوج محادثات Gateway"
"هذا الـ Gateway"
"لا توجد عمليات تشغيل حديثة بعد."
+ "نموذج اللغة على الجهاز غير متاح"
"ستظهر المقترحات المطابقة هنا بعد أن تنشئ الوكلاء مسودات مهارات قابلة لإعادة الاستخدام."
"Session Search"
"OpenClaw يتحدث"
@@ -526,6 +533,7 @@
"سطح الشاشة جاهز"
"إقران Gateway"
"وصّل Gateway لتحميل القنوات."
+ "يتوقف مؤقتًا أثناء الأنشطة الصوتية الأخرى."
"النموذج"
"الصور"
"الصق رمز الإعداد"
@@ -566,10 +574,12 @@
"pin"
"نسخ %1$s"
"مقترن"
+ "تعذر حفظ كلمات التنبيه"
"سيؤدي هذا إلى عزل \"%1$s\" وتحديث حالة ورشة Skills من Gateway."
"تسجيل ملاحظة صوتية"
"السماح بأدوات الكاميرا عند طلبها."
"المشكلات"
+ "التنبيه الصوتي"
"قبل %1$s ي"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"الأخيرة"
"نتيجة الحل غير معروفة. تبقى الإجراءات معطلة حتى يتم التحقق من سجل Gateway."
"dialog"
+ "الاستماع إلى كلمات التنبيه"
"camera snap"
"حدّد Gateway موفّرًا غير معروف %1$s"
"متابعة Android · %1$s"
@@ -613,6 +624,7 @@
"مهارة"
"لم يحدّد Gateway موفّر %1$s النشط"
"قيد الانتظار"
+ "تم حفظ كلمات التنبيه"
"الأقدم أولاً"
"الشاشة"
"قيد التشغيل منذ"
@@ -645,6 +657,7 @@
"%1$s... (حسنًا)"
"الموفرون والنماذج المُهيأة"
"جارٍ الاتصال…"
+ "اتصل بـ Gateway لحفظ كلمات التنبيه"
"فتح الملف الشخصي"
"ابدأ تشغيل Gateway الخاص بك."
"ساعدني في تحويل هذا الهدف إلى قائمة تحقق عملية: "
@@ -700,6 +713,7 @@
"OpenClaw يرد"
"المستندات"
"%1$s جاهز"
+ "لغة الجهاز غير مدعومة"
"في قائمة الانتظار — سيُرسل عند إعادة الاتصال"
"قبل %1$s د"
"جارٍ التحقق من صلاحية الاقتران"
@@ -731,6 +745,7 @@
"السماح للمجدول بتشغيل عملية الأتمتة هذه."
"%1$s مطبّق"
"لا توجد مذكرة أحلام بعد."
+ "يعمل على الجهاز أثناء ظهور OpenClaw."
"%1$s يعمل"
"%1$s %2$s"
"خام"
@@ -870,6 +885,7 @@
"تم إيقاف التشغيل الآلي مؤقتًا."
"OpenClaw للجوال"
"A2UI reset"
+ "Gateway غير متاح"
"Read"
"تحتاج هذه المهارة إلى عنصر إعداد واحد. يعرض Android ما هو مثبّت؛ وتظل تغييرات الإعداد/التكوين على سطح المكتب أو CLI."
"آخر تشغيل"
@@ -976,6 +992,7 @@
"مرفوض"
"تضمين حزم Android وحزم الخلفية."
"Gateway جاهز."
+ "تم التشغيل"
"يستغرق هذا وقتًا أطول من المتوقع.\nتحقق من أن Gateway قيد التشغيل ويمكن الوصول إليه."
"جارٍ إعادة الاتصال"
"يتحقق OpenClaw من الوصول إلى Gateway والعقدة."
@@ -1021,6 +1038,7 @@
"المصادقة المحفوظة غير صالحة"
"%1$s نطاقات"
"وصّل Gateway لتحميل السجلات الأخيرة."
+ "حفظ كلمات التنبيه"
"أدِر المهارات المثبّتة وأضف الإصدارات الموثوقة من ClawHub."
"جارٍ الإرسال…"
"لم يتم تحميل أي وكلاء بعد."
@@ -1055,6 +1073,7 @@
"قائمة الانتظار دون اتصال ممتلئة (%1$s من الرسائل)؛ احذف العناصر قيد الانتظار أولًا."
"تتطلب البوابات العامة wss:// أو Tailscale Serve. يُسمح باستخدام ws:// مع localhost ومضيفي .local ومحاكي Android وعناوين IP الخاصة بشبكة LAN."
"وصّل Gateway لتحميل تفاصيل Skill."
+ "مستمع التنبيه"
"توسيع معاينة الرابط"
"NULL (فشل)"
"تحديث"
@@ -1196,6 +1215,7 @@
"تعذر تحميل هذا المجلد."
"لم يحتوِ رمز QR على رمز إعداد صالح."
"راجع صلاحيات الوصول إلى العقدة"
+ "إضافة عبارة تنبيه"
"يتعذر الوصول إلى Gateway"
"الأتمتة"
"يحتاج إلى اتصال"
@@ -1225,6 +1245,7 @@
"الاسم"
"الإصدار"
"Cron"
+ "إزالة عبارة التنبيه"
"لم يتم قبول رمز الإعداد. أنشئ رمزًا جديدًا باستخدام openclaw qr."
"14 رسالة · Android"
"فشل النسخ: %1$s"
@@ -1366,6 +1387,7 @@
"إلغاء الأرشفة"
"Transcripts"
"الجلسات الحديثة"
+ "كلمات التنبيه"
"قم بتكوين %1$s على Gateway"
"امسح رمز QR ضوئيًا أو استخدم رمز الإعداد من OpenClaw Gateway لديك."
"نموذج أولي لنظام التصميم"
diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml
index 788b43f3a871..32ec273e71c9 100644
--- a/apps/android/app/src/main/res/values-de/strings.xml
+++ b/apps/android/app/src/main/res/values-de/strings.xml
@@ -46,6 +46,7 @@
"Das Gateway überprüft vor dem Download genau diese Version mit ClawHub. Wenn für die Version eine ausdrückliche Risikobestätigung erforderlich ist, zeigt Android vor dem erneuten Versuch die Gateway-Warnung an."
"Der Einrichtungscode verwendet eine IPv6-Zonen-ID. Verwende eine IPv6-Adresse ohne Bereichsangabe oder einen LAN-Hostnamen."
"Anhang"
+ "Aktivierungswörter, Spracheingabe und Wiedergabe konfigurieren."
"Hört zu (PTT)"
"Vorschlag abgelehnt."
"Benutzer"
@@ -126,7 +127,6 @@
"Android-Einrichtungsanleitung"
"%1$s Apps sind für die Weiterleitung blockiert."
"Gekoppelte Geräte"
- "Sprache, Transport und Wiedergabe konfigurieren."
"%1$s ausstehend"
"Gerätename"
"Standort"
@@ -151,6 +151,7 @@
"+%1$s weitere"
"thread create"
"Blockiert"
+ "Aktivierungswort oder -phrase"
"Gateway benötigt eine Gerätefreigabe"
"%1$s/%2$s bereit"
"Verbunden (Operator offline)"
@@ -163,6 +164,7 @@
"Bild"
"Bildvorschau schließen"
"eval"
+ "Letzter Befehl: %1$s"
"Halten Sie ein Terminal auf dem Gerät geöffnet, auf dem OpenClaw ausgeführt wird."
"Keine fehlenden Elemente"
"Die Canvas-Ausgabe erfordert eine aktive Gateway-Verbindung."
@@ -206,6 +208,7 @@
"Verbindung zum Gateway wird hergestellt"
"Das Gateway kann diesen Pfad ändern, aber einen vorhandenen Pfad nicht löschen."
"TTS"
+ "Speichern…"
"Anker %1$s"
"search"
"Geplante Gateway-Aufgaben prüfen und verwalten."
@@ -369,6 +372,7 @@
"Abklingzeit %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Die Spracherkennung auf dem Gerät ist nicht verfügbar."
"Die Anhänge sind zu groß, um sie für eine einzelne Nachricht in die Warteschlange zu stellen. Entfernen Sie einige und versuchen Sie es erneut."
"1 Modell konfiguriert. Aktualisieren Sie, um die Verfügbarkeit erneut zu prüfen."
"Für diesen Host ist eine sichere Verbindung erforderlich."
@@ -413,6 +417,7 @@
"bald"
"Keine Gateway-Genehmigungen."
"Host"
+ "Fügen Sie pro Feld ein Aktivierungswort oder eine Aktivierungsphrase hinzu. Sagen Sie anschließend eines davon vor Ihrem Befehl."
"Transkribieren und dann senden"
"Ausführen um"
"Zugriff auf das Gateway-Gerät"
@@ -475,6 +480,7 @@
"OpenClaw suchen"
"Hauptsitzung"
"%1$s ausstehend"
+ "Spracherkennung auf dem Gerät nicht verfügbar"
"Keine App kann diese Nachricht teilen"
"Suche schließen"
"Zu überwachender Befehl"
@@ -507,6 +513,7 @@
"Gateway-Talk-Katalog nicht geladen"
"dieses Gateway"
"Noch keine letzten Ausführungen."
+ "Sprachmodell auf dem Gerät nicht verfügbar"
"Passende Vorschläge erscheinen hier, nachdem Agenten wiederverwendbare Skill-Entwürfe erstellt haben."
"Session Search"
"OpenClaw spricht"
@@ -526,6 +533,7 @@
"Bildschirmoberfläche bereit"
"Gateway koppeln"
"Verbinde die Gateway, um Kanäle zu laden."
+ "Wird bei anderen Sprachaktivitäten pausiert."
"Modell"
"Fotos"
"Einrichtungscode einfügen"
@@ -566,10 +574,12 @@
"pin"
"%1$s kopieren"
"Gekoppelt"
+ "Aktivierungswörter konnten nicht gespeichert werden"
"Dadurch wird \"%1$s\" unter Quarantäne gestellt und der Status von Skill Workshop über das Gateway aktualisiert."
"Sprachnachricht aufnehmen"
"Kameratools auf Anfrage zulassen."
"Probleme"
+ "Sprachaktivierung"
"vor %1$s Tagen"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Zuletzt verwendet"
"Ergebnis der Auflösung unbekannt. Aktionen bleiben deaktiviert, bis der Gateway-Eintrag verifiziert wurde."
"dialog"
+ "Auf Aktivierungswörter warten"
"camera snap"
"Gateway hat unbekannten Anbieter %1$s ausgewählt"
"Android folgen · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway hat den aktiven Anbieter für %1$s nicht identifiziert"
"Warten"
+ "Aktivierungswörter gespeichert"
"Älteste zuerst"
"Bildschirm"
"Läuft seit"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Anbieter und konfigurierte Modelle"
"Verbindung wird hergestellt…"
+ "Mit einem Gateway verbinden, um Aktivierungswörter zu speichern"
"Profil öffnen"
"Starte deine Gateway."
"Hilf mir, dieses Ziel in eine praktische Checkliste zu verwandeln: "
@@ -700,6 +713,7 @@
"OpenClaw antwortet"
"Dokumentation"
"%1$s bereit"
+ "Gerätesprache wird nicht unterstützt"
"In Warteschlange — wird nach erneuter Verbindung gesendet"
"vor %1$s Min."
"Kopplungszugriff wird geprüft"
@@ -731,6 +745,7 @@
"Dem Scheduler erlauben, diese Automatisierung auszuführen."
"%1$s angewendet"
"Noch kein Traumtagebuch."
+ "Wird auf dem Gerät ausgeführt, solange OpenClaw sichtbar ist."
"%1$s arbeitet"
"%1$s %2$s"
"Rohdaten"
@@ -870,6 +885,7 @@
"Die Automation wurde pausiert."
"OpenClaw Mobile"
"A2UI reset"
+ "Gateway nicht verfügbar"
"Read"
"Für diesen Skill muss 1 Element eingerichtet werden. Android zeigt an, was installiert ist; Änderungen an Einrichtung und Konfiguration sind nur über den Desktop oder die CLI möglich."
"Letzte Ausführung"
@@ -976,6 +992,7 @@
"Abgelehnt"
"Android- und Hintergrundpakete einschließen."
"Ihr Gateway ist bereit."
+ "Ausgelöst"
"Dies dauert länger als erwartet.\nPrüfen Sie, ob das Gateway ausgeführt wird und erreichbar ist."
"Verbindung wird wiederhergestellt"
"OpenClaw prüft den Zugriff auf Gateway und Node."
@@ -1021,6 +1038,7 @@
"Gespeicherte Authentifizierung ungültig"
"%1$s Bereiche"
"Verbinden Sie die Gateway, um aktuelle Protokolle zu laden."
+ "Aktivierungswörter speichern"
"Verwalten Sie installierte Skills und fügen Sie vertrauenswürdige Versionen aus ClawHub hinzu."
"Wird gesendet…"
"Noch keine Agents geladen."
@@ -1055,6 +1073,7 @@
"Die Offline-Warteschlange ist voll (%1$s Nachrichten). Löschen Sie zuerst Elemente aus der Warteschlange."
"Öffentliche Gateways erfordern wss:// oder Tailscale Serve. ws:// ist für localhost, .local-Hosts, den Android-Emulator und private LAN-IPs zulässig."
"Verbinden Sie die Gateway, um Skill-Details zu laden."
+ "Aktivierungswort-Erkennung"
"Linkvorschau erweitern"
"NULL (FEHLGESCHLAGEN)"
"Aktualisieren"
@@ -1196,6 +1215,7 @@
"Dieser Ordner konnte nicht geladen werden."
"Der QR-Code enthielt keinen gültigen Einrichtungscode."
"Knotenzugriff überprüfen"
+ "Aktivierungsphrase hinzufügen"
"Gateway nicht erreichbar"
"Automatisierung"
"Verbindung erforderlich"
@@ -1225,6 +1245,7 @@
"Name"
"Version"
"Cron"
+ "Aktivierungsphrase entfernen"
"Der Einrichtungscode wurde nicht akzeptiert. Generiere mit openclaw qr einen neuen Code."
"14 Nachrichten · Android"
"Transkription fehlgeschlagen: %1$s"
@@ -1366,6 +1387,7 @@
"Aus Archiv entfernen"
"Transcripts"
"Aktuelle Sitzungen"
+ "Aktivierungswörter"
"Konfigurieren Sie %1$s auf dem Gateway"
"Scannen Sie einen QR-Code oder verwenden Sie den Einrichtungscode von Ihrem OpenClaw Gateway."
"Designsystem-Prototyp"
diff --git a/apps/android/app/src/main/res/values-es/strings.xml b/apps/android/app/src/main/res/values-es/strings.xml
index c08f7ec67a72..70ea3156ff2c 100644
--- a/apps/android/app/src/main/res/values-es/strings.xml
+++ b/apps/android/app/src/main/res/values-es/strings.xml
@@ -46,6 +46,7 @@
"Gateway verificará esta versión exacta con ClawHub antes de descargarla. Si la versión requiere una aceptación explícita del riesgo, Android mostrará la advertencia de Gateway antes de volver a intentarlo."
"El código de configuración usa un ID de zona IPv6. Usa una dirección IPv6 sin ámbito o un nombre de host de LAN."
"Archivo adjunto"
+ "Configura las palabras de activación, la conversación y la reproducción."
"Escuchando (PTT)"
"Propuesta rechazada."
"usuario"
@@ -126,7 +127,6 @@
"Guía de configuración de Android"
"%1$s aplicaciones bloqueadas para el reenvío."
"Dispositivos emparejados"
- "Configura la voz, el transporte y la reproducción."
"%1$s pendientes"
"Nombre del dispositivo"
"Ubicación"
@@ -151,6 +151,7 @@
"+%1$s más"
"thread create"
"Bloqueada"
+ "Palabra o frase de activación"
"Gateway necesita la aprobación del dispositivo"
"%1$s/%2$s listas"
"Conectado (operador sin conexión)"
@@ -163,6 +164,7 @@
"Imagen"
"Cerrar vista previa de la imagen"
"eval"
+ "Último comando: %1$s"
"Ten una terminal abierta en el dispositivo que ejecuta OpenClaw."
"No falta ningún elemento"
"La salida del lienzo necesita una conexión activa al Gateway."
@@ -206,6 +208,7 @@
"Conectando con el Gateway"
"El gateway puede cambiar esta ruta pero no puede borrar una ruta existente."
"TTS"
+ "Guardando…"
"Anclaje %1$s"
"search"
"Inspecciona y gestiona el trabajo programado del Gateway."
@@ -369,6 +372,7 @@
"Tiempo de espera %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "El reconocimiento de voz en el dispositivo no está disponible."
"Los archivos adjuntos son demasiado grandes para ponerlos en cola en un solo mensaje; elimina algunos e inténtalo de nuevo."
"1 modelo configurado. Actualiza para volver a comprobar la disponibilidad."
"Se requiere una conexión segura para este host."
@@ -413,6 +417,7 @@
"pronto"
"No hay aprobaciones del Gateway."
"Host"
+ "Añade una palabra o frase de activación por campo. Después, di una antes de tu comando."
"Transcribir y luego enviar"
"Ejecutar a las"
"Acceso al dispositivo Gateway"
@@ -475,6 +480,7 @@
"Buscar en OpenClaw"
"Sesión principal"
"%1$s pendientes"
+ "El reconocimiento de voz en el dispositivo no está disponible"
"Ninguna app puede compartir este mensaje"
"Cerrar búsqueda"
"Comando a observar"
@@ -507,6 +513,7 @@
"Catálogo de conversación de Gateway no cargado"
"este gateway"
"Aún no hay ejecuciones recientes."
+ "El modelo de lenguaje en el dispositivo no está disponible"
"Las propuestas coincidentes aparecerán aquí después de que los agentes creen borradores de skills reutilizables."
"Session Search"
"OpenClaw está hablando"
@@ -526,6 +533,7 @@
"Superficie de pantalla lista"
"Emparejar Gateway"
"Conecta el Gateway para cargar los canales."
+ "Se pausa durante otra actividad de voz."
"Modelo"
"Fotos"
"Pegar código de configuración"
@@ -566,10 +574,12 @@
"pin"
"Copiar %1$s"
"Emparejado"
+ "No se pudieron guardar las palabras de activación"
"Esto pondrá \"%1$s\" en cuarentena y actualizará el estado de Skill Workshop desde el Gateway."
"Grabar nota de voz"
"Permitir las herramientas de cámara cuando se soliciten."
"Problemas"
+ "Activación por voz"
"hace %1$s d"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Reciente"
"Resultado de la resolución desconocido. Las acciones permanecen deshabilitadas hasta verificar el registro del Gateway."
"dialog"
+ "Escuchar palabras de activación"
"camera snap"
"Gateway seleccionó un proveedor desconocido: %1$s"
"Seguir Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway no identificó el proveedor activo de %1$s"
"En espera"
+ "Palabras de activación guardadas"
"Más antiguos primero"
"Pantalla"
"En ejecución desde"
@@ -645,6 +657,7 @@
"%1$s... (CORRECTO)"
"Proveedores y modelos configurados"
"Conectando…"
+ "Conéctate a un Gateway para guardar las palabras de activación"
"Abrir perfil"
"Inicia tu Gateway."
"Ayúdame a convertir este objetivo en una lista de verificación práctica: "
@@ -700,6 +713,7 @@
"OpenClaw está respondiendo"
"Documentación"
"%1$s listos"
+ "El idioma del dispositivo no es compatible"
"En cola — se enviará al volver a conectar"
"hace %1$s min"
"Comprobando el acceso de emparejamiento"
@@ -731,6 +745,7 @@
"Permite que el programador ejecute esta automatización."
"%1$s aplicados"
"Aún no hay diario de sueños."
+ "Se ejecuta en el dispositivo mientras OpenClaw está visible."
"%1$s está trabajando"
"%1$s %2$s"
"Sin procesar"
@@ -870,6 +885,7 @@
"Automatización en pausa."
"OpenClaw móvil"
"A2UI reset"
+ "Gateway no disponible"
"Read"
"Esta skill necesita configurar 1 elemento. Android muestra lo que está instalado; los cambios de configuración se realizan desde la aplicación de escritorio o la CLI."
"Última ejecución"
@@ -976,6 +992,7 @@
"Rechazado"
"Incluye Android y paquetes en segundo plano."
"Tu Gateway está listo."
+ "Activado"
"Esto está tardando más de lo esperado.\nComprueba que el Gateway esté en ejecución y accesible."
"Reconectando"
"OpenClaw está comprobando el acceso al Gateway y al nodo."
@@ -1021,6 +1038,7 @@
"La autenticación guardada no es válida"
"%1$s ámbitos"
"Conecta el gateway para cargar los registros recientes."
+ "Guardar palabras de activación"
"Gestiona las skills instaladas y añade versiones de confianza desde ClawHub."
"Enviando…"
"Aún no se han cargado agentes."
@@ -1055,6 +1073,7 @@
"La cola sin conexión está llena (%1$s mensajes); elimina primero los elementos en cola."
"Los gateways públicos requieren wss:// o Tailscale Serve. ws:// está permitido para localhost, hosts .local, el emulador de Android y direcciones IP de LAN privadas."
"Conecta el Gateway para cargar los detalles de la Skill."
+ "Detector de activación"
"Expandir vista previa del enlace"
"NULL (FALLIDO)"
"Actualizar"
@@ -1196,6 +1215,7 @@
"No se pudo cargar esta carpeta."
"El código QR no contenía un código de configuración válido."
"Revisa el acceso al nodo"
+ "Añadir frase de activación"
"No se puede acceder al Gateway"
"Automatización"
"Necesita conexión"
@@ -1225,6 +1245,7 @@
"Nombre"
"Versión"
"Cron"
+ "Eliminar frase de activación"
"No se aceptó el código de configuración. Genera uno nuevo con openclaw qr."
"14 mensajes · Android"
"Error de transcripción: %1$s"
@@ -1366,6 +1387,7 @@
"Desarchivar"
"Transcripts"
"Sesiones recientes"
+ "Palabras de activación"
"Configura %1$s en el Gateway"
"Escanea un código QR o usa el código de configuración de tu OpenClaw Gateway."
"Prototipo de sistema de diseño"
diff --git a/apps/android/app/src/main/res/values-fa/strings.xml b/apps/android/app/src/main/res/values-fa/strings.xml
index 294ee6f64be1..2976a0c72d7e 100644
--- a/apps/android/app/src/main/res/values-fa/strings.xml
+++ b/apps/android/app/src/main/res/values-fa/strings.xml
@@ -46,6 +46,7 @@
"Gateway پیش از دانلود، این انتشار دقیق را با ClawHub تأیید میکند. اگر انتشار به تأیید صریح ریسک نیاز داشته باشد، Android پیش از تلاش مجدد هشدار Gateway را نمایش میدهد."
"کد راهاندازی از شناسهٔ محدودهٔ IPv6 استفاده میکند. از یک نشانی IPv6 بدون محدوده یا نام میزبان LAN استفاده کنید."
"پیوست"
+ "واژههای بیدارباش، گفتوگو و پخش را پیکربندی کنید."
"در حال شنیدن (PTT)"
"پیشنهاد رد شد."
"کاربر"
@@ -126,7 +127,6 @@
"راهنمای راهاندازی Android"
"%1$s برنامه از بازارسال مسدود شدهاند."
"دستگاههای جفتشده"
- "صدا، انتقال و پخش را پیکربندی کنید."
"%1$s در انتظار"
"نام دستگاه"
"موقعیت مکانی"
@@ -151,6 +151,7 @@
"+%1$s مورد دیگر"
"thread create"
"مسدود"
+ "واژه یا عبارت بیدارباش"
"Gateway به تأیید دستگاه نیاز دارد"
"%1$s/%2$s آماده"
"متصل (اپراتور آفلاین است)"
@@ -163,6 +164,7 @@
"تصویر"
"بستن پیشنمایش تصویر"
"eval"
+ "آخرین فرمان: %1$s"
"روی دستگاهی که OpenClaw را اجرا میکند، یک ترمینال باز داشته باشید."
"هیچ موردی کم نیست"
"خروجی بوم به اتصال فعال Gateway نیاز دارد."
@@ -206,6 +208,7 @@
"در حال اتصال به Gateway"
"gateway میتواند این مسیر را تغییر دهد اما نمیتواند مسیر موجود را پاک کند."
"TTS"
+ "در حال ذخیره…"
"لنگر %1$s"
"search"
"کارهای زمانبندیشده Gateway را بررسی و مدیریت کنید."
@@ -369,6 +372,7 @@
"زمان انتظار %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"پیامک"
+ "تشخیص گفتار روی دستگاه در دسترس نیست."
"پیوستها برای قرار گرفتن در صف یک پیام بیش از حد بزرگ هستند؛ تعدادی را حذف و دوباره تلاش کنید."
"۱ مدل پیکربندی شده است. برای بررسی دوباره موجود بودن، تازهسازی کنید."
"برای این میزبان، اتصال امن الزامی است."
@@ -413,6 +417,7 @@
"بهزودی"
"هیچ تأییدیهای برای Gateway وجود ندارد."
"میزبان"
+ "در هر فیلد یک واژه یا عبارت بیدارباش اضافه کنید. سپس پیش از فرمان خود یکی از آنها را بگویید."
"رونویسی و سپس ارسال"
"اجرا در"
"دسترسی به دستگاه Gateway"
@@ -475,6 +480,7 @@
"جستجوی OpenClaw"
"نشست اصلی"
"%1$s در انتظار"
+ "تشخیص گفتار روی دستگاه در دسترس نیست"
"هیچ برنامهای نمیتواند این پیام را به اشتراک بگذارد"
"بستن جستجو"
"دستور برای پایش"
@@ -507,6 +513,7 @@
"کاتالوگ گفتوگوی Gateway بارگذاری نشده است"
"این Gateway"
"هنوز اجرای اخیری وجود ندارد."
+ "مدل زبانی روی دستگاه در دسترس نیست"
"پیشنهادهای منطبق پس از ساختن پیشنویسهای Skill قابلاستفادهی مجدد توسط عاملها اینجا نمایش داده میشوند."
"Session Search"
"OpenClaw در حال صحبت است"
@@ -526,6 +533,7 @@
"سطح صفحه آماده است"
"جفتسازی Gateway"
"برای بارگیری کانالها، Gateway را متصل کنید."
+ "هنگام سایر فعالیتهای صوتی متوقف میشود."
"مدل"
"عکسها"
"چسباندن کد راهاندازی"
@@ -566,10 +574,12 @@
"pin"
"کپی %1$s"
"جفتشده"
+ "ذخیره واژههای بیدارباش ممکن نشد"
"این کار \"%1$s\" را قرنطینه میکند و وضعیت Skill Workshop را از Gateway تازهسازی میکند."
"ضبط یادداشت صوتی"
"در صورت درخواست، ابزارهای دوربین را مجاز کنید."
"مشکلات"
+ "بیدارباش صوتی"
"%1$s روز پیش"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"اخیر"
"نتیجه تعیین تکلیف نامشخص است. تا زمانی که رکورد Gateway تأیید نشود، اقدامات غیرفعال میمانند."
"dialog"
+ "گوشدادن به واژههای بیدارباش"
"camera snap"
"Gateway ارائهدهنده ناشناخته %1$s را انتخاب کرد"
"دنبال کردن Android · %1$s"
@@ -613,6 +624,7 @@
"مهارت"
"Gateway ارائهدهنده فعال %1$s را شناسایی نکرد"
"در انتظار"
+ "واژههای بیدارباش ذخیره شدند"
"ابتدا قدیمیترین"
"صفحه"
"در حال اجرا از"
@@ -645,6 +657,7 @@
"%1$s... (تأیید)"
"ارائهدهندگان و مدلهای پیکربندیشده"
"در حال اتصال…"
+ "برای ذخیره واژههای بیدارباش به یک Gateway متصل شوید"
"باز کردن پروفایل"
"Gateway خود را شروع کنید."
"کمکم کن این هدف را به یک چکلیست کاربردی تبدیل کنم: "
@@ -700,6 +713,7 @@
"OpenClaw در حال پاسخدادن است"
"مستندات"
"%1$s آماده"
+ "زبان دستگاه پشتیبانی نمیشود"
"در صف — پس از اتصال مجدد ارسال میشود"
"%1$s دقیقه پیش"
"در حال بررسی دسترسی جفتسازی"
@@ -731,6 +745,7 @@
"به زمانبند اجازه دهید این خودکارسازی را اجرا کند."
"%1$s اعمالشده"
"هنوز دفترچهٔ رؤیایی وجود ندارد."
+ "تا زمانی که OpenClaw قابل مشاهده است، روی دستگاه اجرا میشود."
"%1$s در حال کار است"
"%1$s %2$s"
"خام"
@@ -870,6 +885,7 @@
"اجرای خودکار متوقف شد."
"OpenClaw موبایل"
"A2UI reset"
+ "Gateway در دسترس نیست"
"Read"
"این Skills به ۱ مورد راهاندازی نیاز دارد. Android موارد نصبشده را نمایش میدهد؛ تغییرات راهاندازی/پیکربندی فقط از طریق دسکتاپ یا CLI انجام میشوند."
"آخرین اجرا"
@@ -976,6 +992,7 @@
"ردشده"
"بستههای Android و پسزمینه را شامل کنید."
"Gateway شما آماده است."
+ "فعال شد"
"این فرایند بیش از حد انتظار طول کشیده است.\nبررسی کنید که Gateway در حال اجرا و در دسترس باشد."
"در حال اتصال مجدد"
"OpenClaw در حال بررسی دسترسی به Gateway و گره است."
@@ -1021,6 +1038,7 @@
"احراز هویت ذخیرهشده نامعتبر است"
"%1$s محدوده"
"برای بارگیری گزارشهای اخیر، Gateway را متصل کنید."
+ "ذخیره واژههای بیدارباش"
"مهارتهای نصبشده را مدیریت کنید و نسخههای مورد اعتماد را از ClawHub اضافه کنید."
"در حال ارسال…"
"هنوز عاملی بارگذاری نشده است."
@@ -1055,6 +1073,7 @@
"صف آفلاین پر است (%1$s پیام)؛ ابتدا موارد در صف را حذف کنید."
"Gatewayهای عمومی به wss:// یا Tailscale Serve نیاز دارند. استفاده از ws:// برای localhost، میزبانهای .local، شبیهساز Android و IPهای خصوصی LAN مجاز است."
"برای بارگذاری جزئیات Skill، Gateway را متصل کنید."
+ "شنونده بیدارباش"
"گسترش پیشنمایش پیوند"
"NULL (ناموفق)"
"بهروزرسانی"
@@ -1196,6 +1215,7 @@
"این پوشه بارگیری نشد."
"کد QR شامل کد راهاندازی معتبر نبود."
"دسترسی گره را بررسی کنید"
+ "افزودن عبارت بیدارباش"
"دسترسی به Gateway ممکن نیست"
"خودکارسازی"
"نیازمند اتصال"
@@ -1225,6 +1245,7 @@
"نام"
"نسخه"
"Cron"
+ "حذف عبارت بیدارباش"
"کد راهاندازی پذیرفته نشد. با openclaw qr یک کد جدید ایجاد کنید."
"۱۴ پیام · Android"
"رونویسی ناموفق بود: %1$s"
@@ -1366,6 +1387,7 @@
"خارج کردن از بایگانی"
"Transcripts"
"نشستهای اخیر"
+ "واژههای بیدارباش"
"%1$s را روی Gateway پیکربندی کنید"
"یک کد QR را اسکن کنید یا از کد راهاندازی OpenClaw Gateway خود استفاده کنید."
"نمونهٔ اولیهٔ سیستم طراحی"
diff --git a/apps/android/app/src/main/res/values-fr/strings.xml b/apps/android/app/src/main/res/values-fr/strings.xml
index 5cbdd9511225..290bb75d92df 100644
--- a/apps/android/app/src/main/res/values-fr/strings.xml
+++ b/apps/android/app/src/main/res/values-fr/strings.xml
@@ -46,6 +46,7 @@
"Le Gateway vérifiera cette version exacte auprès de ClawHub avant le téléchargement. Si la version nécessite une acceptation explicite des risques, Android affichera l’avertissement du Gateway avant de réessayer."
"Le code de configuration utilise un ID de zone IPv6. Utilisez une adresse IPv6 sans portée ou un nom d’hôte LAN."
"Pièce jointe"
+ "Configurez les mots d’activation, la conversation et la lecture."
"Écoute (PTT)"
"Proposition rejetée."
"utilisateur"
@@ -126,7 +127,6 @@
"Guide de configuration Android"
"%1$s applications empêchées de transférer."
"Appareils associés"
- "Configurez la voix, le transport et la lecture."
"%1$s en attente"
"Nom de l’appareil"
"Localisation"
@@ -151,6 +151,7 @@
"+%1$s de plus"
"thread create"
"Bloqué"
+ "Mot ou phrase d’activation"
"Gateway nécessite l’approbation de l’appareil"
"%1$s/%2$s prêtes"
"Connecté (opérateur hors ligne)"
@@ -163,6 +164,7 @@
"Image"
"Fermer l\'aperçu de l\'image"
"eval"
+ "Dernière commande : %1$s"
"Ayez un terminal ouvert sur l’appareil exécutant OpenClaw."
"Aucun élément manquant"
"La sortie du Canvas nécessite une connexion Gateway active."
@@ -206,6 +208,7 @@
"Connexion à la Gateway"
"Le gateway peut modifier ce chemin mais ne peut pas effacer un chemin existant."
"TTS"
+ "Enregistrement…"
"Ancrage %1$s"
"search"
"Consultez et gérez les tâches planifiées du Gateway."
@@ -369,6 +372,7 @@
"Délai de récupération %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "La reconnaissance vocale sur l’appareil n’est pas disponible."
"Les pièces jointes sont trop volumineuses pour être mises en file d’attente dans un seul message ; supprimez-en certaines et réessayez."
"1 modèle configuré. Actualisez pour vérifier à nouveau la disponibilité."
"Une connexion sécurisée est requise pour cet hôte."
@@ -413,6 +417,7 @@
"bientôt"
"Aucune approbation Gateway."
"Hôte"
+ "Ajoutez un mot ou une phrase d’activation par champ. Prononcez-en ensuite un avant votre commande."
"Transcrire puis envoyer"
"Exécuter à"
"Accès à l’appareil Gateway"
@@ -475,6 +480,7 @@
"Rechercher dans OpenClaw"
"Session principale"
"%1$s en attente"
+ "Reconnaissance vocale sur l’appareil indisponible"
"Aucune app ne peut partager ce message"
"Fermer la recherche"
"Commande à surveiller"
@@ -507,6 +513,7 @@
"Catalogue de discussion Gateway non chargé"
"ce Gateway"
"Aucune exécution récente pour le moment."
+ "Modèle linguistique sur l’appareil indisponible"
"Les propositions correspondantes apparaîtront ici après que les agents auront créé des brouillons de skills réutilisables."
"Session Search"
"OpenClaw parle"
@@ -526,6 +533,7 @@
"Surface d’écran prête"
"Appairer la Gateway"
"Connectez le Gateway pour charger les canaux."
+ "Se met en pause pendant les autres activités vocales."
"Modèle"
"Photos"
"Coller le code de configuration"
@@ -566,10 +574,12 @@
"pin"
"Copier %1$s"
"Associé"
+ "Impossible d’enregistrer les mots d’activation"
"Cela mettra \"%1$s\" en quarantaine et actualisera l’état de Skill Workshop depuis le Gateway."
"Enregistrer une note vocale"
"Autoriser les outils de caméra sur demande."
"Problèmes"
+ "Réveil vocal"
"il y a %1$s j"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Récent"
"Résultat de la résolution inconnu. Les actions restent désactivées jusqu’à ce que l’enregistrement du Gateway soit vérifié."
"dialog"
+ "Écouter les mots d’activation"
"camera snap"
"Gateway a sélectionné un fournisseur inconnu %1$s"
"Suivre Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway n’a pas identifié le fournisseur %1$s actif"
"En attente"
+ "Mots d’activation enregistrés"
"Plus anciens d\'abord"
"Écran"
"En cours depuis"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Fournisseurs et modèles configurés"
"Connexion…"
+ "Connectez-vous à un Gateway pour enregistrer les mots d’activation"
"Ouvrir le profil"
"Démarrez votre Gateway."
"Aidez-moi à transformer cet objectif en une liste de tâches concrètes : "
@@ -700,6 +713,7 @@
"OpenClaw répond"
"Documentation"
"%1$s prêts"
+ "Langue de l’appareil non prise en charge"
"En attente — envoi lors de la reconnexion"
"il y a %1$s min"
"Vérification de l’accès d’appairage"
@@ -731,6 +745,7 @@
"Autoriser le planificateur à exécuter cette automatisation."
"%1$s appliqués"
"Aucun journal de rêves pour le moment."
+ "S’exécute sur l’appareil tant qu’OpenClaw est visible."
"%1$s travaille"
"%1$s %2$s"
"Brut"
@@ -870,6 +885,7 @@
"Automatisation mise en pause."
"OpenClaw mobile"
"A2UI reset"
+ "Gateway indisponible"
"Read"
"Cette compétence nécessite 1 élément de configuration. Android indique ce qui est installé ; les modifications de configuration s’effectuent depuis l’application de bureau ou la CLI."
"Dernière exécution"
@@ -976,6 +992,7 @@
"Rejeté"
"Inclure Android et les packages en arrière-plan."
"Votre Gateway est prête."
+ "Déclenché"
"Cela prend plus de temps que prévu.\nVérifiez que la Gateway est en cours d’exécution et accessible."
"Reconnexion"
"OpenClaw vérifie l’accès au gateway et au nœud."
@@ -1021,6 +1038,7 @@
"Authentification enregistrée invalide"
"%1$s portées"
"Connectez le Gateway pour charger les journaux récents."
+ "Enregistrer les mots d’activation"
"Gérez les compétences installées et ajoutez des versions fiables depuis ClawHub."
"Envoi…"
"Aucun agent chargé pour le moment."
@@ -1055,6 +1073,7 @@
"La file d’attente hors ligne est pleine (%1$s messages) ; supprimez d’abord des éléments en attente."
"Les gateways publics nécessitent wss:// ou Tailscale Serve. ws:// est autorisé pour localhost, les hôtes .local, l’émulateur Android et les adresses IP de réseaux locaux privés."
"Connectez la Gateway pour charger les détails du Skill."
+ "Détection des mots d’activation"
"Développer l’aperçu du lien"
"NULL (ÉCHEC)"
"Mettre à jour"
@@ -1196,6 +1215,7 @@
"Impossible de charger ce dossier."
"Le code QR ne contenait pas de code de configuration valide."
"Vérifiez l’accès au nœud"
+ "Ajouter une phrase d’activation"
"Impossible de joindre le Gateway"
"Automatisation"
"Connexion requise"
@@ -1225,6 +1245,7 @@
"Nom"
"Version"
"Cron"
+ "Supprimer la phrase d’activation"
"Le code de configuration n’a pas été accepté. Générez un nouveau code avec openclaw qr."
"14 messages · Android"
"Échec de la transcription : %1$s"
@@ -1366,6 +1387,7 @@
"Désarchiver"
"Transcripts"
"Sessions récentes"
+ "Mots d’activation"
"Configurez %1$s sur le Gateway"
"Scannez un code QR ou utilisez le code de configuration de votre OpenClaw Gateway."
"Prototype de système de design"
diff --git a/apps/android/app/src/main/res/values-hi/strings.xml b/apps/android/app/src/main/res/values-hi/strings.xml
index cc8a1796111f..87c949b4295d 100644
--- a/apps/android/app/src/main/res/values-hi/strings.xml
+++ b/apps/android/app/src/main/res/values-hi/strings.xml
@@ -46,6 +46,7 @@
"डाउनलोड से पहले Gateway इस सटीक रिलीज़ को ClawHub से सत्यापित करेगा। यदि रिलीज़ के लिए जोखिम की स्पष्ट स्वीकृति आवश्यक है, तो दोबारा प्रयास करने से पहले Android Gateway चेतावनी दिखाएगा।"
"सेटअप कोड IPv6 ज़ोन ID का उपयोग करता है। बिना स्कोप वाला IPv6 पता या LAN होस्टनाम उपयोग करें।"
"अटैचमेंट"
+ "वेक वर्ड, बातचीत और प्लेबैक कॉन्फ़िगर करें।"
"सुन रहा है (PTT)"
"प्रस्ताव अस्वीकार किया गया."
"उपयोगकर्ता"
@@ -126,7 +127,6 @@
"Android सेटअप गाइड"
"%1$s ऐप्स को फ़ॉरवर्ड करने से ब्लॉक किया गया है।"
"पेयर किए गए डिवाइस"
- "आवाज़, ट्रांसपोर्ट, और प्लेबैक कॉन्फ़िगर करें।"
"%1$s लंबित"
"डिवाइस का नाम"
"स्थान"
@@ -151,6 +151,7 @@
"+%1$s और"
"thread create"
"अवरुद्ध"
+ "वेक वर्ड या वाक्यांश"
"Gateway को डिवाइस की स्वीकृति चाहिए"
"%1$s/%2$s तैयार"
"कनेक्टेड (ऑपरेटर ऑफ़लाइन)"
@@ -163,6 +164,7 @@
"इमेज"
"छवि पूर्वावलोकन बंद करें"
"eval"
+ "पिछला कमांड: %1$s"
"OpenClaw चला रहे डिवाइस पर terminal खुला रखें।"
"कोई आइटम अनुपलब्ध नहीं है"
"कैनवास आउटपुट के लिए सक्रिय Gateway कनेक्शन आवश्यक है।"
@@ -206,6 +208,7 @@
"Gateway से कनेक्ट किया जा रहा है"
"गेटवे इस पथ को बदल सकता है लेकिन मौजूदा पथ को हटा नहीं सकता।"
"TTS"
+ "सहेजा जा रहा है…"
"एंकर %1$s"
"search"
"शेड्यूल किए गए Gateway कार्य का निरीक्षण और प्रबंधन करें।"
@@ -369,6 +372,7 @@
"कूलडाउन %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "डिवाइस पर स्पीच रिकग्निशन उपलब्ध नहीं है।"
"एक संदेश के लिए अटैचमेंट कतार में लगाने हेतु बहुत बड़े हैं; कुछ हटाकर फिर से कोशिश करें।"
"1 मॉडल कॉन्फ़िगर किया गया है। उपलब्धता दोबारा जाँचने के लिए रीफ़्रेश करें।"
"इस होस्ट के लिए सुरक्षित कनेक्शन आवश्यक है।"
@@ -413,6 +417,7 @@
"जल्द"
"कोई Gateway स्वीकृतियाँ नहीं।"
"होस्ट"
+ "हर फ़ील्ड में एक वेक वर्ड या वाक्यांश जोड़ें। फिर अपना कमांड देने से पहले उनमें से एक बोलें।"
"ट्रांसक्राइब करें फिर भेजें"
"इस समय चलाएं"
"Gateway डिवाइस तक पहुँच"
@@ -475,6 +480,7 @@
"OpenClaw में खोजें"
"मुख्य सत्र"
"%1$s लंबित"
+ "डिवाइस पर वाक् पहचान उपलब्ध नहीं है"
"कोई भी ऐप यह संदेश साझा नहीं कर सकता"
"खोज बंद करें"
"देखने के लिए कमांड"
@@ -507,6 +513,7 @@
"Gateway टॉक कैटलॉग लोड नहीं हुआ"
"यह Gateway"
"अभी तक कोई हाल का रन नहीं।"
+ "डिवाइस पर भाषा मॉडल उपलब्ध नहीं है"
"एजेंट्स द्वारा पुन: उपयोग योग्य स्किल ड्राफ़्ट बनाने के बाद मिलान करने वाले प्रस्ताव यहाँ दिखाई देंगे."
"Session Search"
"OpenClaw बोल रहा है"
@@ -526,6 +533,7 @@
"स्क्रीन सतह तैयार है"
"Gateway पेयर करें"
"चैनल लोड करने के लिए gateway कनेक्ट करें।"
+ "अन्य वॉइस गतिविधि के दौरान रुक जाता है।"
"मॉडल"
"फ़ोटो"
"Setup Code पेस्ट करें"
@@ -566,10 +574,12 @@
"pin"
"%1$s कॉपी करें"
"पेयर किया गया"
+ "वेक वर्ड सहेजे नहीं जा सके"
"यह \"%1$s\" को क्वारंटीन करेगा और Gateway से Skill Workshop की स्थिति रीफ़्रेश करेगा।"
"वॉइस नोट रिकॉर्ड करें"
"अनुरोध किए जाने पर कैमरा टूल्स की अनुमति दें।"
"समस्याएँ"
+ "वॉइस वेक"
"%1$sदि. पहले"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"हाल के"
"समाधान का परिणाम अज्ञात है। Gateway रिकॉर्ड सत्यापित होने तक कार्रवाइयाँ अक्षम रहती हैं।"
"dialog"
+ "वेक वर्ड सुनें"
"camera snap"
"Gateway ने अज्ञात प्रदाता %1$s चुना"
"Android का अनुसरण करें · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway ने सक्रिय %1$s प्रदाता की पहचान नहीं की"
"प्रतीक्षा में"
+ "वेक वर्ड सहेजे गए"
"सबसे पुराने पहले"
"स्क्रीन"
"तब से चल रहा है"
@@ -645,6 +657,7 @@
"%1$s... (ठीक)"
"प्रदाता और कॉन्फ़िगर किए गए मॉडल"
"कनेक्ट हो रहा है…"
+ "वेक वर्ड सहेजने के लिए Gateway से कनेक्ट करें"
"प्रोफ़ाइल खोलें"
"अपना Gateway शुरू करें।"
"इस लक्ष्य को एक व्यावहारिक चेकलिस्ट में बदलने में मेरी मदद करें: "
@@ -700,6 +713,7 @@
"OpenClaw जवाब दे रहा है"
"दस्तावेज़"
"%1$s तैयार"
+ "डिवाइस की भाषा समर्थित नहीं है"
"कतार में — दोबारा कनेक्ट होने पर भेजा जाएगा"
"%1$sमि. पहले"
"पेयरिंग एक्सेस की जाँच की जा रही है"
@@ -731,6 +745,7 @@
"शेड्यूलर को यह ऑटोमेशन चलाने की अनुमति दें।"
"%1$s लागू किए गए"
"अभी तक कोई ड्रीम डायरी नहीं है।"
+ "OpenClaw दिखाई देने के दौरान डिवाइस पर चलता है।"
"%1$s काम कर रहा है"
"%1$s %2$s"
"कच्चा"
@@ -870,6 +885,7 @@
"ऑटोमेशन रोका गया।"
"OpenClaw मोबाइल"
"A2UI reset"
+ "Gateway उपलब्ध नहीं है"
"Read"
"इस skill के लिए 1 सेटअप आइटम आवश्यक है। Android दिखाता है कि क्या इंस्टॉल है; सेटअप/कॉन्फ़िगरेशन में बदलाव केवल desktop या CLI पर किए जा सकते हैं।"
"पिछला रन"
@@ -976,6 +992,7 @@
"अस्वीकृत"
"Android और बैकग्राउंड पैकेज शामिल करें।"
"आपका Gateway तैयार है।"
+ "ट्रिगर किया गया"
"इसमें अपेक्षा से अधिक समय लग रहा है।\nजाँचें कि Gateway चल रहा है और उस तक पहुँचा जा सकता है।"
"दोबारा कनेक्ट हो रहा है"
"OpenClaw gateway और नोड एक्सेस की जाँच कर रहा है।"
@@ -1021,6 +1038,7 @@
"सहेजा गया प्रमाणीकरण अमान्य है"
"%1$s स्कोप"
"हाल के लॉग लोड करने के लिए Gateway कनेक्ट करें।"
+ "वेक वर्ड सहेजें"
"इंस्टॉल किए गए Skills प्रबंधित करें और ClawHub से विश्वसनीय रिलीज़ जोड़ें।"
"भेजा जा रहा है…"
"अभी तक कोई एजेंट लोड नहीं हुआ है।"
@@ -1055,6 +1073,7 @@
"ऑफ़लाइन कतार भर गई है (%1$s संदेश); पहले कतारबद्ध आइटम हटाएँ।"
"सार्वजनिक Gateway के लिए wss:// या Tailscale Serve आवश्यक है। ws:// की अनुमति localhost, .local होस्ट, Android emulator और निजी LAN IP के लिए है।"
"Skill विवरण लोड करने के लिए Gateway कनेक्ट करें।"
+ "वेक लिसनर"
"लिंक पूर्वावलोकन विस्तृत करें"
"NULL (विफल)"
"अपडेट"
@@ -1196,6 +1215,7 @@
"यह फ़ोल्डर लोड नहीं हो सका."
"QR कोड में मान्य सेटअप कोड नहीं था।"
"नोड एक्सेस की समीक्षा करें"
+ "वेक वाक्यांश जोड़ें"
"Gateway तक नहीं पहुँचा जा सकता"
"ऑटोमेशन"
"कनेक्शन आवश्यक है"
@@ -1225,6 +1245,7 @@
"नाम"
"संस्करण"
"Cron"
+ "वेक वाक्यांश हटाएँ"
"सेटअप कोड स्वीकार नहीं किया गया। openclaw qr से नया कोड जनरेट करें।"
"14 संदेश · Android"
"ट्रांसक्रिप्शन विफल रहा: %1$s"
@@ -1366,6 +1387,7 @@
"अनआर्काइव करें"
"Transcripts"
"हाल के सेशन"
+ "वेक वर्ड"
"Gateway पर %1$s कॉन्फ़िगर करें"
"QR कोड स्कैन करें या अपने OpenClaw Gateway से सेटअप कोड का उपयोग करें।"
"डिज़ाइन सिस्टम प्रोटोटाइप"
diff --git a/apps/android/app/src/main/res/values-in/strings.xml b/apps/android/app/src/main/res/values-in/strings.xml
index af964fa0464b..20e63fb125d7 100644
--- a/apps/android/app/src/main/res/values-in/strings.xml
+++ b/apps/android/app/src/main/res/values-in/strings.xml
@@ -46,6 +46,7 @@
"Gateway akan memverifikasi rilis ini secara persis dengan ClawHub sebelum mengunduh. Jika rilis memerlukan pengakuan risiko secara eksplisit, Android akan menampilkan peringatan Gateway sebelum mencoba kembali."
"Kode penyiapan menggunakan ID zona IPv6. Gunakan alamat IPv6 tanpa cakupan atau nama host LAN."
"Lampiran"
+ "Konfigurasikan kata aktivasi, percakapan, dan pemutaran."
"Mendengarkan (PTT)"
"Proposal ditolak."
"pengguna"
@@ -126,7 +127,6 @@
"Panduan penyiapan Android"
"%1$s aplikasi diblokir agar tidak meneruskan."
"Perangkat yang Dipasangkan"
- "Konfigurasikan suara, transport, dan pemutaran."
"%1$s tertunda"
"Nama perangkat"
"Lokasi"
@@ -151,6 +151,7 @@
"+%1$s lagi"
"thread create"
"Diblokir"
+ "Kata atau frasa aktivasi"
"Gateway memerlukan persetujuan perangkat"
"%1$s/%2$s siap"
"Terhubung (operator offline)"
@@ -163,6 +164,7 @@
"Gambar"
"Tutup pratinjau gambar"
"eval"
+ "Perintah terakhir: %1$s"
"Buka terminal di perangkat yang menjalankan OpenClaw."
"Tidak ada item yang belum tersedia"
"Output kanvas memerlukan koneksi Gateway aktif."
@@ -206,6 +208,7 @@
"Menghubungkan Gateway"
"Gateway dapat mengubah jalur ini tetapi tidak dapat menghapus jalur yang sudah ada."
"TTS"
+ "Menyimpan…"
"Patokan %1$s"
"search"
"Periksa dan kelola pekerjaan Gateway terjadwal."
@@ -369,6 +372,7 @@
"Waktu tunggu %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Pengenalan ucapan di perangkat tidak tersedia."
"Lampiran terlalu besar untuk dimasukkan ke antrean dalam satu pesan; hapus beberapa lampiran lalu coba lagi."
"1 model dikonfigurasi. Segarkan untuk memeriksa kembali ketersediaan."
"Koneksi aman diperlukan untuk host ini."
@@ -413,6 +417,7 @@
"segera"
"Tidak ada persetujuan gateway."
"Host"
+ "Tambahkan satu kata atau frasa aktivasi per kolom. Kemudian ucapkan salah satunya sebelum perintah Anda."
"Transkripsikan lalu kirim"
"Jalankan pada"
"Akses ke perangkat Gateway"
@@ -475,6 +480,7 @@
"Cari OpenClaw"
"Sesi utama"
"%1$s tertunda"
+ "Pengenalan ucapan di perangkat tidak tersedia"
"Tidak ada aplikasi yang dapat membagikan pesan ini"
"Tutup pencarian"
"Perintah untuk dipantau"
@@ -507,6 +513,7 @@
"Katalog bicara Gateway belum dimuat"
"gateway ini"
"Belum ada proses terbaru."
+ "Model bahasa di perangkat tidak tersedia"
"Proposal yang cocok akan muncul di sini setelah agen membuat draf skill yang dapat digunakan kembali."
"Session Search"
"OpenClaw sedang berbicara"
@@ -526,6 +533,7 @@
"Permukaan layar siap"
"Pasangkan Gateway"
"Hubungkan gateway untuk memuat saluran."
+ "Dijeda selama ada aktivitas suara lain."
"Model"
"Foto"
"Tempel kode penyiapan"
@@ -566,10 +574,12 @@
"pin"
"Salin %1$s"
"Dipasangkan"
+ "Tidak dapat menyimpan kata aktivasi"
"Tindakan ini akan mengarantina \"%1$s\" dan memuat ulang status Skill Workshop dari Gateway."
"Rekam catatan suara"
"Izinkan alat kamera saat diminta."
"Masalah"
+ "Bangun Suara"
"%1$s hari lalu"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Terbaru"
"Hasil penyelesaian tidak diketahui. Tindakan tetap dinonaktifkan hingga catatan Gateway diverifikasi."
"dialog"
+ "Dengarkan kata aktivasi"
"camera snap"
"Gateway memilih penyedia tidak dikenal %1$s"
"Ikuti Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway tidak mengidentifikasi penyedia %1$s yang aktif"
"Menunggu"
+ "Kata aktivasi disimpan"
"Terlama dahulu"
"Layar"
"Berjalan Sejak"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Penyedia dan model yang dikonfigurasi"
"Menghubungkan…"
+ "Hubungkan ke Gateway untuk menyimpan kata aktivasi"
"Buka profil"
"Mulai Gateway Anda."
"Bantu saya mengubah tujuan ini menjadi daftar periksa yang praktis: "
@@ -700,6 +713,7 @@
"OpenClaw sedang membalas"
"Dokumentasi"
"%1$s siap"
+ "Bahasa perangkat tidak didukung"
"Dalam antrean — dikirim saat terhubung kembali"
"%1$s mnt lalu"
"Memeriksa akses pemasangan"
@@ -731,6 +745,7 @@
"Izinkan penjadwal menjalankan otomatisasi ini."
"%1$s diterapkan"
"Belum ada diary mimpi."
+ "Berjalan di perangkat saat OpenClaw terlihat."
"%1$s sedang bekerja"
"%1$s %2$s"
"Mentah"
@@ -870,6 +885,7 @@
"Automasi dijeda."
"OpenClaw seluler"
"A2UI reset"
+ "Gateway tidak tersedia"
"Read"
"Skill ini memerlukan 1 item penyiapan. Android menampilkan apa yang sudah terinstal; perubahan penyiapan/konfigurasi tetap dilakukan melalui desktop atau CLI."
"Eksekusi Terakhir"
@@ -976,6 +992,7 @@
"Ditolak"
"Sertakan paket Android dan latar belakang."
"Gateway Anda siap."
+ "Terpicu"
"Proses ini memakan waktu lebih lama dari yang diperkirakan.\nPastikan Gateway berjalan dan dapat dijangkau."
"Menyambungkan kembali"
"OpenClaw sedang memeriksa akses Gateway dan node."
@@ -1021,6 +1038,7 @@
"Autentikasi yang disimpan tidak valid"
"%1$s cakupan"
"Hubungkan gateway untuk memuat log terbaru."
+ "Simpan kata aktivasi"
"Kelola skill yang terinstal dan tambahkan rilis tepercaya dari ClawHub."
"Mengirim…"
"Belum ada agen yang dimuat."
@@ -1055,6 +1073,7 @@
"Antrean offline penuh (%1$s pesan); hapus item yang mengantre terlebih dahulu."
"Gateway publik memerlukan wss:// atau Tailscale Serve. ws:// diizinkan untuk localhost, host .local, emulator Android, dan IP LAN privat."
"Hubungkan gateway untuk memuat detail skill."
+ "Pendengar kata aktivasi"
"Perluas pratinjau tautan"
"NULL (GAGAL)"
"Perbarui"
@@ -1196,6 +1215,7 @@
"Tidak dapat memuat folder ini."
"Kode QR tidak berisi kode penyiapan yang valid."
"Tinjau akses node"
+ "Tambahkan frasa aktivasi"
"Tidak dapat menjangkau gateway"
"Otomatisasi"
"Memerlukan koneksi"
@@ -1225,6 +1245,7 @@
"Nama"
"Versi"
"Cron"
+ "Hapus frasa aktivasi"
"Kode penyiapan tidak diterima. Buat kode baru dengan openclaw qr."
"14 pesan · Android"
"Transkripsi gagal: %1$s"
@@ -1366,6 +1387,7 @@
"Batalkan arsip"
"Transcripts"
"Sesi Terbaru"
+ "Kata aktivasi"
"Konfigurasikan %1$s di Gateway"
"Pindai kode QR atau gunakan kode penyiapan dari OpenClaw Gateway Anda."
"Prototipe sistem desain"
diff --git a/apps/android/app/src/main/res/values-it/strings.xml b/apps/android/app/src/main/res/values-it/strings.xml
index 8f487a0cb3b7..f7fc0e3987a0 100644
--- a/apps/android/app/src/main/res/values-it/strings.xml
+++ b/apps/android/app/src/main/res/values-it/strings.xml
@@ -46,6 +46,7 @@
"Il Gateway verificherà questa specifica versione con ClawHub prima del download. Se la versione richiede un\'accettazione esplicita del rischio, Android mostrerà l\'avviso del Gateway prima di riprovare."
"Il codice di configurazione usa un ID di zona IPv6. Usa un indirizzo IPv6 senza ambito o un hostname LAN."
"Allegato"
+ "Configura le parole di attivazione, la conversazione e la riproduzione."
"In ascolto (PTT)"
"Proposta rifiutata."
"utente"
@@ -126,7 +127,6 @@
"Guida alla configurazione Android"
"%1$s app bloccate dall\'inoltro."
"Dispositivi associati"
- "Configura voce, trasporto e riproduzione."
"%1$s in sospeso"
"Nome dispositivo"
"Posizione"
@@ -151,6 +151,7 @@
"+%1$s altri"
"thread create"
"Bloccata"
+ "Parola o frase di attivazione"
"Il Gateway richiede l\'approvazione del dispositivo"
"%1$s/%2$s pronte"
"Connesso (operatore offline)"
@@ -163,6 +164,7 @@
"Immagine"
"Chiudi anteprima immagine"
"eval"
+ "Ultimo comando: %1$s"
"Tieni aperto un terminale sul dispositivo che esegue OpenClaw."
"Nessun elemento mancante"
"L’output del canvas richiede una connessione al gateway attiva."
@@ -206,6 +208,7 @@
"Connessione al Gateway"
"Il gateway può modificare questo percorso ma non può cancellare un percorso esistente."
"TTS"
+ "Salvataggio…"
"Ancoraggio %1$s"
"search"
"Visualizza e gestisci le attività pianificate del Gateway."
@@ -369,6 +372,7 @@
"Attesa %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Il riconoscimento vocale sul dispositivo non è disponibile."
"Gli allegati sono troppo grandi per essere messi in coda in un solo messaggio; rimuovine alcuni e riprova."
"1 modello configurato. Aggiorna per verificare nuovamente la disponibilità."
"Per questo host è necessaria una connessione sicura."
@@ -413,6 +417,7 @@
"a breve"
"Nessuna approvazione Gateway."
"Host"
+ "Aggiungi una parola o una frase di attivazione per campo. Quindi pronunciane una prima del comando."
"Trascrivi e poi invia"
"Esegui alle"
"Accesso al dispositivo Gateway"
@@ -475,6 +480,7 @@
"Cerca in OpenClaw"
"Sessione principale"
"%1$s in sospeso"
+ "Riconoscimento vocale sul dispositivo non disponibile"
"Nessuna app può condividere questo messaggio"
"Chiudi ricerca"
"Comando da monitorare"
@@ -507,6 +513,7 @@
"Catalogo conversazioni Gateway non caricato"
"questo Gateway"
"Ancora nessuna esecuzione recente."
+ "Modello linguistico sul dispositivo non disponibile"
"Le proposte corrispondenti appariranno qui dopo che gli agenti avranno creato bozze di skill riutilizzabili."
"Session Search"
"OpenClaw sta parlando"
@@ -526,6 +533,7 @@
"Superficie dello schermo pronta"
"Associa Gateway"
"Connetti il Gateway per caricare i canali."
+ "Si mette in pausa durante altre attività vocali."
"Modello"
"Foto"
"Incolla codice di configurazione"
@@ -566,10 +574,12 @@
"pin"
"Copia %1$s"
"Associato"
+ "Impossibile salvare le parole di attivazione"
"Verrà messa in quarantena \"%1$s\" e lo stato di Skill Workshop verrà aggiornato dal gateway."
"Registra nota vocale"
"Consenti gli strumenti della fotocamera quando richiesto."
"Problemi"
+ "Attivazione vocale"
"%1$s g fa"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Recenti"
"Esito della risoluzione sconosciuto. Le azioni restano disabilitate finché il record del Gateway non viene verificato."
"dialog"
+ "Ascolta le parole di attivazione"
"camera snap"
"Gateway ha selezionato il provider sconosciuto %1$s"
"Segui Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway non ha identificato il provider %1$s attivo"
"In attesa"
+ "Parole di attivazione salvate"
"Prima i più vecchi"
"Schermo"
"In esecuzione da"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Provider e modelli configurati"
"Connessione…"
+ "Connettiti a un Gateway per salvare le parole di attivazione"
"Apri profilo"
"Avvia il tuo Gateway."
"Aiutami a trasformare questo obiettivo in una checklist pratica: "
@@ -700,6 +713,7 @@
"OpenClaw sta rispondendo"
"Documentazione"
"%1$s pronti"
+ "Lingua del dispositivo non supportata"
"In coda — verrà inviato alla riconnessione"
"%1$s min fa"
"Verifica dell\'accesso all\'associazione"
@@ -731,6 +745,7 @@
"Consenti allo strumento di pianificazione di eseguire questa automazione."
"%1$s applicati"
"Nessun diario dei sogni al momento."
+ "Viene eseguito sul dispositivo mentre OpenClaw è visibile."
"%1$s è al lavoro"
"%1$s %2$s"
"Non elaborato"
@@ -870,6 +885,7 @@
"Automazione sospesa."
"OpenClaw mobile"
"A2UI reset"
+ "Gateway non disponibile"
"Read"
"Questa skill richiede 1 elemento di configurazione. Android mostra ciò che è installato; le modifiche alla configurazione devono essere effettuate da desktop o tramite CLI."
"Ultima esecuzione"
@@ -976,6 +992,7 @@
"Rifiutato"
"Includi Android e i pacchetti in background."
"Il tuo Gateway è pronto."
+ "Attivato"
"L\'operazione sta richiedendo più tempo del previsto.\nVerifica che il Gateway sia in esecuzione e raggiungibile."
"Riconnessione"
"OpenClaw sta verificando l\'accesso al Gateway e al nodo."
@@ -1021,6 +1038,7 @@
"Autenticazione salvata non valida"
"%1$s ambiti"
"Connetti il Gateway per caricare i log recenti."
+ "Salva le parole di attivazione"
"Gestisci le skill installate e aggiungi release attendibili da ClawHub."
"Invio in corso…"
"Nessun agente ancora caricato."
@@ -1055,6 +1073,7 @@
"La coda offline è piena (%1$s messaggi); elimina prima gli elementi in coda."
"I gateway pubblici richiedono wss:// o Tailscale Serve. ws:// è consentito per localhost, host .local, l\'emulatore Android e gli IP LAN privati."
"Connetti il gateway per caricare i dettagli della Skill."
+ "Rilevamento dell\'attivazione"
"Espandi anteprima link"
"NULL (NON RIUSCITO)"
"Aggiorna"
@@ -1196,6 +1215,7 @@
"Impossibile caricare questa cartella."
"Il codice QR non conteneva un codice di configurazione valido."
"Controlla l\'accesso al nodo"
+ "Aggiungi frase di attivazione"
"Impossibile raggiungere il Gateway"
"Automazione"
"Connessione necessaria"
@@ -1225,6 +1245,7 @@
"Nome"
"Versione"
"Cron"
+ "Rimuovi frase di attivazione"
"Il codice di configurazione non è stato accettato. Genera un nuovo codice con openclaw qr."
"14 messaggi · Android"
"Trascrizione non riuscita: %1$s"
@@ -1366,6 +1387,7 @@
"Rimuovi dall\'archivio"
"Transcripts"
"Sessioni recenti"
+ "Parole di attivazione"
"Configura %1$s sul Gateway"
"Scansiona un codice QR o usa il codice di configurazione dal tuo OpenClaw Gateway."
"Prototipo del design system"
diff --git a/apps/android/app/src/main/res/values-ja/strings.xml b/apps/android/app/src/main/res/values-ja/strings.xml
index 52340abe0191..9d47c82820c1 100644
--- a/apps/android/app/src/main/res/values-ja/strings.xml
+++ b/apps/android/app/src/main/res/values-ja/strings.xml
@@ -46,6 +46,7 @@
"ダウンロード前に、GatewayがClawHubでこのリリースを正確に検証します。リリースにリスクへの明示的な同意が必要な場合、Androidは再試行する前にGatewayの警告を表示します。"
"セットアップコードに IPv6 ゾーン ID が使用されています。スコープなしの IPv6 アドレスまたは LAN ホスト名を使用してください。"
"添付ファイル"
+ "ウェイクワード、会話、再生を設定します。"
"聞き取り中(PTT)"
"提案が却下されました。"
"ユーザー"
@@ -126,7 +127,6 @@
"Android セットアップガイド"
"%1$s 個のアプリの転送をブロックしました。"
"ペアリング済みデバイス"
- "音声、転送、再生を設定します。"
"%1$s件保留中"
"デバイス名"
"位置情報"
@@ -151,6 +151,7 @@
"+%1$s 件追加"
"thread create"
"ブロック済み"
+ "ウェイクワードまたはフレーズ"
"Gatewayでデバイスの承認が必要です"
"%1$s/%2$s件準備完了"
"接続済み(オペレーターはオフライン)"
@@ -163,6 +164,7 @@
"画像"
"画像プレビューを閉じる"
"eval"
+ "最後のコマンド: %1$s"
"OpenClaw を実行しているデバイスでターミナルを開いておいてください。"
"不足している項目はありません"
"キャンバス出力には、有効なGateway接続が必要です。"
@@ -206,6 +208,7 @@
"Gatewayに接続中"
"gatewayはこのパスを変更できますが、既存のパスを消去することはできません。"
"TTS"
+ "保存中…"
"基準 %1$s"
"search"
"スケジュールされたGatewayの処理を確認・管理します。"
@@ -369,6 +372,7 @@
"クールダウン %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "デバイス上の音声認識は利用できません。"
"添付ファイルが大きすぎるため、1件のメッセージとしてキューに追加できません。一部を削除して、もう一度お試しください。"
"設定済みのモデルが1件あります。更新して利用可能か再確認してください。"
"このホストには安全な接続が必要です。"
@@ -413,6 +417,7 @@
"まもなく"
"Gateway の承認はありません。"
"ホスト"
+ "各フィールドにウェイクワードまたはフレーズを1つずつ追加してください。その後、コマンドの前にそのいずれかを話してください。"
"文字起こしして送信"
"実行時刻"
"Gateway デバイスへのアクセス"
@@ -475,6 +480,7 @@
"OpenClaw を検索"
"メインセッション"
"%1$s件保留中"
+ "デバイス上の音声認識は利用できません"
"このメッセージを共有できるアプリがありません"
"検索を閉じる"
"監視するコマンド"
@@ -507,6 +513,7 @@
"Gateway のトークカタログが読み込まれていません"
"このGateway"
"最近の実行はまだありません。"
+ "デバイス上の言語モデルは利用できません"
"エージェントが再利用可能な Skill のドラフトを作成すると、一致する提案がここに表示されます。"
"Session Search"
"OpenClawが話しています"
@@ -526,6 +533,7 @@
"画面サーフェスの準備ができました"
"Gatewayをペアリング"
"チャンネルを読み込むには Gateway に接続してください。"
+ "他の音声アクティビティ中は一時停止します。"
"モデル"
"写真"
"セットアップコードを貼り付け"
@@ -566,10 +574,12 @@
"pin"
"%1$sをコピー"
"ペアリング済み"
+ "ウェイクワードを保存できませんでした"
"「%1$s」を隔離し、GatewayからSkill Workshopの状態を更新します。"
"ボイスノートを録音"
"要求された場合にカメラツールを許可します。"
"問題"
+ "音声ウェイク"
"%1$s日前"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"最近"
"解決結果が不明です。Gateway の記録が確認されるまで操作は無効のままです。"
"dialog"
+ "ウェイクワードを聞き取る"
"camera snap"
"Gateway が不明なプロバイダー %1$s を選択しました"
"Androidに従う · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway がアクティブな %1$s プロバイダーを識別しませんでした"
"待機中"
+ "ウェイクワードを保存しました"
"古い順"
"画面"
"実行開始日時"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"プロバイダーと設定済みモデル"
"接続中…"
+ "ウェイクワードを保存するには Gateway に接続してください"
"プロフィールを開く"
"Gateway を起動します。"
"この目標を実用的なチェックリストに変換してください: "
@@ -700,6 +713,7 @@
"OpenClawが応答中"
"ドキュメント"
"%1$s 件が準備完了"
+ "デバイスの言語はサポートされていません"
"キューに追加済み — 再接続時に送信されます"
"%1$s分前"
"ペアリングアクセスを確認中"
@@ -731,6 +745,7 @@
"スケジューラーによるこの自動化の実行を許可します。"
"%1$s 件適用済み"
"夢日記はまだありません。"
+ "OpenClaw の表示中にデバイス上で動作します。"
"%1$s が作業中です"
"%1$s %2$s"
"未加工"
@@ -870,6 +885,7 @@
"自動化を一時停止しました。"
"OpenClaw モバイル"
"A2UI reset"
+ "Gatewayは利用できません"
"Read"
"このスキルには1件のセットアップ項目が必要です。Androidではインストール済みの内容を確認できます。セットアップや設定の変更はデスクトップかCLIから行ってください。"
"前回の実行"
@@ -976,6 +992,7 @@
"拒否済み"
"Android とバックグラウンドのパッケージを含めます。"
"Gatewayの準備ができました。"
+ "トリガーされました"
"予想より時間がかかっています。\nGatewayが起動していて、接続可能であることを確認してください。"
"再接続中"
"OpenClaw が Gateway とノードへのアクセスを確認しています。"
@@ -1021,6 +1038,7 @@
"保存済みの認証情報が無効です"
"%1$s件のスコープ"
"最近のログを読み込むには、Gatewayに接続してください。"
+ "ウェイクワードを保存"
"インストール済みのスキルを管理し、ClawHubから信頼できるリリースを追加します。"
"送信中…"
"エージェントはまだ読み込まれていません。"
@@ -1055,6 +1073,7 @@
"オフラインキューが上限(%1$s件)に達しています。先にキュー内の項目を削除してください。"
"公開Gatewayにはwss://またはTailscale Serveが必要です。ws://はlocalhost、.localホスト、Androidエミュレーター、およびプライベートLAN IPで使用できます。"
"Skillsの詳細を読み込むには、Gatewayに接続してください。"
+ "ウェイクリスナー"
"リンクのプレビューを展開"
"NULL (FAILED)"
"更新"
@@ -1196,6 +1215,7 @@
"このフォルダを読み込めませんでした。"
"QRコードに有効なセットアップコードが含まれていませんでした。"
"ノードへのアクセスを確認"
+ "ウェイクフレーズを追加"
"Gatewayに接続できません"
"自動化"
"接続が必要です"
@@ -1225,6 +1245,7 @@
"名前"
"バージョン"
"Cron"
+ "ウェイクフレーズを削除"
"セットアップコードが受け付けられませんでした。openclaw qr で新しいコードを生成してください。"
"14 件のメッセージ · Android"
"文字起こしに失敗しました: %1$s"
@@ -1366,6 +1387,7 @@
"アーカイブを解除"
"Transcripts"
"最近のセッション"
+ "ウェイクワード"
"Gateway で %1$s を設定してください"
"QR コードをスキャンするか、OpenClaw Gateway からのセットアップコードを使用します。"
"デザインシステムのプロトタイプ"
diff --git a/apps/android/app/src/main/res/values-ko/strings.xml b/apps/android/app/src/main/res/values-ko/strings.xml
index b6d9c3c8eea4..c40b3005cfd8 100644
--- a/apps/android/app/src/main/res/values-ko/strings.xml
+++ b/apps/android/app/src/main/res/values-ko/strings.xml
@@ -46,6 +46,7 @@
"Gateway는 다운로드 전에 ClawHub에서 이 정확한 릴리스를 확인합니다. 릴리스에 명시적인 위험 확인이 필요한 경우, Android는 재시도하기 전에 Gateway 경고를 표시합니다."
"설정 코드가 IPv6 영역 ID를 사용합니다. 범위가 지정되지 않은 IPv6 주소 또는 LAN 호스트 이름을 사용하세요."
"첨부 파일"
+ "호출어, 대화 및 재생을 설정합니다."
"듣는 중(PTT)"
"제안이 거부되었습니다."
"사용자"
@@ -126,7 +127,6 @@
"Android 설정 가이드"
"%1$s개 앱의 전달이 차단되었습니다."
"페어링된 기기"
- "음성, 전송 및 재생을 구성하세요."
"%1$s개 대기 중"
"기기 이름"
"위치"
@@ -151,6 +151,7 @@
"+%1$s개 더"
"thread create"
"차단됨"
+ "호출어 또는 문구"
"Gateway에 기기 승인이 필요합니다"
"%1$s/%2$s개 준비됨"
"연결됨(운영자 오프라인)"
@@ -163,6 +164,7 @@
"이미지"
"이미지 미리 보기 닫기"
"eval"
+ "마지막 명령: %1$s"
"OpenClaw를 실행 중인 기기에서 터미널을 열어 두세요."
"누락된 항목 없음"
"캔버스 출력에는 활성 Gateway 연결이 필요합니다."
@@ -206,6 +208,7 @@
"Gateway 연결 중"
"gateway는 이 경로를 변경할 수 있지만 기존 경로를 지울 수는 없습니다."
"TTS"
+ "저장 중…"
"기준 %1$s"
"search"
"예약된 Gateway 작업을 확인하고 관리합니다."
@@ -369,6 +372,7 @@
"대기 시간 %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "기기 내 음성 인식을 사용할 수 없습니다."
"첨부 파일이 너무 커서 하나의 메시지로 대기열에 추가할 수 없습니다. 일부를 제거한 후 다시 시도하세요."
"구성된 모델이 1개 있습니다. 새로 고쳐 사용 가능 여부를 다시 확인하세요."
"이 호스트에는 보안 연결이 필요합니다."
@@ -413,6 +417,7 @@
"곧"
"Gateway 승인이 없습니다."
"호스트"
+ "필드마다 호출어나 문구를 하나씩 추가하세요. 그런 다음 명령 전에 하나를 말하세요."
"전사한 후 보내기"
"실행 시각"
"Gateway 기기에 대한 액세스"
@@ -475,6 +480,7 @@
"OpenClaw 검색"
"기본 세션"
"%1$s개 대기 중"
+ "기기 내 음성 인식을 사용할 수 없음"
"이 메시지를 공유할 수 있는 앱이 없습니다"
"검색 닫기"
"감시할 명령"
@@ -507,6 +513,7 @@
"Gateway 토크 카탈로그가 로드되지 않음"
"이 Gateway"
"아직 최근 실행이 없습니다."
+ "기기 내 언어 모델을 사용할 수 없음"
"에이전트가 재사용 가능한 스킬 초안을 만들면 일치하는 제안이 여기에 표시됩니다."
"Session Search"
"OpenClaw가 말하는 중"
@@ -526,6 +533,7 @@
"화면 표면 준비됨"
"Gateway 페어링"
"채널을 불러오려면 Gateway를 연결하세요."
+ "다른 음성 활동 중에는 일시 중지됩니다."
"모델"
"사진"
"설정 코드 붙여넣기"
@@ -566,10 +574,12 @@
"pin"
"%1$s 복사"
"페어링됨"
+ "호출어를 저장할 수 없습니다"
"이 작업은 \"%1$s\"을(를) 격리하고 Gateway에서 Skill Workshop 상태를 새로 고칩니다."
"음성 메모 녹음"
"요청 시 카메라 도구를 허용합니다."
"문제"
+ "음성 깨우기"
"%1$s일 전"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"최근"
"처리 결과를 알 수 없습니다. Gateway 기록이 확인될 때까지 작업이 비활성화됩니다."
"dialog"
+ "호출어 감지"
"camera snap"
"Gateway에서 알 수 없는 제공자 %1$s을(를) 선택했습니다"
"Android 설정 따르기 · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway에서 활성 %1$s 제공자를 식별하지 않았습니다"
"대기 중"
+ "호출어가 저장되었습니다"
"오래된순"
"화면"
"실행 시작 시각"
@@ -645,6 +657,7 @@
"%1$s... (정상)"
"제공자 및 구성된 모델"
"연결 중…"
+ "호출어를 저장하려면 Gateway에 연결하세요"
"프로필 열기"
"Gateway를 시작하세요."
"이 목표를 실용적인 체크리스트로 만드는 것을 도와주세요: "
@@ -700,6 +713,7 @@
"OpenClaw가 응답 중입니다"
"문서"
"%1$s개 준비됨"
+ "기기 언어가 지원되지 않음"
"대기 중 — 다시 연결되면 전송"
"%1$s분 전"
"페어링 액세스 확인 중"
@@ -731,6 +745,7 @@
"스케줄러가 이 자동화를 실행하도록 허용합니다."
"%1$s개 적용됨"
"아직 꿈 일기가 없습니다."
+ "OpenClaw가 표시되는 동안 기기에서 실행됩니다."
"%1$s 작업 중"
"%1$s %2$s"
"원시"
@@ -870,6 +885,7 @@
"자동화가 일시 중지되었습니다."
"OpenClaw 모바일"
"A2UI reset"
+ "Gateway를 사용할 수 없음"
"Read"
"이 Skills에는 설정 항목 1개가 필요합니다. Android에서는 설치된 항목을 확인할 수 있습니다. 설정/구성 변경은 데스크톱 또는 CLI에서만 가능합니다."
"마지막 실행"
@@ -976,6 +992,7 @@
"거부됨"
"Android 및 백그라운드 패키지를 포함합니다."
"Gateway가 준비되었습니다."
+ "트리거됨"
"예상보다 오래 걸리고 있습니다.\nGateway가 실행 중이며 연결 가능한지 확인하세요."
"다시 연결 중"
"OpenClaw가 Gateway 및 노드 액세스를 확인하고 있습니다."
@@ -1021,6 +1038,7 @@
"저장된 인증이 올바르지 않습니다"
"범위 %1$s개"
"최근 로그를 불러오려면 Gateway를 연결하세요."
+ "호출어 저장"
"설치된 Skill을 관리하고 ClawHub에서 신뢰할 수 있는 릴리스를 추가하세요."
"전송 중…"
"아직 불러온 에이전트가 없습니다."
@@ -1055,6 +1073,7 @@
"오프라인 대기열이 가득 찼습니다(%1$s개 메시지). 먼저 대기 중인 항목을 삭제하세요."
"공개 Gateway에는 wss:// 또는 Tailscale Serve가 필요합니다. ws://는 localhost, .local 호스트, Android 에뮬레이터 및 사설 LAN IP에서 허용됩니다."
"스킬 세부 정보를 불러오려면 Gateway를 연결하세요."
+ "호출어 감지"
"링크 미리보기 펼치기"
"NULL (실패)"
"업데이트"
@@ -1196,6 +1215,7 @@
"이 폴더를 불러올 수 없습니다."
"QR 코드에 유효한 설정 코드가 포함되어 있지 않습니다."
"노드 액세스를 검토하세요"
+ "호출 문구 추가"
"Gateway에 연결할 수 없음"
"자동화"
"연결 필요"
@@ -1225,6 +1245,7 @@
"이름"
"버전"
"Cron"
+ "호출 문구 제거"
"설정 코드가 승인되지 않았습니다. openclaw qr로 새 코드를 생성하세요."
"메시지 14개 · Android"
"텍스트 변환 실패: %1$s"
@@ -1366,6 +1387,7 @@
"보관 해제"
"Transcripts"
"최근 세션"
+ "호출어"
"Gateway에서 %1$s 구성"
"QR 코드를 스캔하거나 OpenClaw Gateway의 설정 코드를 사용하세요."
"디자인 시스템 프로토타입"
diff --git a/apps/android/app/src/main/res/values-nl/strings.xml b/apps/android/app/src/main/res/values-nl/strings.xml
index 1b4b66ada06d..95fbdf3dc67b 100644
--- a/apps/android/app/src/main/res/values-nl/strings.xml
+++ b/apps/android/app/src/main/res/values-nl/strings.xml
@@ -46,6 +46,7 @@
"De Gateway verifieert deze exacte release vóór het downloaden bij ClawHub. Als voor de release expliciete risicoacceptatie vereist is, toont Android de Gateway-waarschuwing voordat het opnieuw probeert."
"Installatiecode gebruikt een IPv6-zone-ID. Gebruik een IPv6-adres zonder scope of een LAN-hostnaam."
"Bijlage"
+ "Configureer activeringswoorden, spraak en afspelen."
"Luisteren (PTT)"
"Voorstel afgewezen."
"gebruiker"
@@ -126,7 +127,6 @@
"Android-installatiehandleiding"
"%1$s apps zijn geblokkeerd voor doorsturen."
"Gekoppelde apparaten"
- "Configureer spraak, transport en afspelen."
"%1$s openstaand"
"Apparaatnaam"
"Locatie"
@@ -151,6 +151,7 @@
"+%1$s meer"
"thread create"
"Geblokkeerd"
+ "Activeringswoord of activeringszin"
"Gateway vereist apparaatgoedkeuring"
"%1$s/%2$s gereed"
"Verbonden (operator offline)"
@@ -163,6 +164,7 @@
"Afbeelding"
"Afbeeldingsvoorbeeld sluiten"
"eval"
+ "Laatste opdracht: %1$s"
"Zorg dat er een terminal openstaat op het apparaat waarop OpenClaw draait."
"Geen ontbrekende items"
"Canvas-uitvoer vereist een actieve Gateway-verbinding."
@@ -206,6 +208,7 @@
"Verbinding maken met Gateway"
"De gateway kan dit pad wijzigen maar kan een bestaand pad niet wissen."
"TTS"
+ "Opslaan…"
"Anker %1$s"
"search"
"Bekijk en beheer gepland Gateway-werk."
@@ -369,6 +372,7 @@
"Afkoelperiode %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"Sms"
+ "Spraakherkenning op het apparaat is niet beschikbaar."
"De bijlagen zijn te groot om voor één bericht in de wachtrij te plaatsen; verwijder er enkele en probeer het opnieuw."
"1 geconfigureerd model. Vernieuw om de beschikbaarheid opnieuw te controleren."
"Voor deze host is een beveiligde verbinding vereist."
@@ -413,6 +417,7 @@
"binnenkort"
"Geen Gateway-goedkeuringen."
"Host"
+ "Voeg per veld één activeringswoord of één activeringszin toe. Zeg er vervolgens één vóór uw opdracht."
"Transcriberen en daarna verzenden"
"Uitvoeren om"
"Toegang tot het Gateway-apparaat"
@@ -475,6 +480,7 @@
"Zoeken in OpenClaw"
"Hoofdsessie"
"%1$s openstaand"
+ "Spraakherkenning op het apparaat niet beschikbaar"
"Geen enkele app kan dit bericht delen"
"Zoeken sluiten"
"Commando om te bewaken"
@@ -507,6 +513,7 @@
"Gateway-talkcatalogus niet geladen"
"deze gateway"
"Nog geen recente runs."
+ "Taalmodel op het apparaat niet beschikbaar"
"Overeenkomende voorstellen verschijnen hier nadat agents herbruikbare skillconcepten hebben gemaakt."
"Session Search"
"OpenClaw spreekt"
@@ -526,6 +533,7 @@
"Schermoppervlak gereed"
"Gateway koppelen"
"Verbind de gateway om kanalen te laden."
+ "Wordt gepauzeerd tijdens andere spraakactiviteit."
"Model"
"Foto\'s"
"Installatiecode plakken"
@@ -566,10 +574,12 @@
"pin"
"%1$s kopiëren"
"Gekoppeld"
+ "Kan activeringswoorden niet opslaan"
"Hiermee wordt \"%1$s\" in quarantaine geplaatst en wordt de status van Skill Workshop vernieuwd vanuit de gateway."
"Spraakbericht opnemen"
"Cameratools toestaan wanneer daarom wordt gevraagd."
"Problemen"
+ "Spraakactivering"
"%1$sd geleden"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Recent"
"Uitkomst van de afhandeling onbekend. Acties blijven uitgeschakeld totdat de Gateway-record is geverifieerd."
"dialog"
+ "Luisteren naar activeringswoorden"
"camera snap"
"Gateway heeft onbekende provider %1$s geselecteerd"
"Volg Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway heeft de actieve %1$s-provider niet geïdentificeerd"
"Wachten"
+ "Activeringswoorden opgeslagen"
"Oudste eerst"
"Scherm"
"Actief sinds"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Providers en geconfigureerde modellen"
"Verbinden…"
+ "Maak verbinding met een Gateway om activeringswoorden op te slaan"
"Profiel openen"
"Start je Gateway."
"Help me dit doel om te zetten in een praktische checklist: "
@@ -700,6 +713,7 @@
"OpenClaw antwoordt"
"Documentatie"
"%1$s gereed"
+ "Apparaattaal wordt niet ondersteund"
"In wachtrij — wordt verzonden zodra de verbinding is hersteld"
"%1$sm geleden"
"Koppeltoegang controleren"
@@ -731,6 +745,7 @@
"Sta toe dat de planner deze automatisering uitvoert."
"%1$s toegepast"
"Nog geen droomdagboek."
+ "Wordt op het apparaat uitgevoerd zolang OpenClaw zichtbaar is."
"%1$s is bezig"
"%1$s %2$s"
"Onbewerkt"
@@ -870,6 +885,7 @@
"De automatisering is gepauzeerd."
"OpenClaw mobiel"
"A2UI reset"
+ "Gateway niet beschikbaar"
"Read"
"Voor deze skill moet 1 item worden ingesteld. Android toont wat er is geïnstalleerd; wijzigingen in de installatie of configuratie kunnen alleen via desktop of CLI worden aangebracht."
"Laatste uitvoering"
@@ -976,6 +992,7 @@
"Afgewezen"
"Neem Android- en achtergrondpakketten op."
"Je Gateway is klaar."
+ "Geactiveerd"
"Dit duurt langer dan verwacht.\nControleer of de Gateway actief en bereikbaar is."
"Opnieuw verbinding maken"
"OpenClaw controleert de toegang tot de gateway en het knooppunt."
@@ -1021,6 +1038,7 @@
"Opgeslagen authenticatie ongeldig"
"%1$s bereiken"
"Verbind de Gateway om recente logs te laden."
+ "Activeringswoorden opslaan"
"Beheer geïnstalleerde skills en voeg vertrouwde releases van ClawHub toe."
"Verzenden…"
"Nog geen agents geladen."
@@ -1055,6 +1073,7 @@
"De offlinewachtrij is vol (%1$s berichten); verwijder eerst items uit de wachtrij."
"Openbare gateways vereisen wss:// of Tailscale Serve. ws:// is toegestaan voor localhost, .local-hosts, de Android-emulator en privé-IP-adressen op het LAN."
"Verbind de gateway om skilldetails te laden."
+ "Activeringswoorddetectie"
"Linkvoorvertoning uitklappen"
"NULL (MISLUKT)"
"Bijwerken"
@@ -1196,6 +1215,7 @@
"Deze map kan niet worden geladen."
"De QR-code bevatte geen geldige setupcode."
"Toegang tot node controleren"
+ "Activeringszin toevoegen"
"Gateway niet bereikbaar"
"Automatisering"
"Verbinding nodig"
@@ -1225,6 +1245,7 @@
"Naam"
"Versie"
"Cron"
+ "Activeringszin verwijderen"
"De installatiecode is niet geaccepteerd. Genereer een nieuwe code met openclaw qr."
"14 berichten · Android"
"Transcriptie mislukt: %1$s"
@@ -1366,6 +1387,7 @@
"Dearchiveren"
"Transcripts"
"Recente sessies"
+ "Activeringswoorden"
"Configureer %1$s op de Gateway"
"Scan een QR-code of gebruik de configuratiecode van je OpenClaw Gateway."
"Prototype designsysteem"
diff --git a/apps/android/app/src/main/res/values-pl/strings.xml b/apps/android/app/src/main/res/values-pl/strings.xml
index 6a50196605e7..f78f660ead42 100644
--- a/apps/android/app/src/main/res/values-pl/strings.xml
+++ b/apps/android/app/src/main/res/values-pl/strings.xml
@@ -46,6 +46,7 @@
"Przed pobraniem Gateway zweryfikuje dokładnie tę wersję w ClawHub. Jeśli wersja wymaga wyraźnego potwierdzenia ryzyka, Android wyświetli ostrzeżenie Gateway przed ponowną próbą."
"Kod konfiguracji używa identyfikatora strefy IPv6. Użyj adresu IPv6 bez zakresu lub nazwy hosta w sieci LAN."
"Załącznik"
+ "Skonfiguruj słowa aktywujące, rozmowę i odtwarzanie."
"Nasłuchiwanie (PTT)"
"Propozycja odrzucona."
"użytkownik"
@@ -126,7 +127,6 @@
"Przewodnik konfiguracji Androida"
"Zablokowano przekazywanie dla %1$s aplikacji."
"Sparowane urządzenia"
- "Skonfiguruj głos, transport i odtwarzanie."
"%1$s oczekujących"
"Nazwa urządzenia"
"Lokalizacja"
@@ -151,6 +151,7 @@
"+%1$s więcej"
"thread create"
"Zablokowana"
+ "Słowo lub wyrażenie aktywujące"
"Gateway wymaga zatwierdzenia urządzenia"
"%1$s/%2$s gotowych"
"Połączono (operator offline)"
@@ -163,6 +164,7 @@
"Obraz"
"Zamknij podgląd obrazu"
"eval"
+ "Ostatnie polecenie: %1$s"
"Otwórz terminal na urządzeniu, na którym działa OpenClaw."
"Brak brakujących elementów"
"Dane wyjściowe kanwy wymagają aktywnego połączenia z Gateway."
@@ -206,6 +208,7 @@
"Łączenie z Gateway"
"Gateway może zmienić tę ścieżkę, ale nie może usunąć istniejącej ścieżki."
"TTS"
+ "Zapisywanie…"
"Punkt odniesienia %1$s"
"search"
"Przeglądaj zaplanowane zadania Gateway i zarządzaj nimi."
@@ -369,6 +372,7 @@
"Czas odnowienia %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Rozpoznawanie mowy na urządzeniu jest niedostępne."
"Załączniki są zbyt duże, aby dodać je do kolejki w jednej wiadomości; usuń część z nich i spróbuj ponownie."
"Skonfigurowano 1 model. Odśwież, aby ponownie sprawdzić dostępność."
"Ten host wymaga bezpiecznego połączenia."
@@ -413,6 +417,7 @@
"wkrótce"
"Brak zatwierdzeń Gateway."
"Host"
+ "Dodaj w każdym polu jedno słowo lub wyrażenie aktywujące. Następnie wypowiedz je przed poleceniem."
"Transkrybuj, a następnie wyślij"
"Uruchom o"
"Dostęp do urządzenia Gateway"
@@ -475,6 +480,7 @@
"Szukaj w OpenClaw"
"Sesja główna"
"%1$s oczekujących"
+ "Rozpoznawanie mowy na urządzeniu jest niedostępne"
"Żadna aplikacja nie może udostępnić tej wiadomości"
"Zamknij wyszukiwanie"
"Polecenie do monitorowania"
@@ -507,6 +513,7 @@
"Katalog rozmów Gateway nie został załadowany"
"ten Gateway"
"Brak ostatnich uruchomień."
+ "Model językowy na urządzeniu jest niedostępny"
"Pasujące propozycje pojawią się tutaj po utworzeniu przez agentów wersji roboczych umiejętności wielokrotnego użytku."
"Session Search"
"OpenClaw mówi"
@@ -526,6 +533,7 @@
"Powierzchnia ekranu gotowa"
"Sparuj Gateway"
"Połącz Gateway, aby wczytać kanały."
+ "Wstrzymuje działanie podczas innej aktywności głosowej."
"Model"
"Zdjęcia"
"Wklej kod konfiguracji"
@@ -566,10 +574,12 @@
"pin"
"Kopiuj %1$s"
"Sparowano"
+ "Nie udało się zapisać słów aktywujących"
"Spowoduje to poddanie propozycji „%1$s” kwarantannie i odświeżenie stanu Skill Workshop z gateway."
"Nagraj notatkę głosową"
"Zezwalaj na używanie narzędzi aparatu na żądanie."
"Problemy"
+ "Wybudzanie głosem"
"%1$s dni temu"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Ostatnie"
"Wynik rozstrzygnięcia jest nieznany. Działania pozostaną wyłączone do czasu zweryfikowania rekordu Gateway."
"dialog"
+ "Nasłuchuj słów aktywujących"
"camera snap"
"Gateway wybrał nieznanego dostawcę %1$s"
"Śledź Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway nie zidentyfikował aktywnego dostawcy %1$s"
"Oczekiwanie"
+ "Słowa aktywujące zapisane"
"Najpierw najstarsze"
"Ekran"
"Działa od"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Dostawcy i skonfigurowane modele"
"Łączenie…"
+ "Połącz się z Gateway, aby zapisać słowa aktywujące"
"Otwórz profil"
"Uruchom Gateway."
"Pomóż mi przekształcić ten cel w praktyczną listę kontrolną: "
@@ -700,6 +713,7 @@
"OpenClaw odpowiada"
"Dokumentacja"
"%1$s gotowych"
+ "Język urządzenia nie jest obsługiwany"
"W kolejce — zostanie wysłane po ponownym połączeniu"
"%1$s min temu"
"Sprawdzanie dostępu do parowania"
@@ -731,6 +745,7 @@
"Zezwól harmonogramowi na uruchamianie tej automatyzacji."
"%1$s zastosowanych"
"Nie ma jeszcze dziennika snów."
+ "Działa na urządzeniu, gdy OpenClaw jest widoczny."
"%1$s pracuje"
"%1$s %2$s"
"Surowe"
@@ -870,6 +885,7 @@
"Automatyzacja wstrzymana."
"OpenClaw mobile"
"A2UI reset"
+ "Gateway jest niedostępny"
"Read"
"Ta umiejętność wymaga skonfigurowania 1 elementu. W systemie Android można sprawdzić, co jest zainstalowane; ustawienia i konfigurację można zmienić tylko na komputerze lub za pomocą CLI."
"Ostatnie uruchomienie"
@@ -976,6 +992,7 @@
"Odrzucone"
"Uwzględnij pakiety Androida i działające w tle."
"Gateway jest gotowy."
+ "Aktywowano"
"Trwa to dłużej niż oczekiwano.\nSprawdź, czy Gateway jest uruchomiony i osiągalny."
"Ponowne łączenie"
"OpenClaw sprawdza dostęp do Gateway i węzła."
@@ -1021,6 +1038,7 @@
"Zapisane uwierzytelnienie jest nieprawidłowe"
"%1$s zakresów"
"Połącz Gateway, aby wczytać ostatnie logi."
+ "Zapisz słowa aktywujące"
"Zarządzaj zainstalowanymi umiejętnościami i dodawaj zaufane wydania z ClawHub."
"Wysyłanie…"
"Nie wczytano jeszcze żadnych agentów."
@@ -1055,6 +1073,7 @@
"Kolejka offline jest pełna (%1$s wiadomości); najpierw usuń elementy z kolejki."
"Publiczne bramy Gateway wymagają wss:// lub Tailscale Serve. Protokół ws:// jest dozwolony dla localhost, hostów .local, emulatora Androida i prywatnych adresów IP w sieci LAN."
"Połącz Gateway, aby wczytać szczegóły skill."
+ "Nasłuchiwanie aktywacji"
"Rozwiń podgląd linku"
"NULL (NIEPOWODZENIE)"
"Aktualizuj"
@@ -1196,6 +1215,7 @@
"Nie można załadować tego folderu."
"Kod QR nie zawierał prawidłowego kodu konfiguracji."
"Sprawdź dostęp do węzła"
+ "Dodaj wyrażenie aktywujące"
"Nie można połączyć się z Gateway"
"Automatyzacja"
"Wymaga połączenia"
@@ -1225,6 +1245,7 @@
"Nazwa"
"Wersja"
"Cron"
+ "Usuń wyrażenie aktywujące"
"Kod konfiguracji nie został zaakceptowany. Wygeneruj nowy kod za pomocą openclaw qr."
"14 wiadomości · Android"
"Transkrypcja nie powiodła się: %1$s"
@@ -1248,7 +1269,7 @@
"Terminal"
"Bieżąca"
"1 konto"
- "Wstrzymane"
+ "Wstrzymano"
"Zezwól na aparat"
"Prośby o zatwierdzenie wykonania pojawią się tutaj, gdy ten telefon będzie połączony."
" · Mikrofon: oczekuje"
@@ -1366,6 +1387,7 @@
"Przywróć z archiwum"
"Transcripts"
"Ostatnie sesje"
+ "Słowa aktywujące"
"Skonfiguruj %1$s na Gateway"
"Zeskanuj kod QR lub użyj kodu konfiguracji z OpenClaw Gateway."
"Prototyp systemu projektowego"
diff --git a/apps/android/app/src/main/res/values-pt-rBR/strings.xml b/apps/android/app/src/main/res/values-pt-rBR/strings.xml
index c21827a9384d..40090aee4600 100644
--- a/apps/android/app/src/main/res/values-pt-rBR/strings.xml
+++ b/apps/android/app/src/main/res/values-pt-rBR/strings.xml
@@ -46,6 +46,7 @@
"O Gateway verificará esta versão exata com o ClawHub antes do download. Se a versão exigir o reconhecimento explícito do risco, o Android exibirá o aviso do Gateway antes de tentar novamente."
"O código de configuração usa um ID de zona IPv6. Use um endereço IPv6 sem escopo ou um nome de host da LAN."
"Anexo"
+ "Configure palavras de ativação, fala e reprodução."
"Ouvindo (PTT)"
"Proposta rejeitada."
"usuário"
@@ -126,7 +127,6 @@
"Guia de configuração do Android"
"%1$s apps impedidos de encaminhar."
"Dispositivos pareados"
- "Configure voz, transporte e reprodução."
"%1$s pendentes"
"Nome do dispositivo"
"Localização"
@@ -151,6 +151,7 @@
"+%1$s mais"
"thread create"
"Bloqueada"
+ "Palavra ou frase de ativação"
"O Gateway precisa da aprovação do dispositivo"
"%1$s/%2$s prontas"
"Conectado (operador offline)"
@@ -163,6 +164,7 @@
"Imagem"
"Fechar visualização da imagem"
"eval"
+ "Último comando: %1$s"
"Tenha um terminal aberto no dispositivo que está executando OpenClaw."
"Nenhum item ausente"
"A saída do Canvas precisa de uma conexão ativa com o gateway."
@@ -206,6 +208,7 @@
"Conectando ao Gateway"
"O gateway pode alterar este caminho, mas não pode limpar um caminho existente."
"TTS"
+ "Salvando…"
"Âncora %1$s"
"search"
"Inspecione e gerencie tarefas agendadas do Gateway."
@@ -369,6 +372,7 @@
"Tempo de espera %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "O reconhecimento de fala no dispositivo não está disponível."
"Os anexos são grandes demais para serem colocados na fila em uma única mensagem; remova alguns e tente novamente."
"1 modelo configurado. Atualize para verificar novamente a disponibilidade."
"É necessária uma conexão segura para este host."
@@ -413,6 +417,7 @@
"em breve"
"Nenhuma aprovação do Gateway."
"Host"
+ "Adicione uma palavra ou frase de ativação por campo. Depois, diga uma delas antes do comando."
"Transcrever e enviar"
"Executar em"
"Acesso ao dispositivo Gateway"
@@ -475,6 +480,7 @@
"Pesquisar no OpenClaw"
"Sessão principal"
"%1$s pendentes"
+ "Reconhecimento de fala no dispositivo indisponível"
"Nenhum app pode compartilhar esta mensagem"
"Fechar pesquisa"
"Comando a monitorar"
@@ -507,6 +513,7 @@
"Catálogo de conversa do Gateway não carregado"
"este gateway"
"Ainda não há execuções recentes."
+ "Modelo de linguagem no dispositivo indisponível"
"Propostas correspondentes aparecerão aqui depois que os agentes criarem rascunhos de skills reutilizáveis."
"Session Search"
"OpenClaw está falando"
@@ -526,6 +533,7 @@
"Superfície da tela pronta"
"Parear Gateway"
"Conecte o gateway para carregar canais."
+ "Pausa durante outras atividades de voz."
"Modelo"
"Fotos"
"Colar código de configuração"
@@ -566,10 +574,12 @@
"pin"
"Copiar %1$s"
"Pareado"
+ "Não foi possível salvar as palavras de ativação"
"Isso colocará \"%1$s\" em quarentena e atualizará o estado do Skill Workshop com base no gateway."
"Gravar nota de voz"
"Permitir ferramentas de câmera quando solicitado."
"Problemas"
+ "Ativação por voz"
"há %1$s d"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Recentes"
"Resultado da resolução desconhecido. As ações permanecem desativadas até que o registro do Gateway seja verificado."
"dialog"
+ "Ouvir palavras de ativação"
"camera snap"
"O Gateway selecionou o provedor desconhecido %1$s"
"Seguir Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"O Gateway não identificou o provedor ativo de %1$s"
"Aguardando"
+ "Palavras de ativação salvas"
"Mais antigos primeiro"
"Tela"
"Em execução desde"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Provedores e modelos configurados"
"Conectando…"
+ "Conecte-se a um Gateway para salvar as palavras de ativação"
"Abrir perfil"
"Inicie seu Gateway."
"Ajude-me a transformar este objetivo em uma lista de tarefas prática: "
@@ -700,6 +713,7 @@
"O OpenClaw está respondendo"
"Documentação"
"%1$s prontos"
+ "Idioma do dispositivo não compatível"
"Na fila — será enviado quando a conexão for restabelecida"
"há %1$s min"
"Verificando acesso de pareamento"
@@ -731,6 +745,7 @@
"Permita que o agendador execute esta automação."
"%1$s aplicados"
"Ainda não há diário de sonhos."
+ "É executado no dispositivo enquanto o OpenClaw está visível."
"%1$s está trabalhando"
"%1$s %2$s"
"Bruto"
@@ -870,6 +885,7 @@
"A automação foi pausada."
"OpenClaw para dispositivos móveis"
"A2UI reset"
+ "Gateway indisponível"
"Read"
"Esta skill requer 1 item de configuração. O Android mostra o que está instalado; as alterações de instalação/configuração devem ser feitas pelo desktop ou pela CLI."
"Última execução"
@@ -976,6 +992,7 @@
"Rejeitado"
"Incluir pacotes do Android e em segundo plano."
"Seu Gateway está pronto."
+ "Acionado"
"Isso está demorando mais do que o esperado.\nVerifique se o Gateway está em execução e acessível."
"Reconectando"
"O OpenClaw está verificando o acesso ao Gateway e ao nó."
@@ -1021,6 +1038,7 @@
"Autenticação salva inválida"
"%1$s escopos"
"Conecte o Gateway para carregar os logs recentes."
+ "Salvar palavras de ativação"
"Gerencie as skills instaladas e adicione versões confiáveis do ClawHub."
"Enviando…"
"Nenhum agente carregado ainda."
@@ -1055,6 +1073,7 @@
"A fila offline está cheia (%1$s mensagens); exclua primeiro os itens na fila."
"Gateways públicos exigem wss:// ou Tailscale Serve. ws:// é permitido para localhost, hosts .local, o emulador do Android e IPs de LAN privada."
"Conecte o Gateway para carregar os detalhes da Skill."
+ "Detector de ativação"
"Expandir pré-visualização do link"
"NULL (FALHOU)"
"Atualizar"
@@ -1196,6 +1215,7 @@
"Não foi possível carregar esta pasta."
"O código QR não continha um código de configuração válido."
"Revise o acesso ao nó"
+ "Adicionar frase de ativação"
"Não foi possível acessar o Gateway"
"Automação"
"Precisa de conexão"
@@ -1225,6 +1245,7 @@
"Nome"
"Versão"
"Cron"
+ "Remover frase de ativação"
"O código de configuração não foi aceito. Gere um novo código com openclaw qr."
"14 mensagens · Android"
"Falha na transcrição: %1$s"
@@ -1248,7 +1269,7 @@
"Terminal"
"Atual"
"1 conta"
- "Pausadas"
+ "Pausado"
"Permitir câmera"
"As solicitações de aprovação de execução aparecerão aqui enquanto este telefone estiver conectado."
" · Mic: Pendente"
@@ -1366,6 +1387,7 @@
"Desarquivar"
"Transcripts"
"Sessões recentes"
+ "Palavras de ativação"
"Configure %1$s no Gateway"
"Escaneie um código QR ou use o código de configuração do seu OpenClaw Gateway."
"Protótipo do design system"
diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml
index 7a0b5f3ed265..1fb92b84d956 100644
--- a/apps/android/app/src/main/res/values-ru/strings.xml
+++ b/apps/android/app/src/main/res/values-ru/strings.xml
@@ -46,6 +46,7 @@
"Gateway проверит именно этот выпуск через ClawHub перед загрузкой. Если для выпуска требуется явное подтверждение риска, Android покажет предупреждение Gateway перед повторной попыткой."
"Код настройки использует идентификатор зоны IPv6. Используйте IPv6-адрес без области действия или имя хоста в LAN."
"Вложение"
+ "Настройте фразы активации, голосовое управление и воспроизведение."
"Прослушивание (PTT)"
"Предложение отклонено."
"пользователь"
@@ -126,7 +127,6 @@
"Руководство по настройке Android"
"Переадресация заблокирована для %1$s приложений."
"Сопряженные устройства"
- "Настройте голос, транспорт и воспроизведение."
"%1$s ожидают подтверждения"
"Имя устройства"
"Местоположение"
@@ -151,6 +151,7 @@
"+%1$s еще"
"thread create"
"Заблокировано"
+ "Слово или фраза активации"
"Gateway требуется подтверждение устройства"
"Готово: %1$s/%2$s"
"Подключено (оператор не в сети)"
@@ -163,6 +164,7 @@
"Изображение"
"Закрыть предпросмотр изображения"
"eval"
+ "Последняя команда: %1$s"
"Откройте терминал на устройстве, на котором запущен OpenClaw."
"Ничего не требуется"
"Для вывода Canvas требуется активное подключение к Gateway."
@@ -206,6 +208,7 @@
"Подключение к Gateway"
"Gateway может изменить этот путь, но не может удалить существующий путь."
"TTS"
+ "Сохранение…"
"Привязка %1$s"
"search"
"Просматривайте запланированные задачи Gateway и управляйте ими."
@@ -369,6 +372,7 @@
"Период ожидания %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Распознавание речи на устройстве недоступно."
"Вложения слишком велики, чтобы поставить их в очередь в одном сообщении; удалите некоторые из них и попробуйте ещё раз."
"Настроена 1 модель. Обновите, чтобы повторно проверить доступность."
"Для этого хоста требуется защищённое соединение."
@@ -413,6 +417,7 @@
"скоро"
"Нет подтверждений Gateway."
"Хост"
+ "Добавьте в каждое поле одно слово или фразу активации. Затем произнесите её перед командой."
"Расшифровать и отправить"
"Запустить в"
"Доступ к устройству Gateway"
@@ -475,6 +480,7 @@
"Поиск в OpenClaw"
"Основная сессия"
"Ожидают: %1$s"
+ "Распознавание речи на устройстве недоступно"
"Нет приложения, которое может поделиться этим сообщением"
"Закрыть поиск"
"Команда для наблюдения"
@@ -507,6 +513,7 @@
"Каталог разговоров Gateway не загружен"
"этот Gateway"
"Пока нет недавних запусков."
+ "Языковая модель на устройстве недоступна"
"Подходящие предложения появятся здесь после того, как агенты создадут черновики многоразовых Skills."
"Session Search"
"OpenClaw говорит"
@@ -526,6 +533,7 @@
"Поверхность экрана готова"
"Сопрячь Gateway"
"Подключите Gateway, чтобы загрузить каналы."
+ "Приостанавливается во время другой голосовой активности."
"Модель"
"Фото"
"Вставить код настройки"
@@ -566,10 +574,12 @@
"pin"
"Копировать %1$s"
"Сопряжено"
+ "Не удалось сохранить фразы активации"
"Предложение \"%1$s\" будет помещено в карантин, а состояние Skill Workshop будет обновлено из Gateway."
"Записать голосовое сообщение"
"Разрешать доступ к камере по запросу."
"Проблемы"
+ "Голосовая активация"
"%1$s дн. назад"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Недавние"
"Результат обработки неизвестен. Действия будут недоступны, пока запись Gateway не будет проверена."
"dialog"
+ "Распознавать фразы активации"
"camera snap"
"Gateway выбрал неизвестного поставщика %1$s"
"Следовать Android · %1$s"
@@ -613,6 +624,7 @@
"Навык"
"Gateway не определил активного поставщика %1$s"
"Ожидание"
+ "Фразы активации сохранены"
"Сначала старые"
"Экран"
"Выполняется с"
@@ -645,6 +657,7 @@
"%1$s... (ОК)"
"Провайдеры и настроенные модели"
"Подключение…"
+ "Подключитесь к Gateway, чтобы сохранить фразы активации"
"Открыть профиль"
"Запустите ваш Gateway."
"Помогите мне преобразовать эту цель в практический контрольный список: "
@@ -700,6 +713,7 @@
"OpenClaw отвечает"
"Документация"
"Готово: %1$s"
+ "Язык устройства не поддерживается"
"В очереди — будет отправлено после переподключения"
"%1$s мин назад"
"Проверка доступа для сопряжения"
@@ -731,6 +745,7 @@
"Разрешить планировщику запускать эту автоматизацию."
"%1$s применено"
"Дневника снов пока нет."
+ "Работает на устройстве, пока OpenClaw отображается на экране."
"%1$s работает"
"%1$s %2$s"
"Необработанные данные"
@@ -870,6 +885,7 @@
"Автоматизация приостановлена."
"OpenClaw для мобильных устройств"
"A2UI reset"
+ "Gateway недоступен"
"Read"
"Для этого навыка требуется настроить 1 элемент. На Android можно посмотреть, что установлено; настройка выполняется с компьютера или через CLI."
"Последний запуск"
@@ -976,6 +992,7 @@
"Отклонено"
"Включить Android и фоновые пакеты."
"Ваш Gateway готов."
+ "Активировано"
"Это занимает больше времени, чем ожидалось.\nУбедитесь, что Gateway запущен и доступен."
"Повторное подключение"
"OpenClaw проверяет доступ к Gateway и узлу."
@@ -1021,6 +1038,7 @@
"Сохраненные данные аутентификации недействительны"
"Областей доступа: %1$s"
"Подключите Gateway, чтобы загрузить недавние журналы."
+ "Сохранить фразы активации"
"Управляйте установленными навыками и добавляйте доверенные выпуски из ClawHub."
"Отправка…"
"Агенты пока не загружены."
@@ -1055,6 +1073,7 @@
"Офлайн-очередь заполнена (%1$s сообщений); сначала удалите элементы из очереди."
"Для общедоступных шлюзов требуется wss:// или Tailscale Serve. ws:// разрешён для localhost, хостов .local, эмулятора Android и частных IP-адресов локальной сети."
"Подключите Gateway, чтобы загрузить сведения о Skill."
+ "Распознавание фраз активации"
"Развернуть предпросмотр ссылки"
"NULL (ОШИБКА)"
"Обновить"
@@ -1196,6 +1215,7 @@
"Не удалось загрузить эту папку."
"QR-код не содержал действительный код настройки."
"Проверьте доступ к узлу"
+ "Добавить фразу активации"
"Не удаётся подключиться к Gateway"
"Автоматизация"
"Требуется подключение"
@@ -1225,6 +1245,7 @@
"Название"
"Версия"
"Cron"
+ "Удалить фразу активации"
"Код настройки не принят. Создайте новый код с помощью openclaw qr."
"14 сообщений · Android"
"Не удалось выполнить транскрибацию: %1$s"
@@ -1248,7 +1269,7 @@
"Терминал"
"Текущая"
"1 аккаунт"
- "Приостановленные"
+ "Приостановлено"
"Разрешить доступ к камере"
"Запросы на подтверждение выполнения будут отображаться здесь, пока этот телефон подключен."
" · Микрофон: ожидает"
@@ -1366,6 +1387,7 @@
"Разархивировать"
"Transcripts"
"Недавние сеансы"
+ "Фразы активации"
"Настройте %1$s на Gateway"
"Отсканируйте QR-код или используйте код настройки из вашего OpenClaw Gateway."
"Прототип дизайн-системы"
diff --git a/apps/android/app/src/main/res/values-sv/strings.xml b/apps/android/app/src/main/res/values-sv/strings.xml
index 165cad1fb78a..033b63fa4ac1 100644
--- a/apps/android/app/src/main/res/values-sv/strings.xml
+++ b/apps/android/app/src/main/res/values-sv/strings.xml
@@ -46,6 +46,7 @@
"Gateway verifierar exakt den här versionen med ClawHub före nedladdningen. Om versionen kräver ett uttryckligt godkännande av risken visar Android Gateway-varningen innan ett nytt försök görs."
"Installationskoden använder ett IPv6-zon-ID. Använd en IPv6-adress utan omfång eller ett LAN-värdnamn."
"Bilaga"
+ "Konfigurera aktiveringsord, tal och uppspelning."
"Lyssnar (PTT)"
"Förslaget avvisades."
"användare"
@@ -126,7 +127,6 @@
"Android-konfigurationsguide"
"%1$s appar blockerade från att vidarebefordra."
"Parkopplade enheter"
- "Konfigurera röst, transport och uppspelning."
"%1$s väntande"
"Enhetsnamn"
"Plats"
@@ -151,6 +151,7 @@
"+%1$s till"
"thread create"
"Blockerad"
+ "Aktiveringsord eller fras"
"Gateway behöver enhetsgodkännande"
"%1$s/%2$s redo"
"Ansluten (operatören är offline)"
@@ -163,6 +164,7 @@
"Bild"
"Stäng bildförhandsvisning"
"eval"
+ "Senaste kommando: %1$s"
"Ha en terminal öppen på enheten som kör OpenClaw."
"Inget saknas"
"Canvas-utdata kräver en aktiv Gateway-anslutning."
@@ -206,6 +208,7 @@
"Ansluter till Gateway"
"Gatewayen kan ändra denna sökväg men kan inte rensa en befintlig sökväg."
"TTS"
+ "Sparar…"
"Ankare %1$s"
"search"
"Granska och hantera schemalagt Gateway-arbete."
@@ -369,6 +372,7 @@
"Väntetid %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Taligenkänning på enheten är inte tillgänglig."
"Bilagorna är för stora för att köas i ett enda meddelande. Ta bort några och försök igen."
"1 konfigurerad modell. Uppdatera för att kontrollera tillgängligheten igen."
"En säker anslutning krävs för den här värden."
@@ -413,6 +417,7 @@
"snart"
"Inga Gateway-godkännanden."
"Värd"
+ "Lägg till ett aktiveringsord eller en fras per fält. Säg sedan ett av dem före ditt kommando."
"Transkribera och skicka sedan"
"Kör vid"
"Åtkomst till Gateway-enheten"
@@ -475,6 +480,7 @@
"Sök i OpenClaw"
"Huvudsession"
"%1$s väntande"
+ "Taligenkänning på enheten är inte tillgänglig"
"Ingen app kan dela det här meddelandet"
"Stäng sökning"
"Kommando att bevaka"
@@ -507,6 +513,7 @@
"Gateway-samtalskatalogen har inte lästs in"
"denna Gateway"
"Inga senaste körningar än."
+ "Språkmodellen på enheten är inte tillgänglig"
"Matchande förslag visas här efter att agenter skapat återanvändbara skill-utkast."
"Session Search"
"OpenClaw talar"
@@ -526,6 +533,7 @@
"Skärmytan är klar"
"Parkoppla Gateway"
"Anslut Gateway för att läsa in kanaler."
+ "Pausas under annan röstaktivitet."
"Modell"
"Foton"
"Klistra in installationskod"
@@ -566,10 +574,12 @@
"pin"
"Kopiera %1$s"
"Parkopplad"
+ "Det gick inte att spara aktiveringsorden"
"Detta sätter \"%1$s\" i karantän och uppdaterar statusen för Skill Workshop från Gateway."
"Spela in röstmeddelande"
"Tillåt kameraverktyg på begäran."
"Problem"
+ "Röstaktivering"
"%1$s d sedan"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Senaste"
"Behandlingsresultat okänt. Åtgärder förblir inaktiverade tills Gateway-posten är verifierad."
"dialog"
+ "Lyssna efter aktiveringsord"
"camera snap"
"Gateway valde okänd leverantör %1$s"
"Följ Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway identifierade inte den aktiva %1$s-leverantören"
"Väntar"
+ "Aktiveringsorden har sparats"
"Äldsta först"
"Skärm"
"Körs sedan"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Leverantörer och konfigurerade modeller"
"Ansluter…"
+ "Anslut till en Gateway för att spara aktiveringsord"
"Öppna profil"
"Starta din Gateway."
"Hjälp mig att omvandla det här målet till en praktisk checklista: "
@@ -700,6 +713,7 @@
"OpenClaw svarar"
"Dokumentation"
"%1$s redo"
+ "Enhetens språk stöds inte"
"I kö — skickas när anslutningen återupprättas"
"%1$s min sedan"
"Kontrollerar parkopplingsåtkomst"
@@ -731,6 +745,7 @@
"Tillåt schemaläggaren att köra den här automatiseringen."
"%1$s tillämpade"
"Ingen drömdagbok ännu."
+ "Körs på enheten medan OpenClaw är synligt."
"%1$s arbetar"
"%1$s %2$s"
"Rå"
@@ -870,6 +885,7 @@
"Automatiseringen har pausats."
"OpenClaw för mobilen"
"A2UI reset"
+ "Gateway är inte tillgänglig"
"Read"
"Denna skill kräver 1 konfigurationsåtgärd. Android visar vad som är installerat. Konfigurationsändringar görs via datorn eller CLI."
"Senaste körning"
@@ -976,6 +992,7 @@
"Avvisad"
"Inkludera Android och bakgrundspaket."
"Din Gateway är redo."
+ "Aktiverad"
"Det här tar längre tid än väntat.\nKontrollera att Gateway körs och går att nå."
"Återansluter"
"OpenClaw kontrollerar åtkomst till gateway och nod."
@@ -1021,6 +1038,7 @@
"Sparad autentisering är ogiltig"
"%1$s behörighetsområden"
"Anslut Gateway för att läsa in senaste loggar."
+ "Spara aktiveringsord"
"Hantera installerade skills och lägg till betrodda versioner från ClawHub."
"Skickar…"
"Inga agenter inlästa ännu."
@@ -1055,6 +1073,7 @@
"Offlinekön är full (%1$s meddelanden). Ta först bort köade objekt."
"Offentliga Gateway-adresser kräver wss:// eller Tailscale Serve. ws:// tillåts för localhost, .local-värdar, Android-emulatorn och privata LAN-IP-adresser."
"Anslut gatewayen för att läsa in skill-information."
+ "Aktiveringslyssnare"
"Utöka länkförhandsgranskning"
"NULL (MISSLYCKADES)"
"Uppdatera"
@@ -1196,6 +1215,7 @@
"Det gick inte att läsa in den här mappen."
"QR-koden innehöll ingen giltig installationskod."
"Granska nodåtkomst"
+ "Lägg till aktiveringsfras"
"Kan inte nå Gateway"
"Automatisering"
"Behöver anslutning"
@@ -1225,6 +1245,7 @@
"Namn"
"Version"
"Cron"
+ "Ta bort aktiveringsfras"
"Konfigurationskoden accepterades inte. Generera en ny kod med openclaw qr."
"14 meddelanden · Android"
"Transkriberingen misslyckades: %1$s"
@@ -1366,6 +1387,7 @@
"Avarkivera"
"Transcripts"
"Senaste sessioner"
+ "Aktiveringsord"
"Konfigurera %1$s på Gateway"
"Skanna en QR-kod eller använd installationskoden från din OpenClaw Gateway."
"Prototyp för designsystem"
diff --git a/apps/android/app/src/main/res/values-th/strings.xml b/apps/android/app/src/main/res/values-th/strings.xml
index 7e1f56fd868f..6189df5a169f 100644
--- a/apps/android/app/src/main/res/values-th/strings.xml
+++ b/apps/android/app/src/main/res/values-th/strings.xml
@@ -46,6 +46,7 @@
"Gateway จะตรวจสอบรีลีสนี้กับ ClawHub ก่อนดาวน์โหลด หากรีลีสต้องมีการยอมรับความเสี่ยงอย่างชัดแจ้ง Android จะแสดงคำเตือนจาก Gateway ก่อนลองอีกครั้ง"
"รหัสการตั้งค่าใช้ IPv6 zone ID โปรดใช้ที่อยู่ IPv6 แบบไม่มีขอบเขตหรือชื่อโฮสต์ LAN"
"ไฟล์แนบ"
+ "กำหนดค่าคำปลุก การพูด และการเล่นเสียง"
"กำลังฟัง (PTT)"
"ปฏิเสธข้อเสนอแล้ว"
"ผู้ใช้"
@@ -126,7 +127,6 @@
"คู่มือการตั้งค่า Android"
"บล็อกไม่ให้ส่งต่อ %1$s แอป"
"อุปกรณ์ที่จับคู่แล้ว"
- "กำหนดค่าเสียง การรับส่งข้อมูล และการเล่น"
"รอดำเนินการ %1$s รายการ"
"ชื่ออุปกรณ์"
"ตำแหน่งที่ตั้ง"
@@ -151,6 +151,7 @@
"+%1$s เพิ่มเติม"
"thread create"
"ถูกบล็อก"
+ "คำหรือวลีปลุก"
"Gateway ต้องได้รับการอนุมัติอุปกรณ์"
"พร้อมใช้งาน %1$s/%2$s"
"เชื่อมต่อแล้ว (ผู้ควบคุมออฟไลน์)"
@@ -163,6 +164,7 @@
"รูปภาพ"
"ปิดตัวอย่างรูปภาพ"
"eval"
+ "คำสั่งล่าสุด: %1$s"
"เปิดเทอร์มินัลไว้บนอุปกรณ์ที่กำลังรัน OpenClaw"
"ไม่มีรายการที่ขาดหาย"
"เอาต์พุตแคนวาสต้องใช้การเชื่อมต่อ Gateway ที่ใช้งานอยู่"
@@ -206,6 +208,7 @@
"กำลังเชื่อมต่อ Gateway"
"gateway สามารถเปลี่ยนเส้นทางนี้ได้ แต่ไม่สามารถล้างเส้นทางที่มีอยู่ได้"
"TTS"
+ "กำลังบันทึก…"
"จุดยึด %1$s"
"search"
"ตรวจสอบและจัดการงาน Gateway ที่กำหนดเวลาไว้"
@@ -369,6 +372,7 @@
"ช่วงพัก %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "การรู้จำเสียงพูดบนอุปกรณ์ไม่พร้อมใช้งาน"
"ไฟล์แนบมีขนาดใหญ่เกินกว่าจะเพิ่มลงในคิวสำหรับข้อความเดียวได้ โปรดนำบางไฟล์ออกแล้วลองอีกครั้ง"
"มีโมเดลที่กำหนดค่าไว้ 1 รายการ รีเฟรชเพื่อตรวจสอบความพร้อมใช้งานอีกครั้ง"
"โฮสต์นี้ต้องใช้การเชื่อมต่อที่ปลอดภัย"
@@ -413,6 +417,7 @@
"เร็ว ๆ นี้"
"ไม่มีการอนุมัติของ Gateway"
"โฮสต์"
+ "เพิ่มคำหรือวลีปลุกหนึ่งรายการต่อช่อง จากนั้นพูดคำหรือวลีดังกล่าวก่อนออกคำสั่ง"
"ถอดเสียงแล้วส่ง"
"เรียกใช้เมื่อ"
"การเข้าถึงอุปกรณ์ Gateway"
@@ -475,6 +480,7 @@
"ค้นหา OpenClaw"
"เซสชันหลัก"
"รอดำเนินการ %1$s รายการ"
+ "ไม่สามารถใช้การรู้จำเสียงบนอุปกรณ์ได้"
"ไม่มีแอปที่สามารถแชร์ข้อความนี้ได้"
"ปิดการค้นหา"
"คำสั่งที่จะเฝ้าดู"
@@ -507,6 +513,7 @@
"ยังไม่ได้โหลดแค็ตตาล็อกการพูดของ Gateway"
"Gateway นี้"
"ยังไม่มีการรันล่าสุด"
+ "ไม่สามารถใช้โมเดลภาษาบนอุปกรณ์ได้"
"ข้อเสนอที่ตรงกันจะปรากฏที่นี่หลังจากที่ agent สร้างแบบร่าง skill ที่นำกลับมาใช้ใหม่ได้"
"Session Search"
"OpenClaw กำลังพูด"
@@ -526,6 +533,7 @@
"พื้นผิวหน้าจอพร้อมแล้ว"
"จับคู่ Gateway"
"เชื่อมต่อ Gateway เพื่อโหลดช่องทาง"
+ "หยุดชั่วคราวเมื่อมีกิจกรรมเสียงอื่น"
"โมเดล"
"รูปภาพ"
"วางรหัสตั้งค่า"
@@ -566,10 +574,12 @@
"pin"
"คัดลอก %1$s"
"จับคู่แล้ว"
+ "ไม่สามารถบันทึกคำปลุกได้"
"การดำเนินการนี้จะกักกัน \"%1$s\" และรีเฟรชสถานะ Skill Workshop จาก Gateway"
"บันทึกข้อความเสียง"
"อนุญาตให้ใช้เครื่องมือกล้องเมื่อมีการร้องขอ"
"ปัญหา"
+ "การปลุกด้วยเสียง"
"%1$s วันที่แล้ว"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"ล่าสุด"
"ไม่ทราบผลการดำเนินการ การดำเนินการจะยังคงถูกปิดใช้งานจนกว่าจะยืนยันบันทึกของ Gateway"
"dialog"
+ "ฟังคำปลุก"
"camera snap"
"Gateway เลือกผู้ให้บริการที่ไม่รู้จัก %1$s"
"ติดตาม Android · %1$s"
@@ -613,6 +624,7 @@
"ทักษะ"
"Gateway ไม่ได้ระบุผู้ให้บริการ %1$s ที่ใช้งานอยู่"
"กำลังรอ"
+ "บันทึกคำปลุกแล้ว"
"เก่าสุดก่อน"
"หน้าจอ"
"กำลังทำงานตั้งแต่"
@@ -645,6 +657,7 @@
"%1$s... (ตกลง)"
"ผู้ให้บริการและโมเดลที่กำหนดค่าไว้"
"กำลังเชื่อมต่อ…"
+ "เชื่อมต่อกับ Gateway เพื่อบันทึกคำปลุก"
"เปิดโปรไฟล์"
"เริ่ม Gateway ของคุณ"
"ช่วยเปลี่ยนเป้าหมายนี้ให้เป็นรายการตรวจสอบที่นำไปใช้ได้จริง: "
@@ -700,6 +713,7 @@
"OpenClaw กำลังตอบกลับ"
"เอกสาร"
"พร้อม %1$s รายการ"
+ "ไม่รองรับภาษาของอุปกรณ์"
"อยู่ในคิว — จะส่งเมื่อเชื่อมต่ออีกครั้ง"
"%1$s นาทีที่แล้ว"
"กำลังตรวจสอบสิทธิ์การจับคู่"
@@ -731,6 +745,7 @@
"อนุญาตให้ตัวจัดกำหนดการเรียกใช้ระบบอัตโนมัตินี้"
"นำไปใช้แล้ว %1$s รายการ"
"ยังไม่มีไดอารีความฝัน"
+ "ทำงานบนอุปกรณ์ขณะที่ OpenClaw แสดงอยู่"
"%1$s กำลังทำงาน"
"%1$s %2$s"
"ข้อมูลดิบ"
@@ -870,6 +885,7 @@
"หยุดระบบอัตโนมัติชั่วคราวแล้ว"
"OpenClaw สำหรับอุปกรณ์เคลื่อนที่"
"A2UI reset"
+ "Gateway ไม่พร้อมใช้งาน"
"Read"
"Skills นี้ต้องตั้งค่า 1 รายการ โดย Android จะแสดงสิ่งที่ติดตั้งไว้ ส่วนการตั้งค่า/การเปลี่ยนแปลงการกำหนดค่าต้องดำเนินการบนเดสก์ท็อปหรือ CLI"
"การเรียกใช้ล่าสุด"
@@ -976,6 +992,7 @@
"ปฏิเสธแล้ว"
"รวมแพ็กเกจของ Android และแพ็กเกจเบื้องหลัง"
"Gateway ของคุณพร้อมใช้งานแล้ว"
+ "ทริกเกอร์แล้ว"
"ใช้เวลานานกว่าที่คาดไว้\nตรวจสอบว่า Gateway กำลังทำงานและสามารถเข้าถึงได้"
"กำลังเชื่อมต่อใหม่"
"OpenClaw กำลังตรวจสอบ Gateway และการเข้าถึงโหนด"
@@ -1021,6 +1038,7 @@
"ข้อมูลยืนยันตัวตนที่บันทึกไว้ไม่ถูกต้อง"
"%1$s ขอบเขต"
"เชื่อมต่อ Gateway เพื่อโหลดบันทึกล่าสุด"
+ "บันทึกคำปลุก"
"จัดการ Skills ที่ติดตั้งแล้วและเพิ่มรุ่นที่เชื่อถือได้จาก ClawHub"
"กำลังส่ง…"
"ยังไม่ได้โหลด Agents"
@@ -1055,6 +1073,7 @@
"คิวออฟไลน์เต็มแล้ว (%1$s ข้อความ) โปรดลบรายการที่อยู่ในคิวก่อน"
"Gateway สาธารณะต้องใช้ wss:// หรือ Tailscale Serve ส่วน ws:// ใช้ได้กับ localhost, โฮสต์ .local, โปรแกรมจำลอง Android และ IP ของ LAN ส่วนตัว"
"เชื่อมต่อ Gateway เพื่อโหลดรายละเอียด Skill"
+ "ตัวฟังคำปลุก"
"ขยายตัวอย่างลิงก์"
"NULL (ล้มเหลว)"
"อัปเดต"
@@ -1196,6 +1215,7 @@
"ไม่สามารถโหลดโฟลเดอร์นี้ได้"
"คิวอาร์โค้ดไม่มีรหัสตั้งค่าที่ถูกต้อง"
"ตรวจสอบสิทธิ์การเข้าถึงโหนด"
+ "เพิ่มวลีปลุก"
"ไม่สามารถเข้าถึง Gateway"
"การทำงานอัตโนมัติ"
"ต้องเชื่อมต่อ"
@@ -1225,6 +1245,7 @@
"ชื่อ"
"เวอร์ชัน"
"Cron"
+ "นำวลีปลุกออก"
"ไม่ยอมรับรหัสตั้งค่า โปรดสร้างรหัสใหม่ด้วย openclaw qr"
"14 ข้อความ · Android"
"ถอดเสียงไม่สำเร็จ: %1$s"
@@ -1366,6 +1387,7 @@
"ยกเลิกการเก็บถาวร"
"Transcripts"
"เซสชันล่าสุด"
+ "คำปลุก"
"กำหนดค่า %1$s บน Gateway"
"สแกนคิวอาร์โค้ดหรือใช้รหัสตั้งค่าจาก OpenClaw Gateway ของคุณ"
"ต้นแบบระบบการออกแบบ"
diff --git a/apps/android/app/src/main/res/values-tr/strings.xml b/apps/android/app/src/main/res/values-tr/strings.xml
index c159ef0f088b..4c7e06c64ef4 100644
--- a/apps/android/app/src/main/res/values-tr/strings.xml
+++ b/apps/android/app/src/main/res/values-tr/strings.xml
@@ -46,6 +46,7 @@
"Gateway, indirmeden önce bu sürümün aynısını ClawHub ile doğrulayacaktır. Sürüm için açıkça risk kabulü gerekiyorsa Android, yeniden denemeden önce Gateway uyarısını gösterecektir."
"Kurulum kodu bir IPv6 bölge kimliği kullanıyor. Kapsamsız bir IPv6 adresi veya bir LAN ana makine adı kullanın."
"Ek"
+ "Uyandırma sözcüklerini, konuşmayı ve oynatmayı yapılandırın."
"Dinleniyor (PTT)"
"Teklif reddedildi."
"kullanıcı"
@@ -126,7 +127,6 @@
"Android kurulum kılavuzu"
"%1$s uygulamanın yönlendirmesi engellendi."
"Eşlenmiş Cihazlar"
- "Ses, aktarım ve oynatmayı yapılandırın."
"%1$s bekliyor"
"Cihaz adı"
"Konum"
@@ -151,6 +151,7 @@
"+%1$s daha"
"thread create"
"Engellendi"
+ "Uyandırma sözcüğü veya ifadesi"
"Gateway için cihaz onayı gerekiyor"
"%1$s/%2$s hazır"
"Bağlandı (operatör çevrimdışı)"
@@ -163,6 +164,7 @@
"Görsel"
"Görüntü önizlemesini kapat"
"eval"
+ "Son komut: %1$s"
"OpenClaw çalıştıran cihazda bir terminal açık olsun."
"Eksik öğe yok"
"Tuval çıktısı için etkin bir Gateway bağlantısı gerekir."
@@ -206,6 +208,7 @@
"Gateway\'e Bağlanılıyor"
"Gateway bu yolu değiştirebilir ancak mevcut bir yolu temizleyemez."
"TTS"
+ "Kaydediliyor…"
"Çapa %1$s"
"search"
"Zamanlanmış Gateway işlerini inceleyin ve yönetin."
@@ -369,6 +372,7 @@
"Bekleme süresi %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Cihaz üzerinde konuşma tanıma kullanılamıyor."
"Ekler tek bir mesaj için kuyruğa alınamayacak kadar büyük; bazılarını kaldırıp tekrar deneyin."
"1 yapılandırılmış model var. Kullanılabilirliği yeniden kontrol etmek için yenileyin."
"Bu ana makine için güvenli bağlantı gereklidir."
@@ -413,6 +417,7 @@
"yakında"
"Gateway onayı yok."
"Ana makine"
+ "Her alana bir uyandırma sözcüğü veya ifadesi ekleyin. Ardından komutunuzdan önce bunlardan birini söyleyin."
"Metne çevir ve gönder"
"Şurada çalıştır"
"Gateway cihazına erişim"
@@ -475,6 +480,7 @@
"OpenClaw\'da ara"
"Ana oturum"
"%1$s bekliyor"
+ "Cihaz üzerinde konuşma tanıma kullanılamıyor"
"Hiçbir uygulama bu mesajı paylaşamaz"
"Aramayı kapat"
"İzlenecek komut"
@@ -507,6 +513,7 @@
"Gateway konuşma kataloğu yüklenmedi"
"bu Gateway"
"Henüz son çalıştırma yok."
+ "Cihaz üzerindeki dil modeli kullanılamıyor"
"Eşleşen öneriler, aracılar yeniden kullanılabilir skill taslakları oluşturduktan sonra burada görünecektir."
"Session Search"
"OpenClaw konuşuyor"
@@ -526,6 +533,7 @@
"Ekran yüzeyi hazır"
"Gateway\'i Eşleştir"
"Kanalları yüklemek için gateway\'i bağlayın."
+ "Diğer ses etkinlikleri sırasında duraklatılır."
"Model"
"Fotoğraflar"
"Kurulum kodunu yapıştır"
@@ -566,10 +574,12 @@
"pin"
"%1$s Öğesini Kopyala"
"Eşlendi"
+ "Uyandırma sözcükleri kaydedilemedi"
"Bu işlem \"%1$s\" teklifini karantinaya alacak ve Skill Workshop durumunu Gateway\'den yenileyecek."
"Sesli not kaydet"
"İstendiğinde kamera araçlarına izin ver."
"Sorunlar"
+ "Sesle Uyandırma"
"%1$s gün önce"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Son"
"Çözüm sonucu bilinmiyor. Gateway kaydı doğrulanana kadar eylemler devre dışı kalır."
"dialog"
+ "Uyandırma sözcüklerini dinle"
"camera snap"
"Gateway bilinmeyen sağlayıcıyı seçti: %1$s"
"Android\'i takip et · %1$s"
@@ -613,6 +624,7 @@
"Beceri"
"Gateway, etkin %1$s sağlayıcısını tanımlamadı"
"Bekleniyor"
+ "Uyandırma sözcükleri kaydedildi"
"Önce en eski"
"Ekran"
"Çalışmaya Başlama"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Sağlayıcılar ve yapılandırılmış modeller"
"Bağlanıyor…"
+ "Uyandırma sözcüklerini kaydetmek için bir Gateway\'e bağlanın"
"Profili aç"
"Gateway\'nizi başlatın."
"Bu hedefi pratik bir kontrol listesine dönüştürmeme yardımcı olun: "
@@ -700,6 +713,7 @@
"OpenClaw yanıt veriyor"
"Belgeler"
"%1$s hazır"
+ "Cihaz dili desteklenmiyor"
"Sıraya alındı — yeniden bağlanıldığında gönderilecek"
"%1$s dk önce"
"Eşleştirme erişimi kontrol ediliyor"
@@ -731,6 +745,7 @@
"Zamanlayıcının bu otomasyonu çalıştırmasına izin verin."
"%1$s uygulandı"
"Henüz rüya günlüğü yok."
+ "OpenClaw görünür durumdayken cihaz üzerinde çalışır."
"%1$s çalışıyor"
"%1$s %2$s"
"Ham"
@@ -870,6 +885,7 @@
"Otomasyon duraklatıldı."
"OpenClaw mobil"
"A2UI reset"
+ "Gateway kullanılamıyor"
"Read"
"Bu beceri için 1 kurulum öğesi gerekiyor. Android nelerin yüklü olduğunu gösterir; kurulum/yapılandırma değişiklikleri yalnızca masaüstünden veya CLI üzerinden yapılabilir."
"Son Çalıştırma"
@@ -976,6 +992,7 @@
"Reddedildi"
"Android ve arka plan paketlerini dahil edin."
"Gateway\'iniz hazır."
+ "Tetiklendi"
"Bu işlem beklenenden uzun sürüyor.\nGateway\'in çalıştığını ve erişilebilir olduğunu kontrol edin."
"Yeniden bağlanıyor"
"OpenClaw, Gateway ve düğüm erişimini kontrol ediyor."
@@ -1021,6 +1038,7 @@
"Kaydedilen kimlik doğrulama geçersiz"
"%1$s kapsam"
"Son günlükleri yüklemek için gateway\'i bağlayın."
+ "Uyandırma sözcüklerini kaydet"
"Yüklü skill\'leri yönetin ve ClawHub\'dan güvenilir sürümler ekleyin."
"Gönderiliyor…"
"Henüz yüklenmiş aracı yok."
@@ -1055,6 +1073,7 @@
"Çevrimdışı kuyruk dolu (%1$s mesaj); önce kuyruktaki öğeleri silin."
"Herkese açık gateway\'ler wss:// veya Tailscale Serve gerektirir. ws://; localhost, .local ana makineleri, Android emülatörü ve özel LAN IP\'leri için kullanılabilir."
"Skill ayrıntılarını yüklemek için Gateway\'i bağlayın."
+ "Uyandırma dinleyicisi"
"Bağlantı önizlemesini genişlet"
"NULL (BAŞARISIZ)"
"Güncelle"
@@ -1196,6 +1215,7 @@
"Bu klasör yüklenemedi."
"QR kodu geçerli bir kurulum kodu içermiyordu."
"Düğüm erişimini inceleyin"
+ "Uyandırma ifadesi ekle"
"Gateway\'e ulaşılamıyor"
"Otomasyon"
"Bağlantı gerekiyor"
@@ -1225,6 +1245,7 @@
"Ad"
"Sürüm"
"Cron"
+ "Uyandırma ifadesini kaldır"
"Kurulum kodu kabul edilmedi. openclaw qr ile yeni bir kod oluşturun."
"14 mesaj · Android"
"Transkripsiyon başarısız oldu: %1$s"
@@ -1366,6 +1387,7 @@
"Arşivden çıkar"
"Transcripts"
"Son Oturumlar"
+ "Uyandırma sözcükleri"
"Gateway üzerinde %1$s yapılandırın"
"Bir QR kodu tarayın veya OpenClaw Gateway’inizdeki kurulum kodunu kullanın."
"Tasarım sistemi prototipi"
diff --git a/apps/android/app/src/main/res/values-uk/strings.xml b/apps/android/app/src/main/res/values-uk/strings.xml
index 0b05b426368b..751603b2cc6b 100644
--- a/apps/android/app/src/main/res/values-uk/strings.xml
+++ b/apps/android/app/src/main/res/values-uk/strings.xml
@@ -46,6 +46,7 @@
"Перед завантаженням Gateway перевірить саме цей випуск за допомогою ClawHub. Якщо для випуску потрібно явно підтвердити усвідомлення ризику, Android покаже попередження Gateway перед повторною спробою."
"Код налаштування використовує ідентифікатор зони IPv6. Використайте IPv6-адресу без області або ім’я хоста LAN."
"Вкладення"
+ "Налаштуйте слова активації, мовлення та відтворення."
"Прослуховування (PTT)"
"Пропозицію відхилено."
"користувач"
@@ -126,7 +127,6 @@
"Посібник із налаштування Android"
"Пересилання заблоковано для %1$s застосунків."
"Спарені пристрої"
- "Налаштуйте голос, передавання та відтворення."
"%1$s очікують"
"Назва пристрою"
"Місцезнаходження"
@@ -151,6 +151,7 @@
"+%1$s ще"
"thread create"
"Заблоковано"
+ "Слово або фраза активації"
"Gateway потребує схвалення пристрою"
"%1$s/%2$s готово"
"Підключено (оператор не в мережі)"
@@ -163,6 +164,7 @@
"Зображення"
"Закрити попередній перегляд зображення"
"eval"
+ "Остання команда: %1$s"
"Відкрийте термінал на пристрої, на якому запущено OpenClaw."
"Нічого не бракує"
"Для виводу полотна потрібне активне підключення до Gateway."
@@ -206,6 +208,7 @@
"Підключення до Gateway"
"Gateway може змінити цей шлях, але не може очистити наявний шлях."
"TTS"
+ "Збереження…"
"Прив’язка %1$s"
"search"
"Переглядайте заплановані завдання Gateway і керуйте ними."
@@ -369,6 +372,7 @@
"Період очікування %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Розпізнавання мовлення на пристрої недоступне."
"Вкладення завеликі, щоб додати їх до черги в одному повідомленні; видаліть деякі з них і спробуйте ще раз."
"Налаштовано 1 модель. Оновіть, щоб повторно перевірити доступність."
"Для цього хоста потрібне захищене з’єднання."
@@ -413,6 +417,7 @@
"незабаром"
"Немає затверджень Gateway."
"Хост"
+ "Додайте одне слово або фразу активації в кожне поле. Потім промовте його перед командою."
"Транскрибувати й надіслати"
"Виконати о"
"Доступ до пристрою Gateway"
@@ -475,6 +480,7 @@
"Пошук в OpenClaw"
"Основний сеанс"
"%1$s очікують"
+ "Розпізнавання мовлення на пристрої недоступне"
"Немає застосунку, який може поділитися цим повідомленням"
"Закрити пошук"
"Команда для відстеження"
@@ -507,6 +513,7 @@
"Каталог розмов Gateway не завантажено"
"цей Gateway"
"Ще немає останніх запусків."
+ "Мовна модель на пристрої недоступна"
"Відповідні пропозиції з’являться тут після того, як агенти створять чернетки багаторазових Skills."
"Session Search"
"OpenClaw говорить"
@@ -526,6 +533,7 @@
"Поверхня екрана готова"
"Спарити Gateway"
"Підключіть Gateway, щоб завантажити канали."
+ "Призупиняється під час іншої голосової активності."
"Модель"
"Фото"
"Вставити код налаштування"
@@ -566,10 +574,12 @@
"pin"
"Копіювати %1$s"
"Спарено"
+ "Не вдалося зберегти слова активації"
"Буде ізольовано \"%1$s\", а стан Майстерні навичок оновлено з Gateway."
"Записати голосове повідомлення"
"Дозволяти інструменти камери за запитом."
"Проблеми"
+ "Голосова активація"
"%1$s дн тому"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Нещодавні"
"Результат вирішення невідомий. Дії залишатимуться недоступними, доки запис у Gateway не буде перевірено."
"dialog"
+ "Слухати слова активації"
"camera snap"
"Gateway вибрав невідомого постачальника %1$s"
"Слідувати Android · %1$s"
@@ -613,6 +624,7 @@
"Навичка"
"Gateway не визначив активного постачальника %1$s"
"Очікування"
+ "Слова активації збережено"
"Спочатку найстаріші"
"Екран"
"Виконується з"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Провайдери та налаштовані моделі"
"Підключення…"
+ "Підключіться до Gateway, щоб зберегти слова активації"
"Відкрити профіль"
"Запустіть свій Gateway."
"Допоможіть мені перетворити цю мету на практичний контрольний список: "
@@ -700,6 +713,7 @@
"OpenClaw відповідає"
"Документація"
"Готово: %1$s"
+ "Мова пристрою не підтримується"
"У черзі — буде надіслано після відновлення з’єднання"
"%1$s хв тому"
"Перевірка доступу для спарювання"
@@ -731,6 +745,7 @@
"Дозволити планувальнику запускати цю автоматизацію."
"%1$s застосовано"
"Щоденника снів ще немає."
+ "Працює на пристрої, поки OpenClaw відображається на екрані."
"%1$s працює"
"%1$s %2$s"
"Необроблені дані"
@@ -870,6 +885,7 @@
"Автоматизацію призупинено."
"OpenClaw для мобільних пристроїв"
"A2UI reset"
+ "Gateway недоступний"
"Read"
"Для цієї навички потрібно налаштувати 1 елемент. Android показує, що встановлено; початкове налаштування та зміни конфігурації виконуються на комп’ютері або через CLI."
"Останній запуск"
@@ -976,6 +992,7 @@
"Відхилено"
"Включати Android і фонові пакети."
"Ваш Gateway готовий."
+ "Активовано"
"Це займає більше часу, ніж очікувалося.\nПереконайтеся, що Gateway запущено й він доступний."
"Повторне підключення"
"OpenClaw перевіряє доступ до Gateway і вузла."
@@ -1021,6 +1038,7 @@
"Збережені дані автентифікації недійсні"
"%1$s областей доступу"
"Підключіть gateway, щоб завантажити останні журнали."
+ "Зберегти слова активації"
"Керуйте встановленими навичками та додавайте довірені випуски з ClawHub."
"Надсилання…"
"Агентів ще не завантажено."
@@ -1032,7 +1050,7 @@
"З’єднання між цим телефоном і OpenClaw."
"summarize"
"Це назавжди видалить сеанс і його стенограму."
- "Запускається…"
+ "Запуск…"
"Помилка клієнта"
"%1$s %2$s"
"Автоматизацію ввімкнено."
@@ -1055,6 +1073,7 @@
"Офлайн-черга заповнена (%1$s повідомлень); спочатку видаліть елементи з черги."
"Загальнодоступні шлюзи мають використовувати wss:// або Tailscale Serve. ws:// дозволено для localhost, хостів .local, емулятора Android і приватних IP-адрес локальної мережі."
"Підключіть Gateway, щоб завантажити відомості про Skill."
+ "Прослуховування слів активації"
"Розгорнути попередній перегляд посилання"
"NULL (ПОМИЛКА)"
"Оновити"
@@ -1196,6 +1215,7 @@
"Не вдалося завантажити цю папку."
"QR-код не містив дійсного коду налаштування."
"Перевірте доступ до вузла"
+ "Додати фразу активації"
"Не вдалося підключитися до Gateway"
"Автоматизація"
"Потрібне підключення"
@@ -1225,6 +1245,7 @@
"Назва"
"Версія"
"Cron"
+ "Видалити фразу активації"
"Код налаштування не прийнято. Згенеруйте новий код за допомогою openclaw qr."
"14 повідомлень · Android"
"Не вдалося транскрибувати: %1$s"
@@ -1366,6 +1387,7 @@
"Розархівувати"
"Transcripts"
"Нещодавні сеанси"
+ "Слова активації"
"Налаштуйте %1$s на Gateway"
"Відскануйте QR-код або використайте код налаштування з вашого OpenClaw Gateway."
"Прототип дизайн-системи"
diff --git a/apps/android/app/src/main/res/values-vi/strings.xml b/apps/android/app/src/main/res/values-vi/strings.xml
index 2cd10033a92a..289c831a7805 100644
--- a/apps/android/app/src/main/res/values-vi/strings.xml
+++ b/apps/android/app/src/main/res/values-vi/strings.xml
@@ -46,6 +46,7 @@
"Gateway sẽ xác minh chính xác bản phát hành này với ClawHub trước khi tải xuống. Nếu bản phát hành yêu cầu xác nhận rõ ràng về rủi ro, Android sẽ hiển thị cảnh báo của Gateway trước khi thử lại."
"Mã thiết lập sử dụng ID vùng IPv6. Hãy dùng địa chỉ IPv6 không có phạm vi hoặc tên máy chủ LAN."
"Tệp đính kèm"
+ "Thiết lập từ đánh thức, trò chuyện và phát âm thanh."
"Đang nghe (PTT)"
"Đã từ chối đề xuất."
"người dùng"
@@ -126,7 +127,6 @@
"Hướng dẫn thiết lập Android"
"%1$s ứng dụng bị chặn chuyển tiếp."
"Thiết bị đã ghép đôi"
- "Cấu hình giọng nói, truyền tải và phát lại."
"%1$s đang chờ"
"Tên thiết bị"
"Vị trí"
@@ -151,6 +151,7 @@
"+%1$s nữa"
"thread create"
"Bị chặn"
+ "Từ hoặc cụm từ đánh thức"
"Gateway cần phê duyệt thiết bị"
"%1$s/%2$s đã sẵn sàng"
"Đã kết nối (người vận hành đang ngoại tuyến)"
@@ -163,6 +164,7 @@
"Hình ảnh"
"Đóng xem trước hình ảnh"
"eval"
+ "Lệnh gần nhất: %1$s"
"Mở sẵn một terminal trên thiết bị đang chạy OpenClaw."
"Không thiếu mục nào"
"Đầu ra canvas cần có kết nối Gateway đang hoạt động."
@@ -206,6 +208,7 @@
"Đang kết nối với Gateway"
"Gateway có thể thay đổi đường dẫn này nhưng không thể xóa đường dẫn hiện có."
"TTS"
+ "Đang lưu…"
"Mốc %1$s"
"search"
"Kiểm tra và quản lý công việc Gateway đã lên lịch."
@@ -369,6 +372,7 @@
"Thời gian chờ %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "Tính năng nhận dạng giọng nói trên thiết bị không khả dụng."
"Các tệp đính kèm quá lớn để đưa vào hàng đợi trong một tin nhắn; hãy xóa bớt rồi thử lại."
"1 mô hình đã được cấu hình. Làm mới để kiểm tra lại tính khả dụng."
"Máy chủ này yêu cầu kết nối bảo mật."
@@ -413,6 +417,7 @@
"sắp tới"
"Không có phê duyệt gateway."
"Máy chủ"
+ "Thêm một từ hoặc cụm từ đánh thức vào mỗi trường. Sau đó, hãy nói một từ hoặc cụm từ đó trước lệnh của bạn."
"Chuyển lời nói thành văn bản rồi gửi"
"Chạy lúc"
"Quyền truy cập vào thiết bị Gateway"
@@ -475,6 +480,7 @@
"Tìm kiếm OpenClaw"
"Phiên chính"
"%1$s đang chờ"
+ "Nhận dạng giọng nói trên thiết bị không khả dụng"
"Không có ứng dụng nào có thể chia sẻ tin nhắn này"
"Đóng tìm kiếm"
"Lệnh cần theo dõi"
@@ -507,6 +513,7 @@
"Chưa tải danh mục trò chuyện Gateway"
"Gateway này"
"Chưa có lần chạy nào gần đây."
+ "Mô hình ngôn ngữ trên thiết bị không khả dụng"
"Các đề xuất phù hợp sẽ xuất hiện ở đây sau khi agent tạo bản nháp skill có thể tái sử dụng."
"Session Search"
"OpenClaw đang nói"
@@ -526,6 +533,7 @@
"Bề mặt màn hình đã sẵn sàng"
"Ghép nối Gateway"
"Kết nối Gateway để tải kênh."
+ "Tạm dừng khi có hoạt động giọng nói khác."
"Mô hình"
"Ảnh"
"Dán mã thiết lập"
@@ -566,10 +574,12 @@
"pin"
"Sao chép %1$s"
"Đã ghép đôi"
+ "Không thể lưu từ đánh thức"
"Thao tác này sẽ cách ly \"%1$s\" và làm mới trạng thái Skill Workshop từ Gateway."
"Ghi ghi chú thoại"
"Cho phép dùng công cụ camera khi được yêu cầu."
"Sự cố"
+ "Đánh thức bằng giọng nói"
"%1$s ngày trước"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Gần đây"
"Không rõ kết quả xử lý. Các thao tác vẫn bị vô hiệu hóa cho đến khi bản ghi Gateway được xác minh."
"dialog"
+ "Lắng nghe từ đánh thức"
"camera snap"
"Gateway đã chọn nhà cung cấp không xác định %1$s"
"Theo Android · %1$s"
@@ -613,6 +624,7 @@
"Kỹ năng"
"Gateway không xác định nhà cung cấp %1$s đang hoạt động"
"Đang chờ"
+ "Đã lưu từ đánh thức"
"Cũ nhất trước"
"Màn hình"
"Đang chạy từ"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Nhà cung cấp và mô hình đã cấu hình"
"Đang kết nối…"
+ "Kết nối với Gateway để lưu từ đánh thức"
"Mở hồ sơ"
"Khởi động Gateway của bạn."
"Hãy giúp tôi biến mục tiêu này thành một danh sách kiểm tra thiết thực: "
@@ -700,6 +713,7 @@
"OpenClaw đang trả lời"
"Tài liệu"
"%1$s sẵn sàng"
+ "Ngôn ngữ của thiết bị không được hỗ trợ"
"Đã xếp hàng — sẽ gửi khi kết nối lại"
"%1$s phút trước"
"Đang kiểm tra quyền ghép nối"
@@ -731,6 +745,7 @@
"Cho phép trình lập lịch chạy tác vụ tự động này."
"%1$s đã áp dụng"
"Chưa có nhật ký giấc mơ."
+ "Chạy trên thiết bị khi OpenClaw đang hiển thị."
"%1$s đang làm việc"
"%1$s %2$s"
"Thô"
@@ -870,6 +885,7 @@
"Đã tạm dừng tác vụ tự động."
"OpenClaw dành cho thiết bị di động"
"A2UI reset"
+ "Gateway không khả dụng"
"Read"
"Skill này cần thiết lập 1 mục. Android hiển thị những gì đã được cài đặt; việc thiết lập/thay đổi cấu hình chỉ có thể thực hiện trên máy tính hoặc CLI."
"Lần chạy gần nhất"
@@ -976,6 +992,7 @@
"Đã từ chối"
"Bao gồm Android và các gói chạy nền."
"Gateway của bạn đã sẵn sàng."
+ "Đã kích hoạt"
"Quá trình này mất nhiều thời gian hơn dự kiến.\nHãy kiểm tra để đảm bảo Gateway đang chạy và có thể truy cập được."
"Đang kết nối lại"
"OpenClaw đang kiểm tra quyền truy cập Gateway và nút."
@@ -1021,6 +1038,7 @@
"Xác thực đã lưu không hợp lệ"
"%1$s phạm vi"
"Kết nối gateway để tải nhật ký gần đây."
+ "Lưu từ đánh thức"
"Quản lý các skill đã cài đặt và thêm các bản phát hành đáng tin cậy từ ClawHub."
"Đang gửi…"
"Chưa tải agent nào."
@@ -1055,6 +1073,7 @@
"Hàng đợi ngoại tuyến đã đầy (%1$s tin nhắn); trước tiên, hãy xóa các mục đang chờ."
"Gateway công khai yêu cầu wss:// hoặc Tailscale Serve. ws:// được phép dùng cho localhost, máy chủ .local, trình giả lập Android và các địa chỉ IP LAN riêng."
"Kết nối Gateway để tải thông tin chi tiết về Skill."
+ "Trình nghe từ đánh thức"
"Mở rộng bản xem trước liên kết"
"NULL (THẤT BẠI)"
"Cập nhật"
@@ -1196,6 +1215,7 @@
"Không thể tải thư mục này."
"Mã QR không chứa mã thiết lập hợp lệ."
"Xem lại quyền truy cập nút"
+ "Thêm cụm từ đánh thức"
"Không thể kết nối với Gateway"
"Tác vụ tự động"
"Cần kết nối"
@@ -1225,6 +1245,7 @@
"Tên"
"Phiên bản"
"Cron"
+ "Xóa cụm từ đánh thức"
"Mã thiết lập không được chấp nhận. Hãy tạo mã mới bằng openclaw qr."
"14 tin nhắn · Android"
"Phiên âm không thành công: %1$s"
@@ -1366,6 +1387,7 @@
"Bỏ lưu trữ"
"Transcripts"
"Phiên gần đây"
+ "Từ đánh thức"
"Cấu hình %1$s trên Gateway"
"Quét mã QR hoặc dùng mã thiết lập từ OpenClaw Gateway của bạn."
"Nguyên mẫu hệ thống thiết kế"
diff --git a/apps/android/app/src/main/res/values-zh-rCN/strings.xml b/apps/android/app/src/main/res/values-zh-rCN/strings.xml
index 533ea8782569..77140b9f43cf 100644
--- a/apps/android/app/src/main/res/values-zh-rCN/strings.xml
+++ b/apps/android/app/src/main/res/values-zh-rCN/strings.xml
@@ -46,6 +46,7 @@
"Gateway 将在下载前通过 ClawHub 验证此确切版本。如果该版本需要明确确认风险,Android 将在重试前显示 Gateway 警告。"
"设置代码使用了 IPv6 区域 ID。请使用无作用域的 IPv6 地址或 LAN 主机名。"
"附件"
+ "配置唤醒词、语音交互和播放。"
"正在聆听(按住说话)"
"提案已拒绝。"
"用户"
@@ -126,7 +127,6 @@
"Android 设置指南"
"已阻止 %1$s 个应用转发。"
"已配对设备"
- "配置语音、传输和播放。"
"%1$s 项待审批"
"设备名称"
"位置"
@@ -151,6 +151,7 @@
"+%1$s 个更多"
"thread create"
"已阻止"
+ "唤醒词或短语"
"Gateway 需要设备批准"
"%1$s/%2$s 个已就绪"
"已连接(操作员离线)"
@@ -163,6 +164,7 @@
"图片"
"关闭图片预览"
"eval"
+ "上一条命令:%1$s"
"在运行 OpenClaw 的设备上打开终端。"
"没有缺失项"
"画布输出需要有效的 Gateway 连接。"
@@ -206,6 +208,7 @@
"正在连接 Gateway"
"Gateway 可以更改此路径,但无法清除现有路径。"
"TTS"
+ "正在保存…"
"锚点 %1$s"
"search"
"查看和管理已安排的 Gateway 任务。"
@@ -369,6 +372,7 @@
"冷却时间 %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"短信"
+ "设备端语音识别不可用。"
"附件过大,无法加入单条消息的队列;请移除部分附件后重试。"
"已配置 1 个模型。刷新以重新检查可用性。"
"此主机需要安全连接。"
@@ -413,6 +417,7 @@
"即将"
"没有 Gateway 审批。"
"主机"
+ "每个字段添加一个唤醒词或短语,然后在说出命令前先说出其中一个。"
"转写后发送"
"运行时间"
"访问 Gateway 设备"
@@ -475,6 +480,7 @@
"搜索 OpenClaw"
"主会话"
"%1$s 个待处理"
+ "设备端语音识别不可用"
"没有应用可以分享此消息"
"关闭搜索"
"要监视的命令"
@@ -507,6 +513,7 @@
"Gateway 对话目录未加载"
"此 Gateway"
"暂无最近运行。"
+ "设备端语言模型不可用"
"在代理创建可重用的 Skills 草稿后,匹配的提案将显示在此处。"
"Session Search"
"OpenClaw 正在说话"
@@ -526,6 +533,7 @@
"屏幕表面已就绪"
"配对 Gateway"
"连接 Gateway 以加载渠道。"
+ "检测到其他语音活动时暂停。"
"模型"
"照片"
"粘贴设置代码"
@@ -566,10 +574,12 @@
"pin"
"复制 %1$s"
"已配对"
+ "无法保存唤醒词"
"这将隔离“%1$s”,并从 Gateway 刷新 Skill Workshop 状态。"
"录制语音留言"
"在请求时允许使用相机工具。"
"问题"
+ "语音唤醒"
"%1$s 天前"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"最近"
"处理结果未知。在验证 Gateway 记录之前,操作将保持禁用。"
"dialog"
+ "监听唤醒词"
"camera snap"
"Gateway 选择了未知提供商 %1$s"
"跟随 Android · %1$s"
@@ -613,6 +624,7 @@
"技能"
"Gateway 未识别活动的 %1$s 提供商"
"等待中"
+ "唤醒词已保存"
"最早优先"
"屏幕"
"运行开始时间"
@@ -645,6 +657,7 @@
"%1$s...(正常)"
"提供商和已配置的模型"
"正在连接…"
+ "连接到 Gateway 以保存唤醒词"
"打开个人资料"
"启动你的 Gateway。"
"帮我将此目标转化为实用的检查清单:"
@@ -700,6 +713,7 @@
"OpenClaw 正在回复"
"文档"
"%1$s 个已就绪"
+ "不支持设备语言"
"已加入队列 — 重新连接后发送"
"%1$s 分钟前"
"正在检查配对访问权限"
@@ -731,6 +745,7 @@
"允许调度程序运行此自动化。"
"%1$s 个已应用"
"还没有梦境日记。"
+ "当 OpenClaw 可见时在设备上运行。"
"%1$s 正在工作"
"%1$s %2$s"
"原始"
@@ -870,6 +885,7 @@
"自动化已暂停。"
"OpenClaw 移动版"
"A2UI reset"
+ "Gateway 不可用"
"Read"
"此技能需要设置 1 项。Android 会显示已安装的内容;设置和配置更改需通过桌面端或 CLI 完成。"
"上次运行"
@@ -976,6 +992,7 @@
"已拒绝"
"包括 Android 和后台包。"
"您的 Gateway 已准备就绪。"
+ "已触发"
"所需时间比预期更长。\n请检查 Gateway 是否正在运行且可访问。"
"正在重新连接"
"OpenClaw 正在检查 Gateway 和节点访问权限。"
@@ -1021,6 +1038,7 @@
"保存的身份验证无效"
"%1$s 个权限范围"
"连接 Gateway 以加载最近日志。"
+ "保存唤醒词"
"管理已安装的 Skills,并从 ClawHub 添加受信任的版本。"
"正在发送…"
"尚未加载代理。"
@@ -1055,6 +1073,7 @@
"离线队列已满(%1$s 条消息);请先删除队列中的项目。"
"公共 Gateway 需要使用 wss:// 或 Tailscale Serve。localhost、.local 主机、Android 模拟器和专用局域网 IP 允许使用 ws://。"
"连接 Gateway 以加载 Skill 详情。"
+ "唤醒监听器"
"展开链接预览"
"NULL(失败)"
"更新"
@@ -1196,6 +1215,7 @@
"无法加载此文件夹。"
"二维码不包含有效的设置代码。"
"检查节点访问权限"
+ "添加唤醒短语"
"无法连接到 Gateway"
"自动化"
"需要连接"
@@ -1225,6 +1245,7 @@
"名称"
"版本"
"Cron"
+ "移除唤醒短语"
"设置代码未被接受。请使用 openclaw qr 生成新代码。"
"14 条消息 · Android"
"转录失败:%1$s"
@@ -1366,6 +1387,7 @@
"取消归档"
"Transcripts"
"最近会话"
+ "唤醒词"
"在 Gateway 上配置 %1$s"
"扫描二维码或使用来自您的 OpenClaw Gateway 的设置代码。"
"设计系统原型"
diff --git a/apps/android/app/src/main/res/values-zh-rTW/strings.xml b/apps/android/app/src/main/res/values-zh-rTW/strings.xml
index c122beccf29c..fb18ba7122b1 100644
--- a/apps/android/app/src/main/res/values-zh-rTW/strings.xml
+++ b/apps/android/app/src/main/res/values-zh-rTW/strings.xml
@@ -46,6 +46,7 @@
"Gateway 會在下載前透過 ClawHub 驗證此確切版本。如果該版本需要明確確認風險,Android 會在重試前顯示 Gateway 警告。"
"設定代碼使用 IPv6 區域 ID。請使用未限定範圍的 IPv6 位址或 LAN 主機名稱。"
"附件"
+ "設定喚醒詞、對話與播放。"
"正在聆聽(PTT)"
"提案已拒絕。"
"使用者"
@@ -126,7 +127,6 @@
"Android 設定指南"
"已封鎖 %1$s 個應用程式進行轉送。"
"已配對裝置"
- "設定語音、傳輸和播放。"
"%1$s 個待核准項目"
"裝置名稱"
"位置"
@@ -151,6 +151,7 @@
"另有 %1$s 個"
"thread create"
"已封鎖"
+ "喚醒詞或詞組"
"Gateway 需要裝置核准"
"%1$s/%2$s 個已就緒"
"已連線(操作員離線)"
@@ -163,6 +164,7 @@
"圖片"
"關閉圖片預覽"
"eval"
+ "上一個指令:%1$s"
"請在執行 OpenClaw 的裝置上開啟終端機。"
"沒有缺少的項目"
"畫布輸出需要有效的 Gateway 連線。"
@@ -206,6 +208,7 @@
"正在連線至 Gateway"
"gateway 可以變更此路徑,但無法清除現有路徑。"
"TTS"
+ "儲存中…"
"錨點 %1$s"
"search"
"檢視及管理已排程的 Gateway 工作。"
@@ -369,6 +372,7 @@
"冷卻時間 %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"簡訊"
+ "無法使用裝置端語音辨識。"
"附件過大,無法加入單則訊息的佇列;請移除部分附件後再試一次。"
"已設定 1 個模型。請重新整理以再次檢查可用性。"
"此主機需要安全連線。"
@@ -413,6 +417,7 @@
"即將"
"沒有 Gateway 核准。"
"主機"
+ "每個欄位新增一個喚醒詞或詞組,然後在說出指令前先說出其中一個。"
"轉錄後傳送"
"執行於"
"存取 Gateway 裝置"
@@ -475,6 +480,7 @@
"搜尋 OpenClaw"
"主要工作階段"
"%1$s 個待處理"
+ "裝置端語音辨識無法使用"
"沒有應用程式可分享此訊息"
"關閉搜尋"
"要監看的命令"
@@ -507,6 +513,7 @@
"Gateway 對話目錄尚未載入"
"此 Gateway"
"尚無最近的執行。"
+ "裝置端語言模型無法使用"
"當代理建立可重複使用的 Skill 草稿後,符合的提案會顯示在這裡。"
"Session Search"
"OpenClaw 正在說話"
@@ -526,6 +533,7 @@
"螢幕介面已就緒"
"配對 Gateway"
"連接 Gateway 以載入頻道。"
+ "進行其他語音活動時會暫停。"
"模型"
"照片"
"貼上設定代碼"
@@ -566,10 +574,12 @@
"pin"
"複製 %1$s"
"已配對"
+ "無法儲存喚醒詞"
"這將隔離「%1$s」,並從 Gateway 重新整理 Skill Workshop 狀態。"
"錄製語音留言"
"在要求時允許使用相機工具。"
"問題"
+ "語音喚醒"
"%1$s 天前"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"最近"
"解析結果不明。在驗證 Gateway 記錄之前,操作將維持停用。"
"dialog"
+ "聆聽喚醒詞"
"camera snap"
"Gateway 選取了未知的供應商 %1$s"
"依循 Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway 未識別作用中的 %1$s 供應商"
"等待中"
+ "已儲存喚醒詞"
"最舊優先"
"螢幕"
"開始執行時間"
@@ -645,6 +657,7 @@
"%1$s...(正常)"
"供應商與已設定的模型"
"正在連線…"
+ "連線至 Gateway 以儲存喚醒詞"
"開啟個人檔案"
"啟動您的 Gateway。"
"協助我將此目標轉換為實用的檢查清單: "
@@ -700,6 +713,7 @@
"OpenClaw 正在回覆"
"文件"
"%1$s 個已就緒"
+ "不支援裝置語言"
"已排入佇列 — 重新連線後傳送"
"%1$s 分鐘前"
"正在檢查配對存取權限"
@@ -731,6 +745,7 @@
"允許排程器執行此自動化。"
"%1$s 個已套用"
"尚無夢境日記。"
+ "當 OpenClaw 顯示於畫面時,會在裝置上執行。"
"%1$s 正在運作"
"%1$s %2$s"
"原始"
@@ -870,6 +885,7 @@
"自動化已暫停。"
"OpenClaw 行動版"
"A2UI reset"
+ "Gateway 無法使用"
"Read"
"此技能需要設定 1 個項目。Android 會顯示已安裝的內容;設定變更須在桌面版或 CLI 上進行。"
"上次執行"
@@ -976,6 +992,7 @@
"已拒絕"
"包含 Android 和背景套件。"
"您的 Gateway 已準備就緒。"
+ "已觸發"
"所需時間比預期更長。\n請確認 Gateway 正在執行且可連線。"
"正在重新連線"
"OpenClaw 正在檢查 Gateway 和節點存取權限。"
@@ -1021,6 +1038,7 @@
"已儲存的驗證無效"
"%1$s 個範圍"
"連線 Gateway 以載入最近記錄。"
+ "儲存喚醒詞"
"管理已安裝的技能,並從 ClawHub 新增受信任的發行版本。"
"傳送中…"
"尚未載入任何代理程式。"
@@ -1055,6 +1073,7 @@
"離線佇列已滿(%1$s 則訊息);請先刪除佇列中的項目。"
"公用 Gateway 必須使用 wss:// 或 Tailscale Serve。localhost、.local 主機、Android 模擬器和私人區域網路 IP 可使用 ws://。"
"連接 Gateway 以載入 Skill 詳細資料。"
+ "喚醒詞偵聽器"
"展開連結預覽"
"NULL(失敗)"
"更新"
@@ -1196,6 +1215,7 @@
"無法載入此資料夾。"
"QR code 未包含有效的設定碼。"
"檢查節點存取權"
+ "新增喚醒詞組"
"無法連線至 Gateway"
"自動化"
"需要連線"
@@ -1225,6 +1245,7 @@
"名稱"
"版本"
"Cron"
+ "移除喚醒詞組"
"設定代碼未被接受。請使用 openclaw qr 產生新的代碼。"
"14 則訊息 · Android"
"轉錄失敗:%1$s"
@@ -1366,6 +1387,7 @@
"取消封存"
"Transcripts"
"最近的工作階段"
+ "喚醒詞"
"在 Gateway 上設定 %1$s"
"掃描 QR code,或使用 OpenClaw Gateway 提供的設定代碼。"
"設計系統原型"
diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml
index a080b4743cf5..d8f02224d747 100644
--- a/apps/android/app/src/main/res/values/strings.xml
+++ b/apps/android/app/src/main/res/values/strings.xml
@@ -46,6 +46,7 @@
"The Gateway will verify this exact release with ClawHub before download. If the release needs explicit risk acknowledgement, Android will show the Gateway warning before retrying."
"Setup code uses an IPv6 zone ID. Use an unscoped IPv6 address or a LAN hostname."
"Attachment"
+ "Configure wake words, talk, and playback."
"Listening (PTT)"
"Proposal rejected."
"user"
@@ -126,7 +127,6 @@
"Android setup guide"
"%1$s apps blocked from forwarding."
"Paired Devices"
- "Configure voice, transport, and playback."
"%1$s pending"
"Device name"
"Location"
@@ -151,6 +151,7 @@
"+%1$s more"
"thread create"
"Blocked"
+ "Wake word or phrase"
"Gateway needs device approval"
"%1$s/%2$s ready"
"Connected (operator offline)"
@@ -163,6 +164,7 @@
"Image"
"Close image preview"
"eval"
+ "Last command: %1$s"
"Have a terminal open on the device running OpenClaw."
"No missing items"
"Canvas output needs an active gateway connection."
@@ -206,6 +208,7 @@
"Connecting Gateway"
"The gateway can change this path but cannot clear an existing path."
"TTS"
+ "Saving…"
"Anchor %1$s"
"search"
"Inspect and manage scheduled gateway work."
@@ -369,6 +372,7 @@
"Cooldown %1$s"
"This skill is disabled on the gateway. Enable it here when the current connection has operator.admin."
"SMS"
+ "On-device speech recognition is unavailable."
"Attachments are too large to queue for one message; remove some and try again."
"1 configured model. Refresh to recheck availability."
"Secure connection is required for this host."
@@ -413,6 +417,7 @@
"soon"
"No gateway approvals."
"Host"
+ "Add one wake word or phrase per field. Then say one before your command."
"Transcribe then send"
"Run at"
"Access to the Gateway device"
@@ -475,6 +480,7 @@
"Search OpenClaw"
"Main session"
"%1$s pending"
+ "On-device speech recognition unavailable"
"No app can share this message"
"Close search"
"Command to watch"
@@ -507,6 +513,7 @@
"Gateway talk catalog not loaded"
"this gateway"
"No recent runs yet."
+ "On-device language model unavailable"
"Matching proposals will appear here after agents create reusable skill drafts."
"Session Search"
"OpenClaw is speaking"
@@ -526,6 +533,7 @@
"Screen surface ready"
"Pair Gateway"
"Connect the gateway to load channels."
+ "Pauses during other voice activity."
"Model"
"Photos"
"Paste setup code"
@@ -566,10 +574,12 @@
"pin"
"Copy %1$s"
"Paired"
+ "Could not save wake words"
"This will quarantine \"%1$s\" and refresh Skill Workshop state from the gateway."
"Record voice note"
"Allow camera tools when requested."
"Issues"
+ "Voice Wake"
"%1$sd ago"
"roles"
"Skills"
@@ -585,6 +595,7 @@
"Recent"
"Resolution outcome unknown. Actions stay disabled until the Gateway record is verified."
"dialog"
+ "Listen for wake words"
"camera snap"
"Gateway selected unknown provider %1$s"
"Follow Android · %1$s"
@@ -613,6 +624,7 @@
"Skill"
"Gateway did not identify the active %1$s provider"
"Waiting"
+ "Wake words saved"
"Oldest first"
"Screen"
"Running Since"
@@ -645,6 +657,7 @@
"%1$s... (OK)"
"Providers and configured models"
"Connecting…"
+ "Connect to a Gateway to save wake words"
"Open profile"
"Start your Gateway."
"Help me turn this goal into a practical checklist: "
@@ -700,6 +713,7 @@
"OpenClaw is replying"
"Docs"
"%1$s ready"
+ "Device language not supported"
"Queued — sends when reconnected"
"%1$sm ago"
"Checking pairing access"
@@ -731,6 +745,7 @@
"Allow the scheduler to run this automation."
"%1$s applied"
"No dream diary yet."
+ "Runs on-device while OpenClaw is visible."
"%1$s is working"
"%1$s %2$s"
"Raw"
@@ -870,6 +885,7 @@
"Automation paused."
"OpenClaw mobile"
"A2UI reset"
+ "Gateway unavailable"
"Read"
"This skill needs 1 setup item. Android shows what is installed; setup/config changes stay on desktop or CLI."
"Last Run"
@@ -976,6 +992,7 @@
"Rejected"
"Include Android and background packages."
"Your Gateway is ready."
+ "Triggered"
"This is taking longer than expected.\nCheck that the Gateway is running and reachable."
"Reconnecting"
"OpenClaw is checking gateway and node access."
@@ -1021,6 +1038,7 @@
"Saved auth invalid"
"%1$s scopes"
"Connect the gateway to load recent logs."
+ "Save wake words"
"Manage installed skills and add trusted releases from ClawHub."
"Sending…"
"No agents loaded yet."
@@ -1055,6 +1073,7 @@
"Offline queue is full (%1$s messages); delete queued items first."
"Public gateways require wss:// or Tailscale Serve. ws:// is allowed for localhost, .local hosts, the Android emulator, and private LAN IPs."
"Connect the gateway to load skill details."
+ "Wake listener"
"Expand link preview"
"NULL (FAILED)"
"Update"
@@ -1196,6 +1215,7 @@
"Could not load this folder."
"QR code did not contain a valid setup code."
"Review node access"
+ "Add wake phrase"
"Cannot reach gateway"
"Automation"
"Needs connection"
@@ -1225,6 +1245,7 @@
"Name"
"Version"
"Cron"
+ "Remove wake phrase"
"Setup code was not accepted. Generate a fresh code with openclaw qr."
"14 messages · Android"
"Transcription failed: %1$s"
@@ -1366,6 +1387,7 @@
"Unarchive"
"Transcripts"
"Recent Sessions"
+ "Wake words"
"Configure %1$s on the Gateway"
"Scan a QR code or use the setup code from your OpenClaw Gateway."
"Design system prototype"
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/AndroidScreenshotModeTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/AndroidScreenshotModeTest.kt
index 2211bffa0c15..97e91d30e7b0 100644
--- a/apps/android/app/src/test/java/ai/openclaw/app/AndroidScreenshotModeTest.kt
+++ b/apps/android/app/src/test/java/ai/openclaw/app/AndroidScreenshotModeTest.kt
@@ -47,6 +47,7 @@ class AndroidScreenshotModeTest {
assertEquals(HomeDestination.Chat, AndroidScreenshotScene.Chat.homeDestination)
assertEquals(HomeDestination.Voice, AndroidScreenshotScene.Voice.homeDestination)
assertEquals(HomeDestination.Settings, AndroidScreenshotScene.Settings.homeDestination)
+ assertEquals(HomeDestination.Settings, AndroidScreenshotScene.VoiceWake.homeDestination)
}
@Test
@@ -63,4 +64,12 @@ class AndroidScreenshotModeTest {
assertEquals(SettingsRoute.Gateway, parsed?.settingsRoute)
assertNull(AndroidScreenshotScene.Settings.settingsRoute)
}
+
+ @Test
+ fun voiceWakeSceneTargetsVoiceSettings() {
+ val scene = AndroidScreenshotScene.fromRawValue("voice-wake")
+
+ assertEquals(AndroidScreenshotScene.VoiceWake, scene)
+ assertEquals(SettingsRoute.Voice, scene.settingsRoute)
+ }
}
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/SecurePrefsTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/SecurePrefsTest.kt
index f6c94bb6ed12..0d8053512e73 100644
--- a/apps/android/app/src/test/java/ai/openclaw/app/SecurePrefsTest.kt
+++ b/apps/android/app/src/test/java/ai/openclaw/app/SecurePrefsTest.kt
@@ -86,6 +86,24 @@ class SecurePrefsTest {
assertFalse(plainPrefs.getBoolean("talk.enabled", false))
}
+ @Test
+ fun voiceWakeSettingsDefaultAndPersist() {
+ val context = RuntimeEnvironment.getApplication()
+ val plainPrefs = context.getSharedPreferences("openclaw.node", Context.MODE_PRIVATE)
+ plainPrefs.edit().clear().commit()
+ val prefs = testPrefs(context)
+
+ assertFalse(prefs.voiceWakeEnabled.value)
+ assertEquals(listOf("openclaw", "claude", "computer"), prefs.voiceWakeWords.value)
+
+ prefs.setVoiceWakeEnabled(true)
+ prefs.setVoiceWakeWords(listOf(" hey claw ", "computer"))
+
+ val restored = testPrefs(context)
+ assertTrue(restored.voiceWakeEnabled.value)
+ assertEquals(listOf("hey claw", "computer"), restored.voiceWakeWords.value)
+ }
+
@Test
fun installedAppsSharing_defaultsOffAndPersistsDisclosureConsent() {
val context = RuntimeEnvironment.getApplication()
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/VoiceWakeRuntimeTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/VoiceWakeRuntimeTest.kt
new file mode 100644
index 000000000000..e1e08def5e07
--- /dev/null
+++ b/apps/android/app/src/test/java/ai/openclaw/app/VoiceWakeRuntimeTest.kt
@@ -0,0 +1,264 @@
+package ai.openclaw.app
+
+import ai.openclaw.app.gateway.GatewayEndpoint
+import android.Manifest
+import android.content.Context
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.RuntimeEnvironment
+import org.robolectric.Shadows.shadowOf
+import java.util.UUID
+
+@RunWith(RobolectricTestRunner::class)
+class VoiceWakeRuntimeTest {
+ @Test
+ fun disconnectedSaveDoesNotCreateLocalOverride() {
+ val runtime = createTestRuntime()
+
+ runtime.setVoiceWakeWords(listOf("hey claw"))
+
+ assertEquals(listOf("openclaw", "claude", "computer"), runtime.voiceWakeWords.value)
+ assertEquals("Connect to a Gateway to save wake words", runtime.voiceWakeWordsNoticeText.value)
+ assertFalse(runtime.voiceWakeWordsSaving.value)
+ }
+
+ @Test
+ fun successfulSaveCommitsGatewayCanonicalWords() =
+ runBlocking {
+ val runtime = createTestRuntime()
+ seedConnectedRuntime(runtime)
+ runtime.gatewayDataRequestOverrideForTests = { _, method, _ ->
+ assertEquals("voicewake.set", method)
+ """{"triggers":[" gateway claw "]}"""
+ }
+
+ runtime.setVoiceWakeWords(listOf("local draft"))
+ withTimeout(5_000) {
+ while (runtime.voiceWakeWordsSaving.value) delay(10)
+ }
+
+ assertEquals(listOf("gateway claw"), runtime.voiceWakeWords.value)
+ assertEquals("Wake words saved", runtime.voiceWakeWordsNoticeText.value)
+ }
+
+ @Test
+ fun failedGatewaySaveKeepsAuthoritativeWords() =
+ runBlocking {
+ val runtime = createTestRuntime()
+ seedConnectedRuntime(runtime)
+ runtime.gatewayDataRequestOverrideForTests = { _, _, _ -> error("write rejected") }
+
+ runtime.setVoiceWakeWords(listOf("local draft"))
+ withTimeout(5_000) {
+ while (runtime.voiceWakeWordsSaving.value) delay(10)
+ }
+
+ assertEquals(listOf("openclaw", "claude", "computer"), runtime.voiceWakeWords.value)
+ assertEquals("Could not save wake words", runtime.voiceWakeWordsNoticeText.value)
+ }
+
+ @Test
+ fun responseFromRetiredGatewayDoesNotPublish() =
+ runBlocking {
+ val runtime = createTestRuntime()
+ seedConnectedRuntime(runtime)
+ val response = CompletableDeferred()
+ runtime.gatewayDataRequestOverrideForTests = { _, _, _ -> response.await() }
+
+ runtime.setVoiceWakeWords(listOf("stale words"))
+ withTimeout(5_000) {
+ while (!runtime.voiceWakeWordsSaving.value) delay(10)
+ }
+ writeField(runtime, "gatewayDataGeneration", 1L)
+ response.complete("""{"triggers":["stale words"]}""")
+ withTimeout(5_000) {
+ while (runtime.voiceWakeWordsSaving.value) delay(10)
+ }
+
+ assertEquals(listOf("openclaw", "claude", "computer"), runtime.voiceWakeWords.value)
+ assertEquals(null, runtime.voiceWakeWordsNoticeText.value)
+ }
+
+ @Test
+ fun delayedSaveResponseCannotOverwriteNewerGatewayEvent() =
+ runBlocking {
+ val runtime = createTestRuntime()
+ val endpoint = seedConnectedRuntime(runtime)
+ val response = CompletableDeferred()
+ runtime.gatewayDataRequestOverrideForTests = { _, _, _ -> response.await() }
+
+ runtime.setVoiceWakeWords(listOf("local draft"))
+ withTimeout(5_000) {
+ while (!runtime.voiceWakeWordsSaving.value) delay(10)
+ }
+ runtime.applyNodeVoiceWakeWords(
+ endpointStableId = endpoint.stableId,
+ payloadJson = """{"triggers":["newer gateway words"]}""",
+ isCurrentConnection = { true },
+ )
+ response.complete("""{"triggers":["local draft"]}""")
+ withTimeout(5_000) {
+ while (runtime.voiceWakeWordsSaving.value) delay(10)
+ }
+
+ assertEquals(listOf("newer gateway words"), runtime.voiceWakeWords.value)
+ }
+
+ @Test
+ fun nodeOnlyVoiceWakeEventPublishesForCurrentGateway() {
+ val runtime = createTestRuntime()
+ val endpoint = seedConnectedRuntime(runtime)
+
+ runtime.applyNodeVoiceWakeWords(
+ endpointStableId = endpoint.stableId,
+ payloadJson = """{"triggers":[" node claw "]}""",
+ isCurrentConnection = { true },
+ )
+
+ assertEquals(listOf("node claw"), runtime.voiceWakeWords.value)
+ }
+
+ @Test
+ fun nodeOnlyVoiceWakeEventIgnoresRetiredConnection() {
+ val runtime = createTestRuntime()
+ val endpoint = seedConnectedRuntime(runtime)
+
+ runtime.applyNodeVoiceWakeWords(
+ endpointStableId = endpoint.stableId,
+ payloadJson = """{"triggers":[" stale claw "]}""",
+ isCurrentConnection = { false },
+ )
+
+ assertEquals(listOf("openclaw", "claude", "computer"), runtime.voiceWakeWords.value)
+ }
+
+ @Test
+ fun gatewaySwitchClearsWordsAndBlocksSaveUntilRefresh() {
+ val runtime = createTestRuntime()
+ val firstEndpoint = seedConnectedRuntime(runtime)
+ runtime.applyNodeVoiceWakeWords(
+ endpointStableId = firstEndpoint.stableId,
+ payloadJson = """{"triggers":["gateway a"]}""",
+ isCurrentConnection = { true },
+ )
+ assertEquals(listOf("gateway a"), runtime.voiceWakeWords.value)
+
+ val secondEndpoint = GatewayEndpoint.manual("127.0.0.2", 18789)
+ writeField(runtime, "connectedEndpoint", secondEndpoint)
+ invokeNoArg(runtime, "invalidateVoiceWakeWordsForGateway")
+ runtime.setVoiceWakeWords(listOf("stale overwrite"))
+
+ assertEquals(listOf("openclaw", "claude", "computer"), runtime.voiceWakeWords.value)
+ assertEquals("Connect to a Gateway to save wake words", runtime.voiceWakeWordsNoticeText.value)
+ }
+
+ @Test
+ fun capabilityRefreshTracksGatewayWakeWordReadiness() {
+ val app = RuntimeEnvironment.getApplication()
+ shadowOf(app).grantPermissions(Manifest.permission.RECORD_AUDIO)
+ val securePrefs =
+ app.getSharedPreferences(
+ "openclaw.node.voicewake.runtime.test.${UUID.randomUUID()}",
+ Context.MODE_PRIVATE,
+ )
+ val prefs = SecurePrefs(app, securePrefsOverride = securePrefs)
+ prefs.setVoiceWakeEnabled(true)
+ val runtime = NodeRuntime(app, prefs, mode = NodeRuntimeMode.ScreenshotFixture)
+ val endpoint = GatewayEndpoint.manual("127.0.0.1", 18789)
+ writeField(runtime, "connectedEndpoint", endpoint)
+
+ assertFalse(readField(runtime, "lastVoiceWakeCapabilityEnabled"))
+ writeField(runtime, "voiceWakeWordsGatewayStableId", endpoint.stableId)
+ readField(runtime, "scope").coroutineContext[Job]?.cancel()
+ invokeNoArg(runtime, "refreshVoiceWakeCapabilitySurfaceIfChanged")
+
+ assertTrue(readField(runtime, "lastVoiceWakeCapabilityEnabled"))
+ }
+
+ @Test
+ fun cameraAudioOwnershipBlocksVoiceNoteUntilRelease() {
+ val runtime = createTestRuntime()
+
+ assertEquals(true, runtime.setCameraAudioCaptureActive(true))
+ assertFalse(runtime.tryAcquireVoiceNoteMic())
+
+ assertEquals(true, runtime.setCameraAudioCaptureActive(false))
+ assertEquals(true, runtime.tryAcquireVoiceNoteMic())
+ runtime.releaseVoiceNoteMic()
+ }
+
+ private fun createTestRuntime(): NodeRuntime {
+ val app = RuntimeEnvironment.getApplication()
+ val securePrefs =
+ app.getSharedPreferences(
+ "openclaw.node.voicewake.runtime.test.${UUID.randomUUID()}",
+ Context.MODE_PRIVATE,
+ )
+ return NodeRuntime(app, SecurePrefs(app, securePrefsOverride = securePrefs))
+ }
+
+ private fun seedConnectedRuntime(runtime: NodeRuntime): GatewayEndpoint {
+ val endpoint = GatewayEndpoint.manual("127.0.0.1", 18789)
+ writeField(runtime, "connectedEndpoint", endpoint)
+ runtime.applyNodeVoiceWakeWords(
+ endpointStableId = endpoint.stableId,
+ payloadJson = """{"triggers":["openclaw","claude","computer"]}""",
+ isCurrentConnection = { true },
+ )
+ return endpoint
+ }
+
+ private fun invokeNoArg(
+ target: Any,
+ name: String,
+ ) {
+ val method = target.javaClass.getDeclaredMethod(name)
+ method.isAccessible = true
+ method.invoke(target)
+ }
+
+ private fun writeField(
+ target: Any,
+ name: String,
+ value: Any?,
+ ) {
+ var type: Class<*>? = target.javaClass
+ while (type != null) {
+ val field = runCatching { type.getDeclaredField(name) }.getOrNull()
+ if (field != null) {
+ field.isAccessible = true
+ field.set(target, value)
+ return
+ }
+ type = type.superclass
+ }
+ error("missing field $name")
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ private fun readField(
+ target: Any,
+ name: String,
+ ): T {
+ var type: Class<*>? = target.javaClass
+ while (type != null) {
+ val field = runCatching { type.getDeclaredField(name) }.getOrNull()
+ if (field != null) {
+ field.isAccessible = true
+ return field.get(target) as T
+ }
+ type = type.superclass
+ }
+ error("missing field $name")
+ }
+}
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/node/CameraHandlerTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/node/CameraHandlerTest.kt
index 212fc692370c..cf3891156146 100644
--- a/apps/android/app/src/test/java/ai/openclaw/app/node/CameraHandlerTest.kt
+++ b/apps/android/app/src/test/java/ai/openclaw/app/node/CameraHandlerTest.kt
@@ -76,6 +76,25 @@ class CameraHandlerTest {
assertEquals("MIC_PERMISSION_REQUIRED: grant Microphone permission", error.message)
}
+ @Test
+ fun clipWithAudioFailsBeforeCameraStartsWhenMicrophoneIsBusy() =
+ runBlocking {
+ val app = RuntimeEnvironment.getApplication()
+ val handler =
+ CameraHandler(
+ appContext = app,
+ camera = CameraCaptureManager(app),
+ setCameraAudioCaptureActive = { false },
+ showCameraHud = { _, _, _ -> },
+ invokeErrorFromThrowable = { "UNAVAILABLE" to (it.message ?: "camera failed") },
+ )
+
+ val result = handler.handleClip("""{"includeAudio":true}""")
+
+ assertFalse(result.ok)
+ assertEquals("MIC_BUSY", result.error?.code)
+ }
+
@Test
fun isCameraClipWithinPayloadLimit_allowsZeroAndLimit() {
assertTrue(isCameraClipWithinPayloadLimit(0L))
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/node/ConnectionManagerTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/node/ConnectionManagerTest.kt
index 46d202aad53c..982b2aa33896 100644
--- a/apps/android/app/src/test/java/ai/openclaw/app/node/ConnectionManagerTest.kt
+++ b/apps/android/app/src/test/java/ai/openclaw/app/node/ConnectionManagerTest.kt
@@ -538,6 +538,17 @@ class ConnectionManagerTest {
assertFalse(options.caps.contains("voiceWake"))
}
+ @Test
+ fun buildNodeConnectOptions_advertisesVoiceWakeOnlyWhenEnabledAndAvailable() {
+ val disabled = newManager(voiceWakeEnabled = false).buildNodeConnectOptions()
+ val unavailable = newManager(voiceWakeEnabled = true, voiceWakeAvailable = false).buildNodeConnectOptions()
+ val enabled = newManager(voiceWakeEnabled = true).buildNodeConnectOptions()
+
+ assertFalse(disabled.caps.contains(OpenClawCapability.VoiceWake.rawValue))
+ assertFalse(unavailable.caps.contains(OpenClawCapability.VoiceWake.rawValue))
+ assertTrue(enabled.caps.contains(OpenClawCapability.VoiceWake.rawValue))
+ }
+
@Test
fun buildNodeConnectOptions_advertisesDeviceAppsOnlyWhenUserOptedIn() {
val disabled = newManager(installedAppsSharingEnabled = false).buildNodeConnectOptions()
@@ -606,13 +617,21 @@ class ConnectionManagerTest {
callLogAvailable: Boolean = false,
photosAvailable: Boolean = false,
installedAppsSharingEnabled: Boolean = false,
+ voiceWakeEnabled: Boolean = false,
+ voiceWakeAvailable: Boolean = true,
): ConnectionManager {
val context = RuntimeEnvironment.getApplication()
+ context
+ .getSharedPreferences("openclaw.node", android.content.Context.MODE_PRIVATE)
+ .edit()
+ .clear()
+ .commit()
val prefs =
SecurePrefs(
context,
securePrefsOverride = context.getSharedPreferences("connection-manager-test", android.content.Context.MODE_PRIVATE),
)
+ prefs.setVoiceWakeEnabled(voiceWakeEnabled)
return ConnectionManager(
prefs = prefs,
@@ -626,6 +645,7 @@ class ConnectionManagerTest {
callLogAvailable = { callLogAvailable },
photosAvailable = { photosAvailable },
installedAppsSharingEnabled = { installedAppsSharingEnabled },
+ voiceWakeAvailable = { voiceWakeAvailable },
manualTls = { false },
)
}
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeCommandRegistryTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeCommandRegistryTest.kt
index 81f957d783e5..618f5a615428 100644
--- a/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeCommandRegistryTest.kt
+++ b/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeCommandRegistryTest.kt
@@ -40,6 +40,7 @@ class InvokeCommandRegistryTest {
OpenClawCapability.CallLog.rawValue,
OpenClawCapability.Motion.rawValue,
OpenClawCapability.Photos.rawValue,
+ OpenClawCapability.VoiceWake.rawValue,
)
private val coreCommands =
@@ -99,6 +100,7 @@ class InvokeCommandRegistryTest {
photosAvailable = true,
motionActivityAvailable = true,
motionPedometerAvailable = true,
+ voiceWakeEnabled = true,
),
)
@@ -273,6 +275,7 @@ class InvokeCommandRegistryTest {
motionPedometerAvailable: Boolean = false,
installedAppsSharingEnabled: Boolean = false,
debugBuild: Boolean = false,
+ voiceWakeEnabled: Boolean = false,
): NodeRuntimeFlags =
NodeRuntimeFlags(
cameraEnabled = cameraEnabled,
@@ -286,6 +289,7 @@ class InvokeCommandRegistryTest {
motionPedometerAvailable = motionPedometerAvailable,
installedAppsSharingEnabled = installedAppsSharingEnabled,
debugBuild = debugBuild,
+ voiceWakeEnabled = voiceWakeEnabled,
)
private fun assertContainsAll(
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeDispatcherTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeDispatcherTest.kt
index 34432fbac236..ae12cf28cf5c 100644
--- a/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeDispatcherTest.kt
+++ b/apps/android/app/src/test/java/ai/openclaw/app/node/InvokeDispatcherTest.kt
@@ -14,7 +14,6 @@ import ai.openclaw.app.protocol.OpenClawTalkCommand
import android.content.Context
import android.content.pm.PackageManager
import android.webkit.WebView
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
@@ -398,7 +397,7 @@ class InvokeDispatcherTest {
CameraHandler(
appContext = appContext,
camera = CameraCaptureManager(appContext),
- externalAudioCaptureActive = MutableStateFlow(false),
+ setCameraAudioCaptureActive = { true },
showCameraHud = { _, _, _ -> },
invokeErrorFromThrowable = { err -> "UNAVAILABLE" to (err.message ?: "camera failed") },
)
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/voice/VoiceWakeManagerTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/voice/VoiceWakeManagerTest.kt
new file mode 100644
index 000000000000..75d5118caba3
--- /dev/null
+++ b/apps/android/app/src/test/java/ai/openclaw/app/voice/VoiceWakeManagerTest.kt
@@ -0,0 +1,279 @@
+package ai.openclaw.app.voice
+
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.RuntimeEnvironment
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+@RunWith(RobolectricTestRunner::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class VoiceWakeManagerTest {
+ @Test
+ fun retiredRecognitionSessionDropsLateCallbacks() {
+ val events = mutableListOf()
+ val session = VoiceWakeRecognitionSession(events::add)
+
+ session.emit(VoiceWakeRecognitionEvent.Ready)
+ session.retire()
+ session.emit(VoiceWakeRecognitionEvent.Transcript("openclaw stale command", isFinal = true))
+
+ assertEquals(listOf(VoiceWakeRecognitionEvent.Ready), events)
+ }
+
+ @Test
+ fun enabledForegroundRecognizerDispatchesCommandAndRestarts() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ val commands = mutableListOf()
+ val manager =
+ manager(recognizer = recognizer) { match ->
+ commands += match
+ true
+ }
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ recognizer.emit(VoiceWakeRecognitionEvent.Ready)
+
+ assertTrue(manager.isListening.value)
+ assertEquals("Listening", manager.statusText.value)
+
+ recognizer.emit(VoiceWakeRecognitionEvent.Transcript("OpenClaw, show", isFinal = false))
+ runCurrent()
+ assertEquals(emptyList(), commands)
+
+ recognizer.emit(VoiceWakeRecognitionEvent.Transcript("OpenClaw, show status", isFinal = true))
+ runCurrent()
+
+ assertEquals(listOf(VoiceWakeMatch("OpenClaw", "show status")), commands)
+ assertEquals("show status", manager.lastTriggeredCommand.value)
+ assertEquals(1, recognizer.stopCount)
+
+ advanceUntilIdle()
+ assertEquals(2, recognizer.startCount)
+ }
+
+ @Test
+ fun suppressionStopsAndResumesRecognizer() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ manager.setSuppressed(VoiceWakeSuppressionReason.VoiceCapture, true)
+
+ assertEquals("Paused", manager.statusText.value)
+ assertEquals(1, recognizer.stopCount)
+
+ manager.setSuppressed(VoiceWakeSuppressionReason.VoiceCapture, false)
+ assertEquals(2, recognizer.startCount)
+ }
+
+ @Test
+ fun suppressionDoesNotHoldManagerLockWhileStoppingRecognizer() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer(callbackDuringStop = true)
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ manager.setSuppressed(VoiceWakeSuppressionReason.VoiceCapture, true)
+
+ assertTrue(recognizer.stopCallbackCompleted)
+ assertEquals("Paused", manager.statusText.value)
+ }
+
+ @Test
+ fun oneAudioOwnerCannotReleaseAnotherOwnersSuppression() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ manager.setSuppressed(VoiceWakeSuppressionReason.Camera, true)
+ manager.setSuppressed(VoiceWakeSuppressionReason.VoiceCapture, true)
+ manager.setSuppressed(VoiceWakeSuppressionReason.Camera, false)
+
+ assertEquals("Paused", manager.statusText.value)
+ assertEquals(1, recognizer.startCount)
+
+ manager.setSuppressed(VoiceWakeSuppressionReason.VoiceCapture, false)
+ assertEquals(2, recognizer.startCount)
+ }
+
+ @Test
+ fun staleSuppressionRevisionCannotReleaseNewAudioOwner() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ manager.setSuppressed(VoiceWakeSuppressionReason.Camera, true, revision = 2)
+ manager.setSuppressed(VoiceWakeSuppressionReason.Camera, false, revision = 1)
+
+ assertEquals("Paused", manager.statusText.value)
+ assertEquals(1, recognizer.startCount)
+ }
+
+ @Test
+ fun suppressionCancelsPendingCommandDispatch() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ var commandStarted = false
+ var commandCancelled = false
+ val manager =
+ manager(recognizer = recognizer) {
+ commandStarted = true
+ try {
+ awaitCancellation()
+ } finally {
+ commandCancelled = true
+ }
+ }
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ recognizer.emit(VoiceWakeRecognitionEvent.Transcript("openclaw show status", isFinal = true))
+ runCurrent()
+ assertTrue(commandStarted)
+
+ manager.setSuppressed(VoiceWakeSuppressionReason.VoiceNote, true)
+ runCurrent()
+
+ assertTrue(commandCancelled)
+ assertEquals("Paused", manager.statusText.value)
+ }
+
+ @Test
+ fun permissionRefreshStartsAfterGrant() =
+ runTest {
+ var permissionGranted = false
+ val recognizer = FakeVoiceWakeRecognizer()
+ val manager = manager(recognizer = recognizer, hasPermission = { permissionGranted })
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ assertEquals("Microphone permission required", manager.statusText.value)
+ assertEquals(0, recognizer.startCount)
+
+ permissionGranted = true
+ manager.refreshPermission()
+ assertEquals(1, recognizer.startCount)
+ }
+
+ @Test
+ fun unavailableRecognizerNeverStarts() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer(isAvailable = false)
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+
+ assertFalse(manager.isListening.value)
+ assertEquals("On-device speech recognition unavailable", manager.statusText.value)
+ assertEquals(0, recognizer.startCount)
+ }
+
+ @Test
+ fun permanentLanguageErrorDoesNotRetry() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ recognizer.emit(VoiceWakeRecognitionEvent.Error(android.speech.SpeechRecognizer.ERROR_LANGUAGE_UNAVAILABLE))
+ advanceUntilIdle()
+
+ assertEquals("On-device language model unavailable", manager.statusText.value)
+ assertEquals(1, recognizer.startCount)
+ }
+
+ @Test
+ fun quotaErrorUsesLongBackoff() =
+ runTest {
+ val recognizer = FakeVoiceWakeRecognizer()
+ val manager = manager(recognizer = recognizer)
+
+ manager.setForeground(true)
+ manager.setEnabled(true)
+ recognizer.emit(VoiceWakeRecognitionEvent.Error(android.speech.SpeechRecognizer.ERROR_TOO_MANY_REQUESTS))
+
+ advanceTimeBy(14_999)
+ runCurrent()
+ assertEquals(1, recognizer.startCount)
+
+ advanceTimeBy(1)
+ runCurrent()
+ assertEquals(2, recognizer.startCount)
+ }
+
+ private fun kotlinx.coroutines.test.TestScope.manager(
+ recognizer: FakeVoiceWakeRecognizer,
+ hasPermission: () -> Boolean = { true },
+ onCommand: suspend (VoiceWakeMatch) -> Boolean = { true },
+ ): VoiceWakeManager =
+ VoiceWakeManager(
+ context = RuntimeEnvironment.getApplication(),
+ scope = this,
+ recognizer = recognizer,
+ initialTriggerWords = listOf("openclaw"),
+ onCommand = onCommand,
+ restartDelayMs = 1,
+ hasRecordAudioPermission = hasPermission,
+ )
+
+ private class FakeVoiceWakeRecognizer(
+ override val isAvailable: Boolean = true,
+ private val callbackDuringStop: Boolean = false,
+ ) : VoiceWakeRecognizer {
+ var startCount = 0
+ var stopCount = 0
+ var destroyCount = 0
+ var stopCallbackCompleted = false
+ private var onEvent: ((VoiceWakeRecognitionEvent) -> Unit)? = null
+
+ override fun start(
+ operationId: Long,
+ onEvent: (VoiceWakeRecognitionEvent) -> Unit,
+ ) {
+ startCount += 1
+ this.onEvent = onEvent
+ }
+
+ override fun stop(operationId: Long) {
+ stopCount += 1
+ if (callbackDuringStop) {
+ val completed = CountDownLatch(1)
+ Thread {
+ onEvent?.invoke(VoiceWakeRecognitionEvent.Error(android.speech.SpeechRecognizer.ERROR_CLIENT))
+ completed.countDown()
+ }.start()
+ stopCallbackCompleted = completed.await(1, TimeUnit.SECONDS)
+ }
+ }
+
+ override fun destroy(operationId: Long) {
+ destroyCount += 1
+ }
+
+ fun emit(event: VoiceWakeRecognitionEvent) {
+ onEvent?.invoke(event)
+ }
+ }
+}
diff --git a/apps/android/app/src/test/java/ai/openclaw/app/voice/VoiceWakePreferencesTest.kt b/apps/android/app/src/test/java/ai/openclaw/app/voice/VoiceWakePreferencesTest.kt
new file mode 100644
index 000000000000..fd75a8c4e1eb
--- /dev/null
+++ b/apps/android/app/src/test/java/ai/openclaw/app/voice/VoiceWakePreferencesTest.kt
@@ -0,0 +1,60 @@
+package ai.openclaw.app.voice
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Test
+
+class VoiceWakePreferencesTest {
+ @Test
+ fun sanitizeTrimsDropsEmptyAndUsesDefaults() {
+ assertEquals(listOf("hello", "computer"), VoiceWakePreferences.sanitizeTriggerWords(listOf(" hello ", "", "computer")))
+ assertEquals(VoiceWakePreferences.defaultTriggerWords, VoiceWakePreferences.sanitizeTriggerWords(emptyList()))
+ }
+
+ @Test
+ fun sanitizePreservesPhrasePunctuationAndNewlines() {
+ assertEquals(
+ listOf("hey, openclaw", "line\nbreak"),
+ VoiceWakePreferences.sanitizeTriggerWords(listOf(" hey, openclaw ", "line\nbreak")),
+ )
+ }
+
+ @Test
+ fun matcherRequiresWordBoundariesAndCommand() {
+ assertNull(VoiceWakePhraseMatcher.match("reopenclaw show status", listOf("openclaw")))
+ assertNull(VoiceWakePhraseMatcher.match("openclaw", listOf("openclaw")))
+ assertNull(VoiceWakePhraseMatcher.match("tell openclaw show status", listOf("openclaw")))
+ assertEquals(
+ VoiceWakeMatch(trigger = "OpenClaw", command = "show status"),
+ VoiceWakePhraseMatcher.match("Hey OpenClaw, show status", listOf("openclaw")),
+ )
+ }
+
+ @Test
+ fun matcherUsesEarliestTrigger() {
+ assertEquals(
+ VoiceWakeMatch(trigger = "computer", command = "ask claude for status"),
+ VoiceWakePhraseMatcher.match("computer ask claude for status", listOf("claude", "computer")),
+ )
+ }
+
+ @Test
+ fun matcherSupportsScriptsWithoutWhitespaceWordBoundaries() {
+ assertEquals(
+ VoiceWakeMatch(trigger = "小龙虾", command = "天气怎么样"),
+ VoiceWakePhraseMatcher.match("小龙虾天气怎么样", listOf("小龙虾")),
+ )
+ assertEquals(
+ VoiceWakeMatch(trigger = "โอเพนคลอ", command = "สภาพอากาศ"),
+ VoiceWakePhraseMatcher.match("โอเพนคลอสภาพอากาศ", listOf("โอเพนคลอ")),
+ )
+ }
+
+ @Test
+ fun matcherNormalizesSpokenPunctuationAndWhitespace() {
+ assertEquals(
+ VoiceWakeMatch(trigger = "Hey OpenClaw", command = "show status"),
+ VoiceWakePhraseMatcher.match("Hey OpenClaw show status", listOf("hey,\nopenclaw")),
+ )
+ }
+}
diff --git a/docs/nodes/voicewake.md b/docs/nodes/voicewake.md
index 19504cf5d4ad..2bf246e337dc 100644
--- a/docs/nodes/voicewake.md
+++ b/docs/nodes/voicewake.md
@@ -10,7 +10,7 @@ Wake words are **one global list owned by the Gateway** — there are no per-nod
- **macOS**: local Voice Wake enable/disable toggle. Requires macOS 26+; see [Voice wake (macOS)](/platforms/mac/voicewake) for runtime/PTT details.
- **iOS**: local Voice Wake enable/disable toggle in Settings.
-- **Android**: does not implement Voice Wake. The Voice tab uses manual mic capture instead of wake-word triggers.
+- **Android**: local Voice Wake enable/disable toggle and wake-word editor in Settings → Voice. Requires Android on-device speech recognition.
## Storage
@@ -64,7 +64,7 @@ Both broadcast to every WebSocket client with read scope (macOS app, WebChat, an
- **macOS**: calls `voicewake.set`/`voicewake.get` and listens for `voicewake.changed` to stay in sync with other clients.
- **iOS**: calls `voicewake.set`/`voicewake.get` and listens for `voicewake.changed` to keep local wake-word detection responsive.
-- **Android**: does not advertise the `voiceWake` capability or consume wake-word updates.
+- **Android**: calls `voicewake.set`/`voicewake.get`, listens for `voicewake.changed`, and advertises `voiceWake` while enabled. Recognition stays on-device and foreground-only; it pauses while Talk, manual dictation, voice-note capture, or message speech owns audio.
## Related
diff --git a/scripts/android-screenshots.sh b/scripts/android-screenshots.sh
index b52cc7f361e2..0de2dd4818a5 100644
--- a/scripts/android-screenshots.sh
+++ b/scripts/android-screenshots.sh
@@ -37,7 +37,7 @@ KEEP_EMULATOR="${ANDROID_SCREENSHOT_KEEP_EMULATOR:-0}"
SKIP_BUILD=0
SKIP_INSTALL=0
DRY_RUN=0
-SCENES=(home chat voice settings gateway)
+SCENES=(home chat voice settings gateway voice-wake)
EMULATOR_PID=""
EMULATOR_LOG=""
STARTED_EMULATOR=0
@@ -455,6 +455,7 @@ scene_ready_text() {
chat) printf '%s\n' "Ready when you are" ;;
voice) printf '%s\n' "Ready to talk" ;;
settings) printf '%s\n' "OpenClaw mobile" ;;
+ voice-wake) printf '%s\n' "Wake listener" ;;
# Connected fixtures can push Add Gateway below the composed viewport, so
# wait for the gateway detail's always-visible subtitle instead.
gateway) printf '%s\n' "Connection between this phone and OpenClaw." ;;
diff --git a/scripts/protocol-event-coverage.allowlist.json b/scripts/protocol-event-coverage.allowlist.json
index c7f884338751..2f70050fbd42 100644
--- a/scripts/protocol-event-coverage.allowlist.json
+++ b/scripts/protocol-event-coverage.allowlist.json
@@ -38,7 +38,6 @@
"node.presence": "Node activity is reported by macOS nodes and consumed by gateway routing; Android has no presence reporter yet.",
"device.pair.requested": "Device pairing flows poll via device.pair.* methods on Android.",
"device.pair.resolved": "Device pairing flows poll via device.pair.* methods on Android.",
- "voicewake.changed": "Android reads voicewake state on demand via voicewake.get; no push consumer yet.",
"voicewake.routing.changed": "Android reads voicewake state on demand via voicewake.get; no push consumer yet.",
"plugin.approval.requested": "Plugin approval prompts are not implemented on Android.",
"plugin.approval.resolved": "Plugin approval prompts are not implemented on Android.",
diff --git a/scripts/protocol-gen-kotlin.ts b/scripts/protocol-gen-kotlin.ts
index d1cdd5dd44a4..d4858f47edda 100644
--- a/scripts/protocol-gen-kotlin.ts
+++ b/scripts/protocol-gen-kotlin.ts
@@ -65,6 +65,7 @@ const androidEnums: EnumSpec[] = [
["Calendar", "calendar"],
["Motion", "motion"],
["CallLog", "callLog"],
+ ["VoiceWake", "voiceWake"],
]),
enumSpec("OpenClawCanvasCommand", "canvas.", [
["Present", "present"],