2016-01-21 17:11:53 +00:00
|
|
|
# Copyright 2014-2015 ARM Limited
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
#
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
2016-07-18 17:30:15 +01:00
|
|
|
import signal
|
2016-07-19 10:24:01 +01:00
|
|
|
from math import ceil
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
from wlauto import ExtensionLoader, Command, settings
|
|
|
|
from wlauto.common.resources import Executable
|
|
|
|
from wlauto.core.resource import NO_ONE
|
|
|
|
from wlauto.core.resolver import ResourceResolver
|
|
|
|
from wlauto.core.configuration import RunConfiguration
|
|
|
|
from wlauto.core.agenda import Agenda
|
2016-07-19 10:24:01 +01:00
|
|
|
from wlauto.utils.revent import ReventParser
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
|
2016-07-21 15:21:45 +01:00
|
|
|
class ReventCommand(Command):
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
# Validate command options
|
|
|
|
def validate_args(self, args):
|
|
|
|
if args.clear and not args.package:
|
|
|
|
print "Package must be specified if you want to clear cache\n"
|
|
|
|
self.parser.print_help()
|
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
# pylint: disable=W0201
|
|
|
|
def execute(self, args):
|
|
|
|
self.validate_args(args)
|
|
|
|
self.logger.info("Connecting to device...")
|
|
|
|
|
|
|
|
ext_loader = ExtensionLoader(packages=settings.extension_packages,
|
|
|
|
paths=settings.extension_paths)
|
|
|
|
|
|
|
|
# Setup config
|
|
|
|
self.config = RunConfiguration(ext_loader)
|
|
|
|
for filepath in settings.get_config_paths():
|
|
|
|
self.config.load_config(filepath)
|
|
|
|
self.config.set_agenda(Agenda())
|
|
|
|
self.config.finalize()
|
|
|
|
|
|
|
|
context = LightContext(self.config)
|
|
|
|
|
|
|
|
# Setup device
|
|
|
|
self.device = ext_loader.get_device(settings.device, **settings.device_config)
|
|
|
|
self.device.validate()
|
|
|
|
self.device.dynamic_modules = []
|
|
|
|
self.device.connect()
|
|
|
|
self.device.initialize(context)
|
|
|
|
|
|
|
|
host_binary = context.resolver.get(Executable(NO_ONE, self.device.abi, 'revent'))
|
2016-07-21 15:21:45 +01:00
|
|
|
self.target_binary = self.device.install_executable(host_binary)
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
self.run(args)
|
|
|
|
|
2016-07-21 15:21:45 +01:00
|
|
|
def run(self, args):
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
|
|
class RecordCommand(ReventCommand):
|
|
|
|
|
|
|
|
name = 'record'
|
|
|
|
description = '''Performs a revent recording
|
|
|
|
|
|
|
|
This command helps making revent recordings. It will automatically
|
|
|
|
deploy revent and even has the option of automatically opening apps.
|
|
|
|
|
|
|
|
Revent allows you to record raw inputs such as screen swipes or button presses.
|
|
|
|
This can be useful for recording inputs for workloads such as games that don't
|
|
|
|
have XML UI layouts that can be used with UIAutomator. As a drawback from this,
|
|
|
|
revent recordings are specific to the device type they were recorded on.
|
|
|
|
|
|
|
|
WA uses two parts to the names of revent recordings in the format,
|
|
|
|
{device_name}.{suffix}.revent.
|
|
|
|
|
|
|
|
- device_name can either be specified manually with the ``-d`` argument or
|
|
|
|
it can be automatically determined. On Android device it will be obtained
|
|
|
|
from ``build.prop``, on Linux devices it is obtained from ``/proc/device-tree/model``.
|
|
|
|
- suffix is used by WA to determine which part of the app execution the
|
|
|
|
recording is for, currently these are either ``setup`` or ``run``. This
|
|
|
|
should be specified with the ``-s`` argument.
|
|
|
|
'''
|
|
|
|
|
|
|
|
def initialize(self, context):
|
|
|
|
self.context = context
|
|
|
|
self.parser.add_argument('-d', '--device', help='The name of the device')
|
|
|
|
self.parser.add_argument('-s', '--suffix', help='The suffix of the revent file, e.g. ``setup``')
|
|
|
|
self.parser.add_argument('-o', '--output', help='Directory to save the recording in')
|
|
|
|
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
|
|
|
|
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
|
|
|
|
action="store_true")
|
|
|
|
|
2016-01-21 17:11:53 +00:00
|
|
|
def run(self, args):
|
|
|
|
if args.device:
|
2016-07-21 15:21:45 +01:00
|
|
|
device_name = args.device
|
2016-01-21 17:11:53 +00:00
|
|
|
else:
|
2016-07-21 15:21:45 +01:00
|
|
|
device_name = self.device.get_device_model()
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
if args.suffix:
|
|
|
|
args.suffix += "."
|
|
|
|
|
|
|
|
revent_file = self.device.path.join(self.device.working_directory,
|
2016-07-21 15:21:45 +01:00
|
|
|
'{}.{}revent'.format(device_name, args.suffix or ""))
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
if args.clear:
|
|
|
|
self.device.execute("pm clear {}".format(args.package))
|
|
|
|
|
|
|
|
if args.package:
|
|
|
|
self.logger.info("Starting {}".format(args.package))
|
|
|
|
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
|
|
|
|
|
|
|
|
self.logger.info("Press Enter when you are ready to record...")
|
|
|
|
raw_input("")
|
2016-07-18 17:30:15 +01:00
|
|
|
command = "{} record -s {}".format(self.target_binary, revent_file)
|
2016-01-21 17:11:53 +00:00
|
|
|
self.device.kick_off(command)
|
|
|
|
|
|
|
|
self.logger.info("Press Enter when you have finished recording...")
|
|
|
|
raw_input("")
|
2016-07-18 17:30:15 +01:00
|
|
|
self.device.killall("revent", signal.SIGTERM)
|
|
|
|
self.logger.info("Waiting for revent to finish")
|
|
|
|
while self.device.get_pids_of("revent"):
|
|
|
|
pass
|
2016-01-21 17:11:53 +00:00
|
|
|
self.logger.info("Pulling files from device")
|
|
|
|
self.device.pull_file(revent_file, args.output or os.getcwdu())
|
|
|
|
|
|
|
|
|
2016-07-21 15:21:45 +01:00
|
|
|
class ReplayCommand(ReventCommand):
|
2016-01-21 17:11:53 +00:00
|
|
|
|
|
|
|
name = 'replay'
|
|
|
|
description = '''Replay a revent recording
|
|
|
|
|
|
|
|
Revent allows you to record raw inputs such as screen swipes or button presses.
|
|
|
|
See ``wa show record`` to see how to make an revent recording.
|
|
|
|
'''
|
|
|
|
|
|
|
|
def initialize(self, context):
|
|
|
|
self.context = context
|
|
|
|
self.parser.add_argument('revent', help='The name of the file to replay')
|
|
|
|
self.parser.add_argument('-p', '--package', help='Package to launch before recording')
|
|
|
|
self.parser.add_argument('-C', '--clear', help='Clear app cache before launching it',
|
|
|
|
action="store_true")
|
|
|
|
|
|
|
|
# pylint: disable=W0201
|
|
|
|
def run(self, args):
|
|
|
|
self.logger.info("Pushing file to device")
|
|
|
|
self.device.push_file(args.revent, self.device.working_directory)
|
|
|
|
revent_file = self.device.path.join(self.device.working_directory, os.path.split(args.revent)[1])
|
|
|
|
|
|
|
|
if args.clear:
|
|
|
|
self.device.execute("pm clear {}".format(args.package))
|
|
|
|
|
|
|
|
if args.package:
|
|
|
|
self.logger.info("Starting {}".format(args.package))
|
|
|
|
self.device.execute('monkey -p {} -c android.intent.category.LAUNCHER 1'.format(args.package))
|
|
|
|
|
2016-07-18 17:30:15 +01:00
|
|
|
self.logger.info("Replaying recording")
|
2016-01-21 17:11:53 +00:00
|
|
|
command = "{} replay {}".format(self.target_binary, revent_file)
|
2016-07-19 10:24:01 +01:00
|
|
|
timeout = ceil(ReventParser.get_revent_duration(args.revent)) + 30
|
|
|
|
self.device.execute(command, timeout=timeout)
|
2016-01-21 17:11:53 +00:00
|
|
|
self.logger.info("Finished replay")
|
|
|
|
|
2016-01-27 16:40:41 +00:00
|
|
|
|
2016-01-21 17:11:53 +00:00
|
|
|
# Used to satisfy the API
|
|
|
|
class LightContext(object):
|
|
|
|
def __init__(self, config):
|
|
|
|
self.resolver = ResourceResolver(config)
|
|
|
|
self.resolver.load()
|