feat(android): redesign chat settings UI#44894
Conversation
Merge endpoint and status into a single grouped card with icons. Split connect/disconnect into context-aware buttons.
Add text label under speaker toggle, balance layout with matching spacer column, and wrap status text in a colored pill.
Remove MESSAGE label and divider, let text field auto-size instead of fixed 92dp, and merge Detail/Attach into the bottom action row.
Rename role labels to You/OpenClaw/System, update streaming label to OpenClaw · Live, and remove the redundant SESSION row + Connected pill since the top bar and chip row already convey both.
Remove header bloat, merge Node info into a single Device card, group permissions into Media/Notifications/Data Access cards with internal dividers, and combine Screen+Debug into Preferences. Sections reduced from 9 to 6.
2bf6ba6 to
2f62eba
Compare
Greptile SummaryThis PR redesigns several Android UI screens — Key findings from the review:
Confidence Score: 3/5
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2bf6ba6cb2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| horizontalArrangement = Arrangement.spacedBy(8.dp), | ||
| ) { | ||
| Box(modifier = Modifier.weight(1f)) { | ||
| Box { |
There was a problem hiding this comment.
Keep a flexible slot in composer action row
This change removes the only flexible-width element in the composer toolbar by switching the thinking selector from Modifier.weight(1f) to a plain Box, while the same row now also contains fixed-size Attach/Refresh/Abort buttons plus a non-weighted Send button. In the chat sheet (which already has horizontal padding), this overflows on common ~360dp phone widths, causing trailing actions (typically Send) to be clipped/off-screen and difficult or impossible to tap; keep a weighted child (or split/wrap the controls) so the row can contract on narrow devices.
Useful? React with 👍 / 👎.
🔒 Aisle Security AnalysisWe found 2 potential security issue(s) in this PR:
1. 🟡 Fragile connection gating via substring match on remotely-influenced status text (client-side DoS)
DescriptionThe Connect button behavior is gated by a substring match on
Vulnerable code: if (statusText.contains("operator offline", ignoreCase = true)) {
validationText = null
viewModel.refreshGatewayConnection()
return@Button
}Provenance (remote influence):
This creates a practical client-side denial-of-service / lock-in vector when connecting to an attacker-controlled gateway (or when a gateway is compromised): the gateway can repeatedly close with a reason containing RecommendationDo not use user-facing status strings for control flow.
Example (sketch): enum class GatewayDisconnectCode { OPERATOR_OFFLINE, AUTH_FAILED, NETWORK_ERROR, UNKNOWN }
data class GatewayConnectionState(
val operatorConnected: Boolean,
val nodeConnected: Boolean,
val lastDisconnectCode: GatewayDisconnectCode? = null,
)
// UI
val state by viewModel.gatewayConnectionState.collectAsState()
Button(onClick = {
if (!state.operatorConnected && state.nodeConnected && state.lastDisconnectCode == GatewayDisconnectCode.OPERATOR_OFFLINE) {
viewModel.refreshGatewayConnection()
} else {
viewModel.connectManual()
}
}) { /* ... */ }Additionally, ensure disconnect reasons from the network are mapped to fixed codes (and not used directly as logic inputs). 2. 🔵 Chat message provenance spoofing: unknown roles rendered as “OpenClaw” (assistant)
DescriptionThe chat UI derives the displayed sender label from
Impact (security UX / anti-spoofing):
Vulnerable code: private fun roleLabel(role: String): String {
return when (role) {
"user" -> "You"
"system" -> "System"
else -> "OpenClaw"
}
}RecommendationUse an explicit allowlist of roles and do not treat unknown roles as the assistant.
Example fix: private fun roleLabel(role: String): String = when (role) {
"user" -> "You"
"assistant" -> "OpenClaw"
"system" -> "System"
"tool" -> "Tool"
"developer" -> "Developer"
else -> "Unknown" // or "Unknown (${role.take(24)})"
}And update Analyzed PR: #44894 at commit Last updated on: 2026-03-13T09:19:05Z |
(cherry picked from commit 7638052)
Summary
Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
Security Impact (required)
Yes, explain risk + mitigation:Repro + Verification
Environment
Steps
cd apps/android./gradlew app:compileDebugKotlinExpected
Actual
Evidence
Attach at least one:
Human Verification (required)
What you personally verified (not just CI), and how:
./gradlew app:compileDebugKotlinReview Conversations
Compatibility / Migration
Failure Recovery (if this breaks)
apps/android/app/src/main/java/ai/openclaw/app/ui/*Risks and Mitigations