Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2601)

Unified Diff: experimental/telemetry_mini/telemetry_mini.py

Issue 2996123002: [telemetry_mini] Add AndroidActions class (Closed)
Patch Set: explain **kwargs Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « experimental/telemetry_mini/android_go_stories.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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."""
« no previous file with comments | « experimental/telemetry_mini/android_go_stories.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698