blob: aeb09356be9512db333459fb847a73990d06ba42 [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=''):
"""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:
logging.info('Emulating mouse: %s', mouse_props)
self._device_emulation_process = subprocess.Popen(
['evemu-device', mouse_props], stdout=subprocess.PIPE)
self._names['mouse'] = mouse_name
# Find all touch/mouse input devices.
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()
if not self._names[input_type]:
self._names[input_type] = utils.run(
name_cmd % input_type).stdout.strip()
logging.info('Found %s named %s at node %s', input_type,
self._names[input_type], 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_touch_setting(self, setting, value):
"""Set a given touch setting the given value.
@param setting: Name of touch setting, e.g. 'tapclick'.
@param value: True for enabled, False for disabled.
"""
cmd_value = 1 if value else 0
utils.run('%s --%s %d' % (self._INPUTCONTROL, setting, cmd_value))
logging.info('%s turned %s.', setting, 'on' if value else 'off')
def _set_australian_scrolling(self, value):
"""Set australian scrolling to the given value.
@param value: True for enabled, False for disabled.
"""
self._set_touch_setting('australian_scrolling', value)
def _set_tap_to_click(self, value):
"""Set tap-to-click to the given value.
@param value: True for enabled, False for disabled.
"""
self._set_touch_setting('tapclick', value)
def _set_tap_dragging(self, value):
"""Set tap dragging to the given value.
@param value: True for enabled, False for disabled.
"""
self._set_touch_setting('tapdrag', value)
def cleanup(self):
if self._device_emulation_process:
self._device_emulation_process.kill()
def _reload_page(self):
"""Reloads test page. Presuposes self._tab.
@raise: TestError if page is not reset.
"""
self._tab.Navigate(self._tab.url)
self._tab.WaitForDocumentReadyStateToBeComplete()
def _get_scroll_position(self):
"""Return current scroll position of page. Presuposes self._tab."""
return int(self._tab.EvaluateJavaScript('document.body.scrollTop'))
def _wait_for_default_scroll_position(self):
"""Wait for page to be the default scroll position.
@raise: TestError if page either does not move or does not stop moving.
"""
utils.poll_for_condition(
lambda: self._get_scroll_position() == self._DEFAULT_SCROLL,
exception=error.TestError('Page not set to default scroll!'))
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!'))