diff --git a/.idea/AndroidViewClient.iml b/.idea/AndroidViewClient.iml
index 65e243cd..a696e487 100644
--- a/.idea/AndroidViewClient.iml
+++ b/.idea/AndroidViewClient.iml
@@ -5,7 +5,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7be9824b..bfd101b1 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/setup.py b/setup.py
index fff3387d..ea93f582 100644
--- a/setup.py
+++ b/setup.py
@@ -22,5 +22,5 @@
classifiers=['Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License'],
- install_requires=['setuptools', 'requests', 'numpy', 'matplotlib', 'culebratester-client >= 2.0.12'],
+ install_requires=['setuptools', 'requests', 'numpy', 'matplotlib', 'culebratester-client >= 2.0.17'],
)
diff --git a/src/androidviewclient.egg-info/requires.txt b/src/androidviewclient.egg-info/requires.txt
index 367620af..622dcb6b 100644
--- a/src/androidviewclient.egg-info/requires.txt
+++ b/src/androidviewclient.egg-info/requires.txt
@@ -2,4 +2,4 @@ setuptools
requests
numpy
matplotlib
-culebratester-client
+culebratester-client>=2.0.17
diff --git a/src/com/dtmilano/android/uiautomator/uiautomatorhelper.py b/src/com/dtmilano/android/uiautomator/uiautomatorhelper.py
index 6c6d2eb5..3db0bde6 100644
--- a/src/com/dtmilano/android/uiautomator/uiautomatorhelper.py
+++ b/src/com/dtmilano/android/uiautomator/uiautomatorhelper.py
@@ -20,7 +20,7 @@
from __future__ import print_function
-__version__ = '20.4.3'
+__version__ = '20.4.4'
import json
import os
@@ -29,13 +29,14 @@
import subprocess
import sys
import threading
-
import time
from abc import ABC
+import culebratester_client
+from culebratester_client import Text
+
from com.dtmilano.android.adb.adbclient import AdbClient
from com.dtmilano.android.common import obtainAdbPath
-import culebratester_client
__author__ = 'diego'
@@ -122,10 +123,11 @@ def __init__(self, adbclient, adb=None, localport=9987, remoteport=9987, hostnam
print('⚠️ CulebraTester2 server should have been started and port redirected.', file=sys.stderr)
# TODO: localport should be in ApiClient configuration
self.api_instance = culebratester_client.DefaultApi(culebratester_client.ApiClient())
- self.device = UiAutomatorHelper.Device(self)
- self.target_context = UiAutomatorHelper.TargetContext(self)
- self.object_store = UiAutomatorHelper.ObjectStore(self)
- self.ui_device = UiAutomatorHelper.UiDevice(self)
+ self.device: UiAutomatorHelper.Device = UiAutomatorHelper.Device(self)
+ self.target_context: UiAutomatorHelper.TargetContext = UiAutomatorHelper.TargetContext(self)
+ self.object_store: UiAutomatorHelper.ObjectStore = UiAutomatorHelper.ObjectStore(self)
+ self.ui_device: UiAutomatorHelper.UiDevice = UiAutomatorHelper.UiDevice(self)
+ self.ui_object2: UiAutomatorHelper.UiObject2 = UiAutomatorHelper.UiObject2(self)
def __connectSession(self):
if DEBUG:
@@ -158,7 +160,8 @@ def __connectSession(self):
# lock.release()
return session
- def __whichAdb(self, adb):
+ @staticmethod
+ def __whichAdb(adb):
if adb:
if not os.access(adb, os.X_OK):
raise Exception('adb="%s" is not executable' % adb)
@@ -210,7 +213,8 @@ def __init__(self, uiAutomatorHelper) -> None:
super().__init__()
self.uiAutomatorHelper = uiAutomatorHelper
- def intersection(self, l1, l2):
+ @staticmethod
+ def intersection(l1, l2):
return list(set(l1) & set(l2))
def some(self, l1, l2):
@@ -240,7 +244,7 @@ def display_real_size(self):
def getDisplayRealSize(self):
"""
- :deprecated: use uiAutomatorHelper.device.get_display_real_size()
+ :deprecated: use uiAutomatorHelper.device.display_real_size()
:return: the display real size
"""
return self.api_instance.device_display_real_size_get()
@@ -278,6 +282,14 @@ class ObjectStore(ApiBase):
def __init__(self, uiAutomatorHelper) -> None:
super().__init__(uiAutomatorHelper)
+ def clear(self):
+ """
+ Clears all the objects.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :return: the status
+ """
+ return self.uiAutomatorHelper.api_instance.object_store_clear_get()
+
def list(self):
"""
List the objects.
@@ -286,6 +298,14 @@ def list(self):
"""
return self.uiAutomatorHelper.api_instance.object_store_list_get()
+ def remove(self, oid: int):
+ """
+ Removes an object.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :return: the status
+ """
+ return self.uiAutomatorHelper.api_instance.object_store_remove_get(oid)
+
#
# UiDevice
#
@@ -398,7 +418,8 @@ def take_screenshot(self, scale=1.0, quality=90, **kwargs):
:param kwargs:
:return:
"""
- return self.uiAutomatorHelper.api_instance.ui_device_screenshot_get(scale=scale, quality=quality, _preload_content=False, **kwargs)
+ return self.uiAutomatorHelper.api_instance.ui_device_screenshot_get(scale=scale, quality=quality,
+ _preload_content=False, **kwargs)
def wait_for_idle(self, **kwargs):
"""
@@ -410,6 +431,74 @@ def wait_for_idle(self, **kwargs):
"""
return self.uiAutomatorHelper.api_instance.ui_device_wait_for_idle_get(**kwargs)
+ #
+ # UiObject2
+ #
+ class UiObject2(ApiBase):
+ """
+ Inner UiObject2 class.
+
+ Notice that this class does not require an OID in its constructor.
+ """
+
+ def __init__(self, uiAutomatorHelper) -> None:
+ super().__init__(uiAutomatorHelper)
+
+ def clear(self, oid):
+ """
+ Clears the text content if this object is an editable field.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :param oid: the oid
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.api_instance.ui_object2_clear_get(oid=oid)
+
+ def click(self, oid):
+ """
+ Clicks on this object.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :param oid: the oid
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.api_instance.ui_object2_click_get(oid=oid)
+
+ def dump(self, oid):
+ """
+ Dumps the content of an object.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :param oid: the oid
+ :return: the content
+ """
+ return self.uiAutomatorHelper.api_instance.ui_object2_dump_get(oid=oid)
+
+ def get_text(self, oid):
+ """
+ Returns the text value for this object.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :param oid: the oid
+ :return: the text
+ """
+ return self.uiAutomatorHelper.api_instance.ui_object2_get_text_get(oid=oid)
+
+ def long_click(self, oid):
+ """
+ Performs a long click on this object.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :param oid: the oid
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.api_instance.ui_object2_long_click_get(oid=oid)
+
+ def set_text(self, oid, text):
+ """
+ Sets the text content if this object is an editable field.
+ :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
+ :param oid: the oid
+ :param text: the text
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.api_instance.ui_object2_set_text_post(oid=oid, body=Text(text))
+
def click(self, **kwargs):
"""
:deprecated:
@@ -494,10 +583,12 @@ def pressRecentApps(self):
"""
return self.__httpCommand('/UiDevice/pressRecentApps')
- def swipe(self, startX=-1, startY=-1, endX=-1, endY=-1, steps=10, segments=[], segmentSteps=5):
+ def swipe(self, startX=-1, startY=-1, endX=-1, endY=-1, steps=10, segments=None, segmentSteps=5):
"""
:deprecated:
"""
+ if segments is None:
+ segments = []
if startX != -1 and startY != -1:
params = {'startX': startX, 'startY': startY, 'endX': endX, 'endY': endY, 'steps': steps}
elif segments:
@@ -525,10 +616,21 @@ def waitForIdle(self, timeout):
# UiObject2
#
def setText(self, oid, text):
+ """
+ :deprecated:
+ """
body = {'text': text}
return self.api_instance.ui_object2_oid_set_text_post(body, oid)
def clickAndWait(self, uiObject2, eventCondition, timeout):
+ """
+
+ :deprecated:
+ :param uiObject2:
+ :param eventCondition:
+ :param timeout:
+ :return:
+ """
params = {'eventCondition': eventCondition, 'timeout': timeout}
return self.__httpCommand('/UiObject2/%d/clickAndWait' % uiObject2.oid, params)
@@ -536,8 +638,14 @@ def getText(self, oid):
return self.api_instance.ui_object2_oid_get_text_get(oid)
def isChecked(self, uiObject=None):
+ """
+
+ :deprecated:
+ :param uiObject:
+ :return:
+ """
# This path works for UiObject and UiObject2, so there's no need to handle both cases differently
- path = '/UiObject/%d/isChecked' % (uiObject.oid)
+ path = '/UiObject/%d/isChecked' % uiObject.oid
response = self.__httpCommand(path, None)
r = json.loads(response)
if r['status'] == 'OK':
@@ -571,6 +679,9 @@ def uiScrollable(self, path, params=None):
class UiObject:
+ """
+ A UiObject is a representation of a view.
+ """
def __init__(self, uiAutomatorHelper, oid, response):
self.uiAutomatorHelper = uiAutomatorHelper
self.oid = oid
@@ -596,32 +707,106 @@ def setText(self, text):
class UiObject2:
- def __init__(self, uiAutomatorHelper, oid):
+ """
+ A UiObject2 represents a UI element. Unlike UiObject, it is bound to a particular view instance and can become
+ stale.
+ """
+
+ def __init__(self, uiAutomatorHelper: UiAutomatorHelper, class_name: str, oid: int):
+ """
+ Constructor.
+
+ :param uiAutomatorHelper: the uiAutomatorHelper instance.
+ :param class_name: the class name of the UI object
+ :param oid: the object id
+ """
self.uiAutomatorHelper = uiAutomatorHelper
+ self.class_name = class_name
self.oid = oid
+ def clear(self):
+ """
+ Clears the text content if this object is an editable field.
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.ui_object2.clear(oid=self.oid)
+
def click(self):
- self.uiAutomatorHelper.click(oid=self.oid)
+ """
+ Clicks on this object.
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.ui_object2.click(oid=self.oid)
+
+ def dump(self):
+ """
+ Dumps the content of the object/
+ :return: the content of the object
+ """
+ return self.uiAutomatorHelper.ui_object2.dump(oid=self.oid)
+
+ def get_text(self):
+ """
+ Returns the text value for this object.
+ :return: the text
+ """
+ return self.uiAutomatorHelper.ui_object2.get_text(oid=self.oid)
+
+ def long_click(self):
+ """
+ Performs a long click on this object.
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.ui_object2.long_click(oid=self.oid)
+
+ def set_text(self, text):
+ """
+ Sets the text content if this object is an editable field.
+ :param text: the text
+ :return: the result of the operation
+ """
+ return self.uiAutomatorHelper.ui_object2.set_text(oid=self.oid, text=text)
def clickAndWait(self, eventCondition, timeout):
+ """
+ :deprecated:
+ :param eventCondition:
+ :param timeout:
+ :return:
+ """
self.uiAutomatorHelper.clickAndWait(uiObject2=self, eventCondition=eventCondition, timeout=timeout)
def isChecked(self):
"""
+ :deprecated:
:rtype: bool
"""
return self.uiAutomatorHelper.isChecked(uiObject=self)
def longClick(self):
+ """
+
+ :deprecated:
+ """
self.uiAutomatorHelper.longClick(oid=self.oid)
def getText(self):
+ """
+
+ :deprecated:
+ :return:
+ """
# NOTICE: even if this is an uiObject2 we are invoking the only "getText" method in UiAutomatorHelper
# passing the uiObject2 as uiObject
return self.uiAutomatorHelper.getText(uiObject=self)
def setText(self, text):
+ """
+
+ :deprecated:
+ :param text:
+ """
# NOTICE: even if this is an uiObject2 we are invoking the only "setText" method in UiAutomatorHelper
# passing the uiObject2 as uiObject
self.uiAutomatorHelper.setText(uiObject=self, text=text)