| Index: experimental/telemetry_mini/telemetry_mini.py
|
| diff --git a/experimental/telemetry_mini/telemetry_mini.py b/experimental/telemetry_mini/telemetry_mini.py
|
| index 7685a76e0e7e881a8ae29c055e09cf2ccccf358a..7d244aa3bdffbb61e3cabb893fcd483cb174f8c9 100644
|
| --- a/experimental/telemetry_mini/telemetry_mini.py
|
| +++ b/experimental/telemetry_mini/telemetry_mini.py
|
| @@ -30,6 +30,8 @@ import websocket # pylint: disable=import-error
|
| from xml.etree import ElementTree as element_tree
|
|
|
|
|
| +KEYCODE_BACK = 4
|
| +
|
| # Parse rectangle bounds given as: '[left,top][right,bottom]'.
|
| RE_BOUNDS = re.compile(
|
| r'\[(?P<left>\d+),(?P<top>\d+)\]\[(?P<right>\d+),(?P<bottom>\d+)\]')
|
| @@ -142,7 +144,7 @@ class AdbMini(object):
|
| return result
|
|
|
| @RetryOn(AdbCommandError)
|
| - def GetUiDump(self):
|
| + def GetUiScreenDump(self):
|
| """Return the root XML node with screen captured from the device."""
|
| self.RunShellCommand('rm', '-f', UI_DUMP_TEMP)
|
| output = self.RunShellCommand('uiautomator', 'dump', UI_DUMP_TEMP).strip()
|
| @@ -158,22 +160,80 @@ class AdbMini(object):
|
| return element_tree.parse(f.name)
|
|
|
| @RetryOn(LookupError)
|
| - def FindUiNode(self, attr_values):
|
| - """Find a UI node on screen capture, retrying if not yet visible."""
|
| - root = self.GetUiDump()
|
| + def FindUiElement(self, attr_values):
|
| + """Find a UI element on screen capture, retrying if not yet visible."""
|
| + root = self.GetUiScreenDump()
|
| for node in root.iter():
|
| if all(node.get(k) == v for k, v in attr_values):
|
| return node
|
| - raise LookupError('Specified UI node not found')
|
| + raise LookupError('Specified UI element not found')
|
|
|
| - def TapUiNode(self, *args, **kwargs):
|
| - node = self.FindUiNode(*args, **kwargs)
|
| + def TapUiElement(self, *args, **kwargs):
|
| + node = self.FindUiElement(*args, **kwargs)
|
| m = RE_BOUNDS.match(node.get('bounds'))
|
| left, top, right, bottom = (int(v) for v in m.groups())
|
| x, y = (left + right) / 2, (top + bottom) / 2
|
| self.RunShellCommand('input', 'tap', str(x), str(y))
|
|
|
|
|
| +def _UserAction(f):
|
| + """Decorator to add repeat, and action_delay options to user action methods.
|
| +
|
| + Note: The values (or their defaults) supplied for these extra options will
|
| + also be passed down to the decorated method. It's thus advisable to collect
|
| + them in a catch-all **kwargs, even if just to discard them immediately.
|
| +
|
| + This is a workaround for https://github.com/PyCQA/pylint/issues/258 in which
|
| + decorators confuse pylint and trigger spurious 'unexpected-keyword-arg'
|
| + warnings on method calls that use the extra options.
|
| + """
|
| + @functools.wraps(f)
|
| + def Wrapper(self, *args, **kwargs):
|
| + repeat = kwargs.setdefault('repeat', 1)
|
| + action_delay = kwargs.setdefault('action_delay', None)
|
| + for _ in xrange(repeat):
|
| + f(self, *args, **kwargs)
|
| + self.Idle(action_delay)
|
| + return Wrapper
|
| +
|
| +
|
| +class AndroidActions(object):
|
| + def __init__(self, device, user_action_delay=1):
|
| + self.device = device
|
| + self.user_action_delay = user_action_delay
|
| +
|
| + def Idle(self, duration=None):
|
| + if duration is None:
|
| + duration = self.user_action_delay
|
| + if duration:
|
| + time.sleep(duration)
|
| +
|
| + @_UserAction
|
| + def GoBack(self, **kwargs):
|
| + del kwargs
|
| + self.device.RunShellCommand('input', 'keyevent', str(KEYCODE_BACK))
|
| +
|
| + @_UserAction
|
| + def StartActivity(
|
| + self, data_uri, action='android.intent.action.VIEW', **kwargs):
|
| + del kwargs
|
| + self.device.RunShellCommand('am', 'start', '-a', action, '-d', data_uri)
|
| +
|
| + @_UserAction
|
| + def TapUiElement(self, attr_values, **kwargs):
|
| + del kwargs
|
| + self.device.TapUiElement(attr_values)
|
| +
|
| + @_UserAction
|
| + def SwipeUp(self, **kwargs):
|
| + del kwargs
|
| + # Hardcoded values for 480x854 screen size; should work reasonably on
|
| + # other screen sizes.
|
| + # Command args: swipe <x1> <y1> <x2> <y2> [duration(ms)]
|
| + self.device.RunShellCommand(
|
| + 'input', 'swipe', '240', '568', '240', '284', '400')
|
| +
|
| +
|
| class DevToolsWebSocket(object):
|
| def __init__(self, url):
|
| self._url = url
|
| @@ -394,6 +454,7 @@ class UserStory(object):
|
| def __init__(self, browser):
|
| self.device = browser.device
|
| self.browser = browser
|
| + self.actions = AndroidActions(self.device)
|
|
|
| def GetExtraStoryApps(self):
|
| """Sequence of AndroidApp's, other than the browser, used in the story."""
|
|
|