Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecated set_fastinput_ime, update send_action() #980

Merged
merged 3 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,12 +553,24 @@ Below is a possible output:
### Clipboard
Get of set clipboard content

设置粘贴板内容或获取内容 (目前已知问题是9.0之后的后台程序无法获取剪贴板的内容)
设置粘贴板内容或获取内容

* clipboard/set_clipboard

```python
d.set_clipboard('text', 'label')
d.clipboard = 'hello-world'
# or
d.set_clipboard('hello-world', 'label')

```

Get clipboard content

> get clipboard requires IME(com.github.uiautomator/.AdbKeyboard) call `d.set_input_ime()` before using it.

```python

# get clipboard content
print(d.clipboard)
```

Expand Down Expand Up @@ -1270,22 +1282,23 @@ Refs: [Google uiautomator Configurator](https://developer.android.com/reference/
这种方法通常用于不知道控件的情况下的输入。第一步需要切换输入法,然后发送adb广播命令,具体使用方法如下

```python
d.set_fastinput_ime(True) # 切换成FastInputIME输入法
d.send_keys("你好123abcEFG") # adb广播输入
d.clear_text() # 清除输入框所有内容(Require android-uiautomator.apk version >= 1.0.7)
d.set_fastinput_ime(False) # 切换成正常的输入法
d.send_action("search") # 模拟输入法的搜索
d.send_keys("你好123abcEFG", clear=True) # adb广播输入

d.clear_text() # 清除输入框所有内容

d.send_action() # 根据输入框的需求,自动执行回车、搜索等指令, Added in version 3.1
# 也可以指定发送的输入法action, eg: d.send_action("search") 支持 go, search, send, next, done, previous
```

**send_action** 说明

该函数可以使用的参数有 `go search send next done previous`

_什么时候该使用这个函数呢?_
```python
print(d.current_ime()) # 获取当前输入法ID

```

有些时候在EditText中输入完内容之后,调用`press("search")` or `press("enter")`发现并没有什么反应。
这个时候就需要`send_action`函数了,这里用到了只有输入法才能用的[IME_ACTION_CODE](https://developer.android.com/reference/android/view/inputmethod/EditorInfo)。
`send_action`先broadcast命令发送给输入法操作`IME_ACTION_CODE`,由输入法完成后续跟EditText的通信。(原理我不太清楚,有了解的,提issue告诉我)
> 更多参考: [IME_ACTION_CODE](https://developer.android.com/reference/android/view/inputmethod/EditorInfo)

### Toast (2.2版本之后有添加回来)
Show Toast (好像有点bug)
Expand Down
10 changes: 9 additions & 1 deletion docs/2to3.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ XPath (d.xpath) methods
- remove when, run_watchers, watch_background, watch_stop, watch_clear, sleep_watch
- remove position method, usage like d.xpath(...).position(0.2, 0.2)

InputMethod
- deprecated wait_fastinput_ime
- deprecated set_fastinput_ime use set_input_ime instead

### Command remove
- Remove "uiautomator2 healthcheck"
- Remove "uiautomator2 identify"
Expand Down Expand Up @@ -169,6 +173,10 @@ print(d.device_info)
'version': 12}
```

### app_current
### app_current
- 2.x raise `OSError` if couldn't get focused app
- 3.x raise `DeviceError` if couldn't get focused app

### current_ime
- 2.x return (ime_method_name, bool), e.g. ("com.github.uiautomator/.FastInputIME", True)
- 3.x return ime_method_name, e.g. "com.github.uiautomator/.FastInputIME"
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ requests = "*"
lxml = "*"
adbutils = "^2.5.0"
retry = ">=0,<1"
Deprecated = "*"
Pillow = "*"

[tool.poetry.group.dev.dependencies]
Expand Down
151 changes: 9 additions & 142 deletions uiautomator2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from typing import Any, Dict, List, Optional, Union

import adbutils
from deprecated import deprecated
from lxml import etree
from retry import retry

Expand All @@ -24,10 +23,11 @@
from uiautomator2 import xpath
from uiautomator2._proto import HTTP_TIMEOUT, SCROLL_STEPS, Direction
from uiautomator2._selector import Selector, UiObject
from uiautomator2._input import InputMethodMixIn
from uiautomator2.exceptions import AdbShellError, BaseException, ConnectError, DeviceError, HierarchyEmptyError, SessionBrokenError
from uiautomator2.settings import Settings
from uiautomator2.swipe import SwipeExt
from uiautomator2.utils import list2cmdline
from uiautomator2.utils import list2cmdline, deprecated
from uiautomator2.watcher import WatchContext, Watcher
from uiautomator2.abstract import AbstractShell, AbstractUiautomatorServer, ShellResponse

Expand Down Expand Up @@ -540,8 +540,9 @@
return self(**kwargs).exists

@property
def clipboard(self):
return self.jsonrpc.getClipboard()
def clipboard(self) -> str:
return super().clipboard

Check warning on line 544 in uiautomator2/__init__.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/__init__.py#L544

Added line #L544 was not covered by tests
# return self.jsonrpc.getClipboard() # FIXME(ssx): bug

@clipboard.setter
def clipboard(self, text: str):
Expand Down Expand Up @@ -895,7 +896,7 @@
def click_post_delay(self, v: Union[int, float]):
self.settings['post_delay'] = v

@deprecated(version="2.0.0", reason="use d.toast.show(text, duration) instead")
@deprecated(reason="use d.toast.show(text, duration) instead")
def make_toast(self, text, duration=1.0):
""" Show toast
Args:
Expand All @@ -911,119 +912,6 @@
self.swipe(0.1, 0.9, 0.9, 0.1)


class _InputMethodMixIn(AbstractShell):
def set_fastinput_ime(self, enable: bool = True):
""" Enable of Disable FastInputIME """
fast_ime = 'com.github.uiautomator/.FastInputIME'
if enable:
self.shell(['ime', 'enable', fast_ime])
self.shell(['ime', 'set', fast_ime])
else:
self.shell(['ime', 'disable', fast_ime])

def send_keys(self, text: str, clear: bool = False):
"""
Args:
text (str): text to set
clear (bool): clear before set text

Raises:
EnvironmentError
"""
try:
self.wait_fastinput_ime()
btext = text.encode('utf-8')
base64text = base64.b64encode(btext).decode()
cmd = "ADB_SET_TEXT" if clear else "ADB_INPUT_TEXT"
self.shell(
['am', 'broadcast', '-a', cmd, '--es', 'text', base64text])
return True
except EnvironmentError:
warnings.warn(
"set FastInputIME failed. use \"d(focused=True).set_text instead\"",
Warning)
return self(focused=True).set_text(text)
# warnings.warn("set FastInputIME failed. use \"adb shell input text\" instead", Warning)
# self.shell(["input", "text", text.replace(" ", "%s")])

def send_action(self, code):
"""
Simulate input method edito code

Args:
code (str or int): input method editor code

Examples:
send_action("search"), send_action(3)

Refs:
https://developer.android.com/reference/android/view/inputmethod/EditorInfo
"""
self.wait_fastinput_ime()
__alias = {
"go": 2,
"search": 3,
"send": 4,
"next": 5,
"done": 6,
"previous": 7,
}
if isinstance(code, str):
code = __alias.get(code, code)
self.shell([
'am', 'broadcast', '-a', 'ADB_EDITOR_CODE', '--ei', 'code',
str(code)
])

def clear_text(self):
""" clear text
Raises:
EnvironmentError
"""
try:
self.wait_fastinput_ime()
self.shell(['am', 'broadcast', '-a', 'ADB_CLEAR_TEXT'])
except EnvironmentError:
# for Android simulator
self(focused=True).clear_text()

def wait_fastinput_ime(self, timeout=5.0):
""" wait FastInputIME is ready
Args:
timeout(float): maxium wait time

Raises:
EnvironmentError
"""
# TODO: 模拟器待兼容 eg. Genymotion, 海马玩, Mumu

deadline = time.time() + timeout
while time.time() < deadline:
ime_id, shown = self.current_ime()
if ime_id != "com.github.uiautomator/.FastInputIME":
self.set_fastinput_ime(True)
time.sleep(0.5)
continue
if shown:
return True
time.sleep(0.2)
raise EnvironmentError("FastInputIME started failed")

def current_ime(self):
""" Current input method
Returns:
(method_id(str), shown(bool)

Example output:
("com.github.uiautomator/.FastInputIME", True)
"""
_INPUT_METHOD_RE = re.compile(r'mCurMethodId=([-_./\w]+)')
dim, _ = self.shell(['dumpsys', 'input_method'])
m = _INPUT_METHOD_RE.search(dim)
method_id = None if not m else m.group(1)
shown = "mInputShown=true" in dim
return (method_id, shown)


class _PluginMixIn:
def watch_context(self, autostart: bool = True, builtin: bool = False) -> WatchContext:
Expand Down Expand Up @@ -1054,32 +942,11 @@
def swipe_ext(self) -> SwipeExt:
return SwipeExt(self)

class Device(_Device, _AppMixIn, _PluginMixIn, _InputMethodMixIn, _DeprecatedMixIn):

class Device(_Device, _AppMixIn, _PluginMixIn, InputMethodMixIn, _DeprecatedMixIn):

Check warning on line 946 in uiautomator2/__init__.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/__init__.py#L946

Added line #L946 was not covered by tests
""" Device object """
pass

@property
def info(self) -> Dict[str, Any]:
""" return device info, make sure currentPackageName is set

Return example:
{'currentPackageName': 'io.appium.android.apis',
'displayHeight': 720,
'displayRotation': 3,
'displaySizeDpX': 780,
'displaySizeDpY': 360,
'displayWidth': 1560,
'productName': 'ELE-AL00',
'screenOn': True,
'sdkInt': 29,
'naturalOrientation': False}
"""
_info = super().info
if _info.get('currentPackageName') is None:
try:
_info['currentPackageName'] = self.app_current().get('package')
except DeviceError:
pass
return _info

class Session(Device):
"""Session keeps watch the app status
Expand Down
Loading