diff --git a/Makefile b/Makefile index 596ae4a..6e87c87 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,9 @@ cov: --cov-report xml \ --cov-report term +sync: + cd uiautomator2/assets; ./sync.sh; cd - + build: poetry self add "poetry-dynamic-versioning[plugin]" cd uiautomator2/assets; ./sync.sh; cd - @@ -24,3 +27,4 @@ init: wget https://github.com/appium/appium/raw/master/packages/appium/sample-code/apps/ApiDemos-debug.apk; \ fi poetry run python -m adbutils -i ./ApiDemos-debug.apk + diff --git a/docs/2to3.md b/docs/2to3.md index be9afbe..c87f723 100644 --- a/docs/2to3.md +++ b/docs/2to3.md @@ -159,3 +159,7 @@ print(d.device_info) 'arch': 'arm64-v8a', 'version': 12} ``` + + ### app_current + - 2.x raise `OSError` if couldn't get focused app + - 3.x raise `DeviceError` if couldn't get focused app diff --git a/uiautomator2/__init__.py b/uiautomator2/__init__.py index af6d69f..83abe56 100644 --- a/uiautomator2/__init__.py +++ b/uiautomator2/__init__.py @@ -24,7 +24,7 @@ from uiautomator2 import xpath from uiautomator2._proto import HTTP_TIMEOUT, SCROLL_STEPS, Direction from uiautomator2._selector import Selector, UiObject -from uiautomator2.exceptions import AdbShellError, BaseException, HierarchyEmptyError, SessionBrokenError +from uiautomator2.exceptions import AdbShellError, BaseException, DeviceError, HierarchyEmptyError, SessionBrokenError from uiautomator2.settings import Settings from uiautomator2.swipe import SwipeExt from uiautomator2.utils import list2cmdline @@ -133,7 +133,7 @@ def shell(self, cmdargs: Union[str, List[str]], timeout=60) -> ShellResponse: raise AdbShellError(e) @property - def info(self): + def info(self) -> Dict[str, Any]: return self.jsonrpc.deviceInfo(http_timeout=10) @property @@ -442,14 +442,10 @@ def press(self, key: Union[int, str], meta=None): delete(or del), recent(recent apps), volume_up, volume_down, volume_mute, camera, power. """ - if key in ("home", "back", "enter", "volume_up", "volume_down", "volume_mute", "power", "wakeup"): - self.keyevent(key) - return if isinstance(key, int): return self.jsonrpc.pressKeyCode( key, meta) if meta else self.jsonrpc.pressKeyCode(key) else: - # FIXME: not working with Huiawei P50 return self.jsonrpc.pressKey(key) def screen_on(self): @@ -636,7 +632,7 @@ def app_current(self): dict(package, activity, pid?) Raises: - OSError + DeviceError For developer: Function reset_uiautomator need this function, so can't use jsonrpc here. @@ -644,7 +640,7 @@ def app_current(self): info = self.adb_device.app_current() if info: return dataclasses.asdict(info) - raise OSError("Couldn't get focused app") + raise DeviceError("Couldn't get focused app") def app_install(self, data: str): """ @@ -1022,6 +1018,29 @@ def swipe_ext(self) -> SwipeExt: class Device(_Device, _AppMixIn, _PluginMixIn, _InputMethodMixIn, _DeprecatedMixIn): """ Device object """ + @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 @@ -1061,8 +1080,6 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.close() - - def connect(serial: Union[str, adbutils.AdbDevice] = None) -> Device: """ Args: diff --git a/uiautomator2/assets/sync.sh b/uiautomator2/assets/sync.sh index c345ca2..95644d9 100755 --- a/uiautomator2/assets/sync.sh +++ b/uiautomator2/assets/sync.sh @@ -3,7 +3,7 @@ set -e -APK_VERSION="2.3.3" +APK_VERSION="2.3.6" # AGENT_VERSION="0.10.1" cd "$(dirname $0)" @@ -22,7 +22,7 @@ function download_apk(){ VERSION=$1 NAME=$2 URL="https://github.com/openatx/android-uiautomator-server/releases/download/$VERSION/$NAME" - echo "$URL" + echo ">> download $URL -> $NAME" curl -L "$URL" --output "$NAME" unzip -tq "$NAME" } @@ -33,4 +33,4 @@ function download_apk(){ download_apk "$APK_VERSION" "app-uiautomator.apk" download_apk "$APK_VERSION" "app-uiautomator-test.apk" -echo "apk_version: $APK_VERSION" > version.txt \ No newline at end of file +echo "apk_version: $APK_VERSION" > version.txt diff --git a/uiautomator2/core.py b/uiautomator2/core.py index b5e1381..9400fc0 100644 --- a/uiautomator2/core.py +++ b/uiautomator2/core.py @@ -128,11 +128,16 @@ def _jsonrpc_call(dev: adbutils.AdbDevice, method: str, params: Any, timeout: fl logger.debug("jsonrpc error: %s", data) code = data['error'].get('code') message = data['error'].get('message') + stacktrace = data['error'].get('data') if "UiAutomation not connected" in r.text: raise UiAutomationNotConnectedError("UiAutomation not connected") + if "android.os.DeadObjectException" in message: + # https://developer.android.com/reference/android/os/DeadObjectException + raise UiAutomationNotConnectedError("android.os.DeadObjectException") if "uiautomator.UiObjectNotFoundException" in message: raise UiObjectNotFoundError(code, message, params) - raise RPCUnknownError(f"Unknown RPC error: {code} {message}", params) + raise RPCUnknownError(f"Unknown RPC error: {code} {message}", params, stacktrace) + if "result" not in data: raise RPCInvalidError("Unknown RPC error: no result field")