feat: device.io.keyboard.hide via app_process#36
Conversation
Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/com/mobilenext/devicekit/DeviceKitServer.kt`:
- Around line 137-140: The BACK key injection in hideKeyboard currently ignores
UiAutomation.injectInputEvent(...) return values and always reports success.
Update hideKeyboard in DeviceKitServer to check both BACK down/up injections,
and if either returns false, propagate failure by returning false or an error
instead of true so device.io.keyboard.hide only succeeds when dismissal actually
happens.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 292f80fc-87fb-4a0f-a73b-e6c788e60ed2
📒 Files selected for processing (1)
app/src/main/java/com/mobilenext/devicekit/DeviceKitServer.kt
| val now = SystemClock.uptimeMillis() | ||
| uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0), true) | ||
| uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0), true) | ||
| return true |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does Android UiAutomation.injectInputEvent return false when an input event cannot be injected, and is that failure expected to be handled by callers?
💡 Result:
Yes, the method android.app.UiAutomation.injectInputEvent returns a boolean indicating whether the input event injection succeeded [1][2]. It explicitly returns false if the injection fails [3][4], which can occur due to factors such as remote exceptions [3][5] or other underlying system issues [6]. It is expected that callers handle this failure [7]. Because the return value provides a direct signal regarding the success or failure of the injection operation, robust implementations typically monitor this boolean to verify that the injected input reached the system [8][7]. If it returns false, it indicates that the event was not successfully injected, and callers should generally treat this as an actionable failure rather than assuming the operation was performed [7]. [1][3][2][7]
Citations:
- 1: https://developer.android.com/reference/kotlin/android/app/UiAutomation
- 2: https://developer.android.com/reference/android/app/UiAutomation
- 3: https://android.googlesource.com/platform/frameworks/base/+/HEAD/core/java/android/app/UiAutomation.java
- 4: https://android.googlesource.com/platform/frameworks/base/+/0e2d281/core/java/android/app/UiAutomation.java
- 5: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/UiAutomation.java
- 6: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/core/java/android/app/UiAutomationConnection.java
- 7: Drop automatic adb input swipe fallback from Android gesture swipes callstack/agent-device#690
- 8: https://android.googlesource.com/platform/frameworks/testing/+/61a929bd4642b9042bfb05b85340c1761ab90733/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/EventInjectionStrategy.java
Surface BACK injection failures in hideKeyboard. UiAutomation.injectInputEvent(...) can return false, but both calls are ignored and the method still returns true, so "device.io.keyboard.hide" may report dismissal when the IME is still visible. Return an error or false when either injection fails.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/com/mobilenext/devicekit/DeviceKitServer.kt` around lines
137 - 140, The BACK key injection in hideKeyboard currently ignores
UiAutomation.injectInputEvent(...) return values and always reports success.
Update hideKeyboard in DeviceKitServer to check both BACK down/up injections,
and if either returns false, propagate failure by returning false or an error
instead of true so device.io.keyboard.hide only succeeds when dismissal actually
happens.
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="app/src/main/java/com/mobilenext/devicekit/DeviceKitServer.kt">
<violation number="1" location="app/src/main/java/com/mobilenext/devicekit/DeviceKitServer.kt:138">
P2: `injectInputEvent` returns `false` when injection fails, but both calls ignore the result. The method unconditionally returns `true` once the IME window is detected, so callers may be told the keyboard was dismissed when it wasn't. Check the return values and propagate failure (return `false` or throw).</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0), true) | ||
| uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0), true) | ||
| return true |
There was a problem hiding this comment.
P2: injectInputEvent returns false when injection fails, but both calls ignore the result. The method unconditionally returns true once the IME window is detected, so callers may be told the keyboard was dismissed when it wasn't. Check the return values and propagate failure (return false or throw).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/com/mobilenext/devicekit/DeviceKitServer.kt, line 138:
<comment>`injectInputEvent` returns `false` when injection fails, but both calls ignore the result. The method unconditionally returns `true` once the IME window is detected, so callers may be told the keyboard was dismissed when it wasn't. Check the return values and propagate failure (return `false` or throw).</comment>
<file context>
@@ -120,6 +127,19 @@ class DeviceKitServer : Instrumentation() {
+ if (!imeShown) return false
+
+ val now = SystemClock.uptimeMillis()
+ uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0), true)
+ uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0), true)
+ return true
</file context>
| uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0), true) | |
| uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0), true) | |
| return true | |
| val downOk = uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0), true) | |
| val upOk = uiAutomation.injectInputEvent(KeyEvent(now, now, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0), true) | |
| return downOk && upOk |
Adds a
device.io.keyboard.hideJSON-RPC method.What
The soft keyboard is just an IME-type window.
hidedetects it (AccessibilityWindowInfo.TYPE_INPUT_METHOD) and, if present, injectsBACKviauiAutomationto dismiss it — the same approach uiautomator2/Appium use. Returns{"dismissed": <bool>};falsemeans no IME was up.Why not
device.io.keyboard.show/ InputMethodManagerInputMethodManager.showSoftInput/hideSoftInputFromWindowboth need aView/window token, which this headlessInstrumentation/app_processserver doesn't have.toggleSoftInputis deprecated since API 31 and is a no-op for a process with no served view (targetSdk 35). There's no reliable headless way to summon the IME — Android only raises it for a focused editable view in the target app, which happens when automation taps the field. So onlyhideis offered.Test plan
device.io.keyboard.hide→ keyboard dismisses, returnsdismissed: truedismissed: false, no BACK navigationSummary by cubic
Adds a
device.io.keyboard.hideJSON-RPC method to dismiss the soft keyboard in headless mode. It detects an IME window (AccessibilityWindowInfo.TYPE_INPUT_METHOD) and injects a BACK key viaUiAutomation, returning{ "dismissed": <bool> }(no-op if none shown).Written for commit d0b5f94. Summary will update on new commits.