Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
android_skp_capture.py
Go to the documentation of this file.
1#!/usr/bin/env python
2
3# Copyright 2015 Google Inc.
4#
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8
9from __future__ import print_function
10from __future__ import with_statement
11
12# Imports the monkeyrunner modules used by this program
13from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
14
15import ast
16import os
17import subprocess
18import time
19
20
21# Time to wait between performing UI actions and capturing the SKP.
22WAIT_FOR_SKP_CAPTURE = 1
23
24
26 """Action describing a touch drag."""
27 def __init__(self, start, end, duration, points):
28 self.start = start
29 self.end = end
30 self.duration = duration
31 self.points = points
32
33 def run(self, device):
34 """Perform the action."""
35 return device.drag(self.start, self.end, self.duration, self.points)
36
37
39 """Action describing a button press."""
40 def __init__(self, button, press_type):
41 self.button = button
42 self.press_type = press_type
43
44 def run(self, device):
45 """Perform the action."""
46 return device.press(self.button, self.press_type)
47
48
49def parse_action(action_dict):
50 """Parse a dict describing an action and return an Action object."""
51 if action_dict['type'] == 'drag':
52 return DragAction(tuple(action_dict['start']),
53 tuple(action_dict['end']),
54 action_dict['duration'],
55 action_dict['points'])
56 elif action_dict['type'] == 'press':
57 return PressAction(action_dict['button'], action_dict['press_type'])
58 else:
59 raise TypeError('Unsupported action type: %s' % action_dict['type'])
60
61
62class App:
63 """Class which describes an app to launch and actions to run."""
64 def __init__(self, name, package, activity, app_launch_delay, actions):
65 self.name = name
66 self.package = package
67 self.activity = activity
68 self.app_launch_delay = app_launch_delay
69 self.run_component = '%s/%s' % (self.package, self.activity)
70 self.actions = [parse_action(a) for a in actions]
71
72 def launch(self, device):
73 """Launch the app on the device."""
74 device.startActivity(component=self.run_component)
75 time.sleep(self.app_launch_delay)
76
77 def kill(self):
78 """Kill the app."""
79 adb_shell('am force-stop %s' % self.package)
80
81
82def check_output(cmd):
83 """Convenience implementation of subprocess.check_output."""
84 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
85 if proc.wait() != 0:
86 raise Exception('Command failed: %s' % ' '.join(cmd))
87 return proc.communicate()[0]
88
89
90def adb_shell(cmd):
91 """Run the given ADB shell command and emulate the exit code."""
92 output = check_output(['adb', 'shell', cmd + '; echo $?']).strip()
93 lines = output.splitlines()
94 if lines[-1] != '0':
95 raise Exception('ADB command failed: %s\n\nOutput:\n%s' % (cmd, output))
96 return '\n'.join(lines[:-1])
97
98
99def remote_file_exists(filename):
100 """Return True if the given file exists on the device and False otherwise."""
101 try:
102 adb_shell('test -f %s' % filename)
103 return True
104 except Exception:
105 return False
106
107
108def capture_skp(skp_file, package, device):
109 """Capture an SKP."""
110 remote_path = '/data/data/%s/cache/%s' % (package, os.path.basename(skp_file))
111 try:
112 adb_shell('rm %s' % remote_path)
113 except Exception:
114 if remote_file_exists(remote_path):
115 raise
116
117 adb_shell('setprop debug.hwui.capture_frame_as_skp %s' % remote_path)
118 try:
119 # Spin, wait for the SKP to be written.
120 timeout = 10 # Seconds
121 start = time.time()
122 device.drag((300, 300), (300, 350), 1, 10) # Arbitrary action to force a draw.
123 while not remote_file_exists(remote_path):
124 if time.time() - start > timeout:
125 raise Exception('Timed out waiting for SKP capture.')
126 time.sleep(1)
127
128 # Pull the SKP from the device.
129 cmd = ['adb', 'pull', remote_path, skp_file]
130 check_output(cmd)
131
132 finally:
133 adb_shell('setprop debug.hwui.capture_frame_as_skp ""')
134
135
136def load_app(filename):
137 """Load the JSON file describing an app and return an App instance."""
138 with open(filename) as f:
139 app_dict = ast.literal_eval(f.read())
140 return App(app_dict['name'],
141 app_dict['package'],
142 app_dict['activity'],
143 app_dict['app_launch_delay'],
144 app_dict['actions'])
145
146
147def main():
148 """Capture SKPs for all apps."""
149 device = MonkeyRunner.waitForConnection()
150
151 # TODO(borenet): Kill all apps.
152 device.wake()
153 device.drag((600, 600), (10, 10), 0.2, 10)
154
155 apps_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'apps')
156 app_files = [os.path.join(apps_dir, app) for app in os.listdir(apps_dir)]
157
158 for app_file in app_files:
159 app = load_app(app_file)
160 print(app.name)
161 print(' Package %s' % app.package)
162 app.launch(device)
163 print(' Launched activity %s' % app.activity)
164
165 for action in app.actions:
166 print(' %s' % action.__class__.__name__)
167 action.run(device)
168
169 time.sleep(WAIT_FOR_SKP_CAPTURE)
170 print(' Capturing SKP.')
171 skp_file = '%s.skp' % app.name
172 capture_skp(skp_file, app.package, device)
173 print(' Wrote SKP to %s' % skp_file)
174 print
175 app.kill()
176
177
178if __name__ == '__main__':
179 main()
void print(void *str)
Definition bridge.cpp:126
__init__(self, name, package, activity, app_launch_delay, actions)
__init__(self, start, end, duration, points)
__init__(self, button, press_type)
capture_skp(skp_file, package, device)
Definition main.py:1
Definition run.py:1