Skip to content

Commit 9bcddeb

Browse files
authored
Merge pull request #1137 from openatx/copilot/fix-cbaf6a15-f3c2-43c5-b9a6-6e583e3f53c9
Hide input method automatically after send_keys completion
2 parents 38a5ec5 + 9c9568f commit 9bcddeb

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

tests/test_input.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
"""Tests for input method functionality"""
5+
6+
from unittest.mock import Mock, patch
7+
8+
import pytest
9+
10+
from uiautomator2._input import InputMethodMixIn
11+
from uiautomator2.exceptions import AdbBroadcastError
12+
13+
14+
class MockInputMethodMixIn(InputMethodMixIn):
15+
"""Mock implementation for testing"""
16+
17+
def __init__(self):
18+
self._adb_device = Mock()
19+
self._jsonrpc = Mock()
20+
self._broadcast_calls = []
21+
self._shell_calls = []
22+
self._current_ime = 'com.github.uiautomator/.AdbKeyboard'
23+
24+
@property
25+
def adb_device(self):
26+
return self._adb_device
27+
28+
@property
29+
def jsonrpc(self):
30+
return self._jsonrpc
31+
32+
def shell(self, args):
33+
"""Mock shell method"""
34+
self._shell_calls.append(args)
35+
result = Mock()
36+
result.output = self._current_ime
37+
return result
38+
39+
def _broadcast(self, action, extras=None):
40+
"""Mock broadcast method"""
41+
from uiautomator2._input import BORADCAST_RESULT_OK, BroadcastResult
42+
self._broadcast_calls.append((action, extras or {}))
43+
return BroadcastResult(BORADCAST_RESULT_OK, "success")
44+
45+
def __call__(self, **kwargs):
46+
"""Mock selector call for fallback"""
47+
if not hasattr(self, '_mock_element'):
48+
self._mock_element = Mock()
49+
self._mock_element.set_text = Mock(return_value=True)
50+
return self._mock_element
51+
52+
53+
def test_send_keys_hides_keyboard_when_using_custom_ime():
54+
"""Test that send_keys hides keyboard after successful input with custom IME"""
55+
mock_input = MockInputMethodMixIn()
56+
57+
# Test successful send_keys with custom IME
58+
result = mock_input.send_keys("hello world")
59+
60+
# Should return True for successful operation
61+
assert result is True
62+
63+
# Check broadcast calls - should have both input and hide calls
64+
broadcast_calls = mock_input._broadcast_calls
65+
assert len(broadcast_calls) >= 2
66+
67+
# First call should be for input
68+
assert broadcast_calls[0][0] == "ADB_KEYBOARD_INPUT_TEXT"
69+
assert "text" in broadcast_calls[0][1]
70+
71+
# Last call should be for hiding keyboard
72+
assert broadcast_calls[-1][0] == "ADB_KEYBOARD_HIDE"
73+
assert broadcast_calls[-1][1] == {}
74+
75+
76+
def test_send_keys_fallback_does_not_hide_keyboard():
77+
"""Test that send_keys fallback to set_text does not hide keyboard"""
78+
mock_input = MockInputMethodMixIn()
79+
80+
# Mock the _must_broadcast to raise AdbBroadcastError for input text
81+
def failing_must_broadcast(action, extras=None):
82+
if action == "ADB_KEYBOARD_INPUT_TEXT":
83+
raise AdbBroadcastError("Simulated failure for input text")
84+
# Should not reach here (keyboard hide) in fallback mode
85+
raise AdbBroadcastError(f"Unexpected broadcast call: {action}")
86+
87+
mock_input._must_broadcast = failing_must_broadcast
88+
89+
# Test fallback behavior
90+
with patch('warnings.warn'): # Suppress warning output
91+
result = mock_input.send_keys("hello world")
92+
93+
# Should return the result from set_text (True in our mock)
94+
assert result is True
95+
96+
# The element's set_text should have been called
97+
mock_element = mock_input(focused=True)
98+
assert mock_element.set_text.called
99+
mock_element.set_text.assert_called_with("hello world")
100+
101+
102+
def test_hide_keyboard_method():
103+
"""Test the hide_keyboard method directly"""
104+
mock_input = MockInputMethodMixIn()
105+
106+
mock_input.hide_keyboard()
107+
108+
# Should have made broadcast call for hiding
109+
broadcast_calls = mock_input._broadcast_calls
110+
assert len(broadcast_calls) >= 1
111+
assert broadcast_calls[-1][0] == "ADB_KEYBOARD_HIDE"
112+
assert broadcast_calls[-1][1] == {}

uiautomator2/_input.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ def send_keys(self, text: str):
111111
base64text = base64.b64encode(btext).decode()
112112
cmd = "ADB_KEYBOARD_INPUT_TEXT"
113113
self._must_broadcast(cmd, {"text": base64text})
114+
# Hide keyboard after successful input when using custom IME
115+
self._must_broadcast('ADB_KEYBOARD_HIDE')
114116
return True
115117
except AdbBroadcastError:
116118
warnings.warn(

0 commit comments

Comments
 (0)