# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you 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. """ The Touch Actions implementation """ from selenium.webdriver.remote.command import Command class TouchActions(object): """ Generate touch actions. Works like ActionChains; actions are stored in the TouchActions object and are fired with perform(). """ def __init__(self, driver): """ Creates a new TouchActions object. :Args: - driver: The WebDriver instance which performs user actions. It should be with touchscreen enabled. """ self._driver = driver self._actions = [] def perform(self): """ Performs all stored actions. """ for action in self._actions: action() def tap(self, on_element): """ Taps on a given element. :Args: - on_element: The element to tap. """ self._actions.append(lambda: self._driver.execute( Command.SINGLE_TAP, {'element': on_element.id})) return self def double_tap(self, on_element): """ Double taps on a given element. :Args: - on_element: The element to tap. """ self._actions.append(lambda: self._driver.execute( Command.DOUBLE_TAP, {'element': on_element.id})) return self def tap_and_hold(self, xcoord, ycoord): """ Touch down at given coordinates. :Args: - xcoord: X Coordinate to touch down. - ycoord: Y Coordinate to touch down. """ self._actions.append(lambda: self._driver.execute( Command.TOUCH_DOWN, { 'x': int(xcoord), 'y': int(ycoord)})) return self def move(self, xcoord, ycoord): """ Move held tap to specified location. :Args: - xcoord: X Coordinate to move. - ycoord: Y Coordinate to move. """ self._actions.append(lambda: self._driver.execute( Command.TOUCH_MOVE, { 'x': int(xcoord), 'y': int(ycoord)})) return self def release(self, xcoord, ycoord): """ Release previously issued tap 'and hold' command at specified location. :Args: - xcoord: X Coordinate to release. - ycoord: Y Coordinate to release. """ self._actions.append(lambda: self._driver.execute( Command.TOUCH_UP, { 'x': int(xcoord), 'y': int(ycoord)})) return self def scroll(self, xoffset, yoffset): """ Touch and scroll, moving by xoffset and yoffset. :Args: - xoffset: X offset to scroll to. - yoffset: Y offset to scroll to. """ self._actions.append(lambda: self._driver.execute( Command.TOUCH_SCROLL, { 'xoffset': int(xoffset), 'yoffset': int(yoffset)})) return self def scroll_from_element(self, on_element, xoffset, yoffset): """ Touch and scroll starting at on_element, moving by xoffset and yoffset. :Args: - on_element: The element where scroll starts. - xoffset: X offset to scroll to. - yoffset: Y offset to scroll to. """ self._actions.append(lambda: self._driver.execute( Command.TOUCH_SCROLL, { 'element': on_element.id, 'xoffset': int(xoffset), 'yoffset': int(yoffset)})) return self def long_press(self, on_element): """ Long press on an element. :Args: - on_element: The element to long press. """ self._actions.append(lambda: self._driver.execute( Command.LONG_PRESS, {'element': on_element.id})) return self def flick(self, xspeed, yspeed): """ Flicks, starting anywhere on the screen. :Args: - xspeed: The X speed in pixels per second. - yspeed: The Y speed in pixels per second. """ self._actions.append(lambda: self._driver.execute( Command.FLICK, { 'xspeed': int(xspeed), 'yspeed': int(yspeed)})) return self def flick_element(self, on_element, xoffset, yoffset, speed): """ Flick starting at on_element, and moving by the xoffset and yoffset with specified speed. :Args: - on_element: Flick will start at center of element. - xoffset: X offset to flick to. - yoffset: Y offset to flick to. - speed: Pixels per second to flick. """ self._actions.append(lambda: self._driver.execute( Command.FLICK, { 'element': on_element.id, 'xoffset': int(xoffset), 'yoffset': int(yoffset), 'speed': int(speed)})) return self # Context manager so TouchActions can be used in a 'with .. as' statements. def __enter__(self): return self # Return created instance of self. def __exit__(self, _type, _value, _traceback): pass # Do nothing, does not require additional cleanup.