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

Unified Diff: platform_tools/android/skp_gen/android_skp_capture.py

Issue 1483063006: Add android_skp_capture.py, JSON file for geniewidget (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years 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 | « no previous file | platform_tools/android/skp_gen/apps/geniewidget.json » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: platform_tools/android/skp_gen/android_skp_capture.py
diff --git a/platform_tools/android/skp_gen/android_skp_capture.py b/platform_tools/android/skp_gen/android_skp_capture.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b1a33ac1a50c22c1fe559db09dcee581d09e550
--- /dev/null
+++ b/platform_tools/android/skp_gen/android_skp_capture.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+
+# Copyright 2015 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+from __future__ import with_statement
+
+# Imports the monkeyrunner modules used by this program
+from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
+
+import ast
+import os
+import subprocess
+import time
+
+
+class DragAction:
+ """Action describing a touch drag."""
+ def __init__(self, start, end, duration, points):
+ self.start = start
+ self.end = end
+ self.duration = duration
+ self.points = points
+
+ def run(self, device):
+ """Perform the action."""
+ return device.drag(self.start, self.end, self.duration, self.points)
+
+
+class PressAction:
+ """Action describing a button press."""
+ def __init__(self, button, press_type):
+ self.button = button
+ self.press_type = press_type
+
+ def run(self, device):
+ """Perform the action."""
+ return device.press(self.button, self.press_type)
+
+
+def parse_action(action_dict):
+ """Parse a dict describing an action and return an Action object."""
+ if action_dict['type'] == 'drag':
+ return DragAction(tuple(action_dict['start']),
+ tuple(action_dict['end']),
rmistry 2015/12/02 20:49:18 What does it return if you do not specify tuple he
borenet 2015/12/03 18:14:48 A list. I'm not sure if monkeyrunner really cares
+ action_dict['duration'],
+ action_dict['points'])
+ elif action_dict['type'] == 'press':
+ return PressAction(action_dict['button'], action_dict['press_type'])
+ else:
+ raise TypeError('Unsupported action type: %s' % action_dict['type'])
+
+
+class App:
+ """Class which describes an app to launch and actions to run."""
+ def __init__(self, name, package, activity, actions):
+ self.name = name
+ self.package = package
+ self.activity = activity
+ self.run_component = '/'.join((self.package, self.activity))
rmistry 2015/12/02 20:49:18 [optional] I believe '%s/%s' % (self.package, self
borenet 2015/12/03 18:14:48 Done.
+ self.actions = [parse_action(a) for a in actions]
+
+ def launch(self, device):
+ """Launch the app on the device."""
+ device.startActivity(component=self.run_component)
+ time.sleep(3)
rmistry 2015/12/02 20:49:18 Make time to wait a parameter in the constructor.
borenet 2015/12/03 18:14:48 Done.
+
+ def kill(self):
+ """Kill the app."""
+ adb_shell('am force-stop %s' % self.package)
+
+
+def check_output(cmd):
+ """Convenience implementation of subprocess.check_output."""
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ if proc.wait() != 0:
+ raise Exception('Command failed: %s' % ' '.join(cmd))
+ return proc.communicate()[0]
+
+
+def adb_shell(cmd):
+ """Run the given ADB shell command and emulate the exit code."""
+ output = check_output(['adb', 'shell', cmd + '; echo $?']).strip()
+ split = output.splitlines()
rmistry 2015/12/02 20:49:18 Call these lines or tokens or output_tokens instea
borenet 2015/12/03 18:14:48 Done.
+ if split[-1] != '0':
+ raise Exception('ADB command failed: %s\n\nOutput:\n%s' % (cmd, output))
+ return '\n'.join(split[:-1])
+
+
+def remote_file_exists(filename):
+ """Return True if the given file exists on the device and False otherwise."""
+ try:
+ adb_shell('test -f %s' % filename)
+ return True
+ except Exception:
+ return False
+
+
+def capture_skp(filename, package, device):
rmistry 2015/12/02 20:49:18 call this skp_file instead? that is the argument y
borenet 2015/12/03 18:14:48 Done.
+ """Capture an SKP."""
+ remote_path = '/data/data/%s/cache/%s' % (package, os.path.basename(filename))
+ if remote_file_exists(remote_path):
+ adb_shell('rm %s' % remote_path)
rmistry 2015/12/02 20:49:18 I am assuming that trying to remove a file that do
borenet 2015/12/03 18:14:47 Yeah, so the problem with that is I'd want to actu
rmistry 2015/12/04 13:47:51 You would be saving an exists call in a few places
borenet 2015/12/04 14:41:44 Done.
+
+ adb_shell('setprop debug.hwui.capture_frame_as_skp %s' % remote_path)
+ try:
+ # Spin, wait for the SKP to be written.
+ timeout = 10 # Seconds
+ start = time.time()
+ device.drag((300, 300), (300, 350), 1, 10) # Dummy action to force a draw.
+ while not remote_file_exists(remote_path):
+ if time.time() - start > timeout:
+ raise Exception('Timed out waiting for SKP capture.')
+ time.sleep(1)
+
+ # Pull the SKP from the device.
+ cmd = ['adb', 'pull', remote_path, filename]
+ check_output(cmd)
+
+ finally:
+ adb_shell('setprop debug.hwui.capture_frame_as_skp ""')
+
+
+def load_app(filename):
+ """Load the JSON file describing an app and return an App instance."""
+ with open(filename) as f:
+ app_dict = ast.literal_eval(f.read())
+ return App(app_dict['name'],
+ app_dict['package'],
+ app_dict['activity'],
+ app_dict['actions'])
+
+
+def main():
+ """Capture SKPs for all apps."""
+ device = MonkeyRunner.waitForConnection()
+
+ # TODO(borenet): Kill all apps.
+ device.wake()
+ device.drag((600, 600), (10, 10), 0.2, 10)
+
+ apps_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'apps')
+ app_files = [os.path.join(apps_dir, app) for app in os.listdir(apps_dir)]
+
+ for app_file in app_files:
+ app = load_app(app_file)
+ print app.name
+ print ' Package %s' % app.package
+ app.launch(device)
+ print ' Launched activity %s' % app.activity
+
+ for action in app.actions:
+ print ' %s' % action.__class__.__name__
+ action.run(device)
+
+ time.sleep(1)
rmistry 2015/12/02 20:49:18 Could also either put this in the JSON or make it
borenet 2015/12/03 18:14:48 Done.
+ print ' Capturing SKP.'
+ skp_file = '%s.skp' % app.name
+ capture_skp(skp_file, app.package, device)
+ print ' Wrote SKP to %s' % skp_file
+ print ''
rmistry 2015/12/02 20:49:18 [optional] print with no arguments should also wor
borenet 2015/12/03 18:14:48 Done.
+ app.kill()
+
+
+if __name__ == '__main__':
+ main()
« no previous file with comments | « no previous file | platform_tools/android/skp_gen/apps/geniewidget.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698