blob: 2b494b423e1c61cd525a69371d0550882a6db8e6 [file] [log] [blame]
# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from collections import defaultdict
import logging
import subprocess
from autotest_lib.client.bin import test
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
class touch_playback_test_base(test.test):
"""Base class for touch tests involving playback."""
version = 1
_PLAYBACK_COMMAND = 'evemu-play --insert-slot0 %s < %s'
_INPUTCONTROL = '/opt/google/input/inputcontrol'
_TOUCH_TYPES = ['touchpad', 'touchscreen', 'mouse']
_DEFAULT_SCROLL = 5000
@property
def _has_touchpad(self):
"""True if device under test has a touchpad; else False."""
return self._has_inputs['touchpad']
@property
def _has_touchscreen(self):
"""True if device under test has a touchscreen; else False."""
return self._has_inputs['touchscreen']
@property
def _has_mouse(self):
"""True if device under test has or emulates a USB mouse; else False."""
return self._has_inputs['mouse']
def warmup(self, mouse_props=None, mouse_name=None):
"""Determine the nodes of all present touch devices, if any.
Use inputcontrol command to get the touch ids and xinput to get the
corresponding node numbers. These numbers are used for playback.
Emulate a USB mouse if a property file is provided.
@param mouse_props: property file for a mouse to emulate. Created
using 'evemu-describe /dev/input/X'.
@param mouse_name: name of expected mouse.
"""
name_cmd = '%s --names -t %s' % (self._INPUTCONTROL, '%s')
type_cmd = name_cmd + ' | grep "%s" | cut -d : -f 1'
node_cmd = ('DISPLAY=:0 XAUTHORITY=/home/chronos/.Xauthority '
'xinput list-props %s '
'| grep dev/input | cut -d \'"\' -f 2')
self._has_inputs = defaultdict(bool)
self._nodes = defaultdict(str)
self._names = defaultdict(str)
self._device_emulation_process = None
# Emulate mouse if property file was provided.
if mouse_props:
self._device_emulation_process = subprocess.Popen(
['evemu-device', mouse_props], stdout=subprocess.PIPE)
self._names['mouse'] = mouse_name
for input_type in self._TOUCH_TYPES:
id_num = utils.run(type_cmd % (
input_type, self._names[input_type])).stdout.strip()
if id_num:
self._has_inputs[input_type] = True
self._nodes[input_type] = utils.run(
node_cmd % id_num).stdout.strip()
name = utils.run(name_cmd % input_type).stdout.strip()
logging.info('Found %s named %s at node %s', input_type,
name, self._nodes[input_type])
logging.info('This DUT has the following input devices:')
logging.info(
utils.run('%s --names' % self._INPUTCONTROL).stdout.strip())
def _playback(self, filepath, touch_type='touchpad'):
"""Playback a given set of touch movements.
@param filepath: path to the movements file on the DUT.
@param touch_type: name of device type; 'touchpad' by default. String
must be in self._TOUCH_TYPES list.
"""
assert(touch_type in self._TOUCH_TYPES)
node = self._nodes[touch_type]
logging.info('Playing back finger-movement on %s, file=%s.', node,
filepath)
utils.run(self._PLAYBACK_COMMAND % (node, filepath))
def _set_australian_scrolling(self, value):
"""Set australian scrolling to the given value.
@param value: True for enabled, False for disabled.
"""
cmd_value = 1 if value else 0
utils.run('%s --australian_scrolling %d' % (self._INPUTCONTROL,
cmd_value))
logging.info('Australian scrolling turned %s.',
'on' if value else 'off')
def cleanup(self):
if self._device_emulation_process:
self._device_emulation_process.kill()
def _get_scroll_position(self):
"""Return current scroll position of page. Presuposes self._tab."""
return int(self._tab.EvaluateJavaScript('document.body.scrollTop'))
def _reset_scroll_position(self):
"""Reset page position to default. Presuposes self._tab.
@raise: TestError if page is not reset.
"""
self._tab.ExecuteJavaScript('window.scrollTo(0, %d)'
% self._DEFAULT_SCROLL)
utils.poll_for_condition(
lambda: self._get_scroll_position() == self._DEFAULT_SCROLL,
exception=error.TestError('Default scroll was not set!'))
def _wait_for_scroll_position_to_settle(self):
"""Wait for page to move and then stop moving.
@raise: TestError if page either does not move or does not stop moving.
"""
# Wait until page starts moving.
utils.poll_for_condition(
lambda: self._get_scroll_position() != self._DEFAULT_SCROLL,
exception=error.TestError('No scrolling occurred!'))
# Wait until page has stopped moving.
self._previous = self._DEFAULT_SCROLL
def _movement_stopped():
current = self._get_scroll_position()
result = current == self._previous
self._previous = current
return result
utils.poll_for_condition(
lambda: _movement_stopped(), sleep_interval=1,
exception=error.TestError('Page did not stop moving!'))