blob: 6fbd3f0a0885a134c04888b6a1673247ddcb2b54 [file] [log] [blame]
# Copyright 2015 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.
""" This is a module containing functions that allow the test suite to
determine the specifics of the gesture and execute them on the touchbot.
In essence, you use this class to go from a Test object to the robot
actually performing the correct gesture on the pad.
"""
import math
from threading import Thread
import colorama as color
import tests
from touchbot import Touchbot
STANDARD_FINGERTIP = '1round_9mm'
STANDARD_SECONDARY_FINGERTIP = '2round_9mm'
FAT_FINGERTIP = '1round_14mm'
FAT_SECONDARY_FINGERTIP = '2round_14mm'
NOISE_TESTING_FINGERTIP = '1round_12mm'
THREE_FINGER_FINGERTIP = 'three_fingers'
FOUR_FINGER_FINGERTIP = 'four_fingers'
FIVE_FINGER_FINGERTIP = 'five_fingers'
BUFFER_SIZE = 0.1
OVERSHOOT_DISTANCE = 0.05
LEFT = BUFFER_SIZE
OVER_LEFT = -OVERSHOOT_DISTANCE
RIGHT = 1.0 - BUFFER_SIZE
OVER_RIGHT = 1.0 + OVERSHOOT_DISTANCE
TOP = BUFFER_SIZE
OVER_TOP = -OVERSHOOT_DISTANCE
BOTTOM = 1.0 - BUFFER_SIZE
OVER_BOTTOM = 1.0 + OVERSHOOT_DISTANCE
CENTER = 0.5
LOCATION_COORDINATES = {
tests.GV.TL: (LEFT, TOP),
tests.GV.TR: (RIGHT, TOP),
tests.GV.BL: (LEFT, BOTTOM),
tests.GV.BR: (RIGHT, BOTTOM),
tests.GV.TS: (CENTER, TOP),
tests.GV.BS: (CENTER, BOTTOM),
tests.GV.LS: (LEFT, CENTER),
tests.GV.RS: (RIGHT, CENTER),
tests.GV.CENTER: (CENTER, CENTER),
}
LINE_DIRECTION_COORDINATES = {
tests.GV.LR: ((LEFT, CENTER), (RIGHT, CENTER)),
tests.GV.RL: ((RIGHT, CENTER), (LEFT, CENTER)),
tests.GV.TB: ((CENTER, TOP), (CENTER, BOTTOM)),
tests.GV.BT: ((CENTER, BOTTOM), (CENTER, TOP)),
tests.GV.BLTR: ((LEFT, BOTTOM), (RIGHT, TOP)),
tests.GV.BRTL: ((RIGHT, BOTTOM), (LEFT, TOP)),
tests.GV.TRBL: ((RIGHT, TOP), (LEFT, BOTTOM)),
tests.GV.TLBR: ((LEFT, TOP), (RIGHT, BOTTOM)),
tests.GV.CL: ((CENTER, CENTER), (OVER_LEFT, CENTER)),
tests.GV.CR: ((CENTER, CENTER), (OVER_RIGHT, CENTER)),
tests.GV.CT: ((CENTER, CENTER), (CENTER, OVER_TOP)),
tests.GV.CB: ((CENTER, CENTER), (CENTER, OVER_BOTTOM)),
tests.GV.CUL: ((CENTER, CENTER), (OVER_LEFT, OVER_TOP)),
tests.GV.CLL: ((CENTER, CENTER), (OVER_LEFT, OVER_BOTTOM)),
tests.GV.CLR: ((CENTER, CENTER), (OVER_RIGHT, OVER_BOTTOM)),
}
STATIONARY_FINGER_LOCATION = {
tests.GV.LR: LOCATION_COORDINATES[tests.GV.TS],
tests.GV.RL: LOCATION_COORDINATES[tests.GV.BS],
tests.GV.TB: LOCATION_COORDINATES[tests.GV.LS],
tests.GV.BT: LOCATION_COORDINATES[tests.GV.RS],
}
SPEEDS = {
tests.GV.NORMAL: Touchbot.SPEED_MEDIUM,
tests.GV.SLOW: Touchbot.SPEED_SLOW,
tests.GV.FAST: Touchbot.SPEED_FAST,
}
ANGLES = {
tests.GV.HORIZONTAL: 0,
tests.GV.VERTICAL: 90,
tests.GV.DIAGONAL: 45,
}
ONE_FINGERTIP_TAP_TESTS = [
tests.ONE_FINGER_TAP,
tests.REPEATED_TAPS,
tests.THREE_FINGER_TAP,
tests.FOUR_FINGER_TAP,
tests.FIVE_FINGER_TAP,
]
TAP_TEST_FINGERTIPS = {
tests.ONE_FINGER_TAP: STANDARD_FINGERTIP,
tests.REPEATED_TAPS: STANDARD_FINGERTIP,
tests.THREE_FINGER_TAP: THREE_FINGER_FINGERTIP,
tests.FOUR_FINGER_TAP: FOUR_FINGER_FINGERTIP,
tests.FIVE_FINGER_TAP: FIVE_FINGER_FINGERTIP,
}
SINGLE_FINGER_LINE_TESTS = [
tests.ONE_FINGER_TO_EDGE,
tests.ONE_FINGER_TRACKING,
tests.ONE_FINGER_TRACKING_FROM_CENTER,
tests.ONE_FINGER_SWIPE,
]
TWO_FINGER_LINE_TESTS = [
tests.TWO_FINGER_TRACKING,
tests.TWO_CLOSE_FINGERS_TRACKING,
tests.TWO_FAT_FINGERS_TRACKING,
tests.TWO_FINGER_SWIPE,
]
PHYSICAL_CLICK_TESTS = [
tests.ONE_FINGER_PHYSICAL_CLICK,
tests.TWO_FINGER_PHYSICAL_CLICK,
]
def _ComputePerpendicularAngle(start, end):
""" Compute the fingertip angle to be perpendicular to the
movement direction.
The robot's X/Y axes are not in the same direction as the touch device's,
they are flipped.
DUT x ----> Robot y ---->
y x
| |
| |
\/ \/
As a result the angle is computed in the DUT space, but then must have
its sign flipped before being used in any commands to the robot or
everything will be wrong since it's a clockwise angle instead of counter-
clockwise.
"""
x1, y1 = start
x2, y2 = end
dy = y2 - y1
dx = x2 - x1
return -1 * (math.degrees(math.atan2(y2 - y1, x2 - x1)) + 90)
def PerformCorrespondingGesture(test, variation_number, robot, device_spec):
variation = test.variations[variation_number]
fn = None
if test.name == tests.NOISE_STATIONARY:
fn = lambda: _PerformStationaryNoiseTest(variation, robot, device_spec)
elif test.name == tests.NOISE_LINE:
fn = lambda: _PerformLineNoiseTest(variation, robot, device_spec)
elif test.name in ONE_FINGERTIP_TAP_TESTS:
fingertip = robot.fingertips[TAP_TEST_FINGERTIPS[test.name]]
num_taps = 20 if test.name == tests.REPEATED_TAPS else 1
vertical_offset = 0
if test.name != tests.ONE_FINGER_TAP:
vertical_offset = robot.LARGE_FINGERTIP_VERTICAL_OFFSET
fn = lambda: _PerformOneFingertipTapTest(
variation, robot, device_spec, fingertip,
vertical_offset, num_taps)
elif test.name == tests.TWO_FINGER_TAP:
fn = lambda: _PerformTwoFingerTapTest(variation, robot, device_spec)
elif test.name in PHYSICAL_CLICK_TESTS:
fingertips = [robot.fingertips[STANDARD_FINGERTIP]]
if test.name == tests.TWO_FINGER_PHYSICAL_CLICK:
fingertips.append(robot.fingertips[STANDARD_SECONDARY_FINGERTIP])
fn = lambda: _PerformPhysicalClickTest(variation, robot, device_spec,
fingertips)
elif test.name == tests.DRUMROLL:
fn = lambda: _PerformDrumroll(variation, robot, device_spec)
elif test.name in SINGLE_FINGER_LINE_TESTS:
pause = 1 if test.name == tests.ONE_FINGER_TRACKING_FROM_CENTER else 0
is_swipe = (test.name == tests.ONE_FINGER_SWIPE)
fn = lambda: _PerformOneFingerLineTest(variation, robot, device_spec,
pause, is_swipe)
elif test.name in TWO_FINGER_LINE_TESTS:
spacing = 5
fingertips = [robot.fingertips[STANDARD_FINGERTIP],
robot.fingertips[STANDARD_SECONDARY_FINGERTIP]]
is_swipe = (test.name == tests.TWO_FINGER_SWIPE)
if test.name == tests.TWO_CLOSE_FINGERS_TRACKING:
spacing = 0
elif test.name == tests.TWO_FAT_FINGERS_TRACKING:
spacing = 10
fingertips = [robot.fingertips[FAT_FINGERTIP],
robot.fingertips[FAT_SECONDARY_FINGERTIP]]
fn = lambda: _PerformTwoFingerLineTest(variation, robot, device_spec,
fingertips, spacing, is_swipe)
elif test.name == tests.RESTING_FINGER_PLUS_2ND_FINGER_MOVE:
moving_fingertip = robot.fingertips[STANDARD_SECONDARY_FINGERTIP]
stationary_location = LOCATION_COORDINATES[tests.GV.BL]
fn = lambda: _PerformRestingFingerTest(variation, robot, device_spec,
moving_fingertip,
stationary_location)
elif test.name == tests.FAT_FINGER_MOVE_WITH_RESTING_FINGER:
moving_fingertip = robot.fingertips[FAT_SECONDARY_FINGERTIP]
direction, speed = variation
stationary_location = STATIONARY_FINGER_LOCATION[direction]
fn = lambda: _PerformRestingFingerTest(variation, robot, device_spec,
moving_fingertip,
stationary_location)
elif test.name == tests.PINCH_TO_ZOOM:
fn = lambda: _PerformPinchTest(variation, robot, device_spec)
elif test.name == tests.DRAG_THUMB_EDGE:
fn = lambda: _PerformThumbEdgeTest(variation, robot, device_spec)
elif test.name == tests.SQUARE_RESOLUTION:
fn = lambda: _PerformSquareResolutionTest(variation, robot, device_spec)
if fn is None:
print color.Fore.RED + 'Robot unable to perform gesture! Skipping...'
return None
return Thread(target=fn)
def _PerformStationaryNoiseTest(variation, robot, device_spec):
frequency, amplitude, waveform, location = variation
tap_position = LOCATION_COORDINATES[location]
fingertip = robot.fingertips[NOISE_TESTING_FINGERTIP]
robot.Tap(device_spec, [fingertip], tap_position, touch_time_s=4)
def _PerformLineNoiseTest(variation, robot, device_spec):
frequency, amplitude, waveform, direction = variation
start, end = LINE_DIRECTION_COORDINATES[direction]
fingertip = robot.fingertips[NOISE_TESTING_FINGERTIP]
robot.Line(device_spec, [fingertip], start, end, pause_s=1, swipe=False)
def _PerformOneFingertipTapTest(variation, robot, device_spec, fingertip,
vertical_offset, num_taps):
location, = variation
tap_position = LOCATION_COORDINATES[location]
robot.Tap(device_spec, [fingertip], tap_position,
vertical_offset=vertical_offset, num_taps=num_taps)
def _PerformTwoFingerTapTest(variation, robot, device_spec):
angle, = variation
fingertip1 = robot.fingertips[STANDARD_FINGERTIP]
fingertip2 = robot.fingertips[STANDARD_SECONDARY_FINGERTIP]
fingertips = [fingertip1, fingertip2]
robot.Tap(device_spec, fingertips, (CENTER, CENTER), angle=ANGLES[angle])
def _PerformOneFingerLineTest(variation, robot, device_spec, pause_time_s,
is_swipe):
direction, speed = variation
start, end = LINE_DIRECTION_COORDINATES[direction]
fingertip = robot.fingertips[STANDARD_FINGERTIP]
robot.PushSpeed(SPEEDS[speed])
robot.Line(device_spec, [fingertip], start, end, pause_s=pause_time_s,
swipe=is_swipe)
robot.PopSpeed()
def _PerformTwoFingerLineTest(variation, robot, device_spec, fingertips,
spacing_mm, is_swipe):
direction, speed = variation
start, end = LINE_DIRECTION_COORDINATES[direction]
angle = _ComputePerpendicularAngle(start, end)
robot.PushSpeed(SPEEDS[speed])
robot.Line(device_spec, fingertips, start, end, fingertip_spacing=spacing_mm,
fingertip_angle=angle, swipe=is_swipe)
robot.PopSpeed()
def _PerformRestingFingerTest(variation, robot, device_spec, moving_fingertip,
stationary_location):
direction, speed = variation
start, end = LINE_DIRECTION_COORDINATES[direction]
stationary_fingertip = robot.fingertips[STANDARD_FINGERTIP]
robot.PushSpeed(SPEEDS[speed])
robot.LineWithStationaryFinger(device_spec, stationary_fingertip,
moving_fingertip, start, end,
stationary_location)
robot.PopSpeed()
def _PerformPinchTest(variation, robot, device_spec):
direction, angle = variation
min_spread = 15
max_spread = min(device_spec.Height(), device_spec.Width(),
robot.MAX_FINGER_DISTANCE)
if direction == tests.GV.ZOOM_OUT:
start_distance, end_distance = max_spread, min_spread
else:
start_distance, end_distance = min_spread, max_spread
fingertips = [robot.fingertips[STANDARD_FINGERTIP],
robot.fingertips[STANDARD_SECONDARY_FINGERTIP]]
robot.PushSpeed(SPEEDS[tests.GV.NORMAL])
robot.Pinch(device_spec, fingertips, (CENTER, CENTER), ANGLES[angle],
start_distance, end_distance)
robot.PopSpeed()
def _PerformThumbEdgeTest(variation, robot, device_spec):
fingertip_type, direction = variation
start, end = LINE_DIRECTION_COORDINATES[direction]
angle = _ComputePerpendicularAngle(start, end)
fingertip = robot.fingertips[fingertip_type]
robot.PushSpeed(SPEEDS[tests.GV.NORMAL])
robot.Line(device_spec, [fingertip], start, end, fingertip_angle=angle)
robot.PopSpeed()
def _PerformPhysicalClickTest(variation, robot, device_spec, fingertips):
location, = variation
click_position = LOCATION_COORDINATES[location]
robot.Click(device_spec, fingertips, click_position)
def _PerformDrumroll(variation, robot, device_spec):
fingertips = [robot.fingertips[STANDARD_FINGERTIP],
robot.fingertips[STANDARD_SECONDARY_FINGERTIP]]
location = LOCATION_COORDINATES[tests.GV.CENTER]
robot.Drumroll(device_spec, fingertips, location)
def _PerformSquareResolutionTest(variation, robot, device_spec):
fingertip = robot.fingertips[STANDARD_FINGERTIP]
location = LOCATION_COORDINATES[tests.GV.CENTER]
robot.Draw45DegreeLineSegment(device_spec, [fingertip], location)