Bug 845925 - Add scroll/pinch actions using touch action chains to the python touch layer, r=mdas

This commit is contained in:
Yiming Yang 2013-04-26 11:14:50 -07:00
Родитель 80dfb44965
Коммит 89729a754e
8 изменённых файлов: 177 добавлений и 11 удалений

Просмотреть файл

@ -0,0 +1,71 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from marionette import MultiActions, Actions
#axis is y or x
#direction is 0 for positive, and -1 for negative
#length is the total length we want to scroll
#increments is how much we want to move per scrolling
#wait_period is the seconds we wait between scrolling
#scroll_back is whether we want to scroll back to original view
def smooth_scroll(marionette_session, start_element, axis, direction, length, increments=None, wait_period=None, scroll_back=None):
if axis not in ["x", "y"]:
raise Exception("Axis must be either 'x' or 'y'")
if direction not in [-1, 0]:
raise Exception("Direction must either be -1 negative or 0 positive")
increments = increments or 100
wait_period = wait_period or 0.05
scroll_back = scroll_back or False
current = 0
if axis is "x":
if direction is -1:
offset = [-increments, 0]
else:
offset = [increments, 0]
else:
if direction is -1:
offset = [0, -increments]
else:
offset = [0, increments]
action = Actions(marionette_session)
action.press(start_element)
while (current < length):
current += increments
action.move_by_offset(*offset).wait(wait_period)
if scroll_back:
offset = [-value for value in offset]
while (current > 0):
current -= increments
action.move_by_offset(*offset).wait(wait_period)
action.release()
action.perform()
#element is the target
#x1,x2 are 1st finger starting position relative to the target
#x3,y3 are 1st finger ending position relative to the target
#x2,y2 are 2nd finger starting position relative to the target
#x4,y4 are 2nd finger ending position relative to the target
#duration is the amount of time in milliseconds we want to complete the pinch.
def pinch(marionette_session, element, x1, y1, x2, y2, x3, y3, x4, y4, duration=200):
time = 0
time_increment = 10
if time_increment >= duration:
time_increment = duration
move_x1 = time_increment*1.0/duration * (x3 - x1)
move_y1 = time_increment*1.0/duration * (y3 - y1)
move_x2 = time_increment*1.0/duration * (x4 - x2)
move_y2 = time_increment*1.0/duration * (y4 - y2)
multiAction = MultiActions(marionette_session)
action1 = Actions(marionette_session)
action2 = Actions(marionette_session)
action1.press(element, x1, y1)
action2.press(element, x2, y2)
while (time < duration):
time += time_increment
action1.move_by_offset(move_x1, move_y1).wait(time_increment/1000)
action2.move_by_offset(move_x2, move_y2).wait(time_increment/1000)
action1.release()
action2.release()
multiAction.add(action1).add(action2).perform()

Просмотреть файл

@ -138,6 +138,22 @@ class Actions(object):
self.action_chain.append(['cancel'])
return self
def flick(self, element, x1, y1, x2, y2, duration=200):
element = element.id
time = 0
time_increment = 10
if time_increment >= duration:
time_increment = duration
move_x = time_increment*1.0/duration * (x2 - x1)
move_y = time_increment*1.0/duration * (y2 - y1)
self.action_chain.append(['press', element, x1, y1])
while (time < duration):
time += time_increment
self.action_chain.append(['moveByOffset', move_x, move_y])
self.action_chain.append(['wait', time_increment/1000])
self.action_chain.append(['release'])
return self
def long_press(self, element, time_in_seconds):
element = element.id
self.action_chain.append(['press', element])

Просмотреть файл

@ -4,7 +4,8 @@
import os
from errors import ElementNotVisibleException
from marionette import Actions
from gestures import pinch
"""
Adds touch support in Marionette
"""
@ -35,8 +36,9 @@ class MarionetteTouchMixin(object):
def flick(self, element, x1, y1, x2, y2, duration=200):
self.check_element(element)
# there's 'flick' which is pixels per second, but I'd rather have the library support it than piece it together here.
self.execute_script("%s.swipe.apply(this, arguments);" % self.library_name, [element, x1, y1, x2, y2, duration])
action = Actions(self.marionette)
action.flick(element, x1, y1, x2, y2, duration).perform()
def pinch(self, *args, **kwargs):
raise Exception("Pinch is unsupported")
def pinch(self, element, x1, y1, x2, y2, x3, y3, x4, y4, duration = 200):
self.check_element(element)
pinch(element, x1, y1, x2, y2, x3, y3, x4, y4, duration)

Просмотреть файл

@ -0,0 +1,23 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import time
from marionette_test import MarionetteTestCase
from gestures import smooth_scroll, pinch
class testGestures(MarionetteTestCase):
def test_smooth_scroll(self):
testTouch = self.marionette.absolute_url("testAction.html")
self.marionette.navigate(testTouch)
button = self.marionette.find_element("id", "mozLinkScrollStart")
smooth_scroll(self.marionette, button, "y", -1, 250)
time.sleep(15)
self.assertEqual("End", self.marionette.execute_script("return document.getElementById('mozLinkScroll').innerHTML;"))
def test_pinch(self):
testTouch = self.marionette.absolute_url("testAction.html")
self.marionette.navigate(testTouch)
button = self.marionette.find_element("id", "mozLinkScrollStart")
pinch(self.marionette, button, 0, 0, 0, 0, 0, -50, 0, 50)
time.sleep(15)

Просмотреть файл

@ -6,6 +6,7 @@ import time
from marionette_test import MarionetteTestCase
from marionette import Actions
from errors import NoSuchElementException, MarionetteException
from unittest import skip
class testSingleFinger(MarionetteTestCase):
def test_wait(self):
@ -131,6 +132,7 @@ class testSingleFinger(MarionetteTestCase):
time.sleep(10)
self.assertEqual("ContextEnd", self.marionette.execute_script("return document.getElementById('mozLinkCopy').innerHTML;"))
@skip("Skipping due to Bug 865334")
def test_long_press_fail(self):
testTouch = self.marionette.absolute_url("testAction.html")
self.marionette.navigate(testTouch)
@ -144,3 +146,13 @@ class testSingleFinger(MarionetteTestCase):
self.marionette.navigate(testTouch)
self.assertRaises(MarionetteException, self.marionette.send_mouse_event, "boolean")
def test_chain_flick(self):
testTouch = self.marionette.absolute_url("testAction.html")
self.marionette.navigate(testTouch)
button = self.marionette.find_element("id", "mozLinkScrollStart")
action = Actions(self.marionette)
action.flick(button, 0, 0, 0, -250).perform()
time.sleep(15)
self.assertEqual("End", self.marionette.execute_script("return document.getElementById('mozLinkScroll').innerHTML;"))
self.assertEqual("Start", self.marionette.execute_script("return document.getElementById('mozLinkScrollStart').innerHTML;"))

Просмотреть файл

@ -11,6 +11,9 @@ b2g = true
; true if the test should be skipped
skip = false
; true if the test requires unagi
unagi = false
[test_getstatus.py]
[test_import_script.py]
[test_import_script_content.py.py]
@ -48,14 +51,15 @@ b2g = false
b2g = true
browser = false
[test_cancel.py]
b2g = true
browser = false
[test_press_release.py]
b2g = true
browser = false
[test_gesture.py]
b2g = true
browser = false
unagi = true
[test_single_finger.py]
b2g = true
browser = false
@ -68,6 +72,10 @@ browser = false
b2g = true
browser = false
[test_cancel.py]
b2g = true
browser = false
[test_simpletest_pass.js]
[test_simpletest_sanity.py]
[test_simpletest_chrome.js]

Просмотреть файл

@ -15,6 +15,10 @@
<button id="mozLinkPos" style="position:absolute;left:0px;top:355px;" type="button" allowevents=true>Button2</button>
<!-- "mozLinkCopy" listens for a touchdown and touchup -->
<button id="mozLinkCopy" style="position:absolute;left:0px;top:455px;" type="button" allowevents=true>Button3</button>
<!-- "mozLinkScroll" listens for scroll -->
<button id="mozLinkScroll" style="position:absolute;left:0px;top:655px;" type="button" allowevents=true>Button8</button>
<!-- "mozLinkScrollStart" listens for scroll -->
<button id="mozLinkScrollStart" style="position:absolute;left:0px;top:405px;" type="button" allowevents=true>Button9</button>
<!-- "mozLinkStart" and "mozLinkEnd" work together to perform touchdown on mozLinkStart, horizontal move and then touchup on mozLinkEnd -->
<button id="mozLinkStart" style="position:absolute;left:10px;top:200px;" type="button" allowevents=true>Press</button>
<button id="mozLinkEnd" style="position:absolute;left:140px;top:200px;" type="button" allowevents=true>Release</button>
@ -32,6 +36,7 @@
var fourth = document.getElementById("mozLinkCopy2");
var fifth = document.getElementById("mozLinkCancel");
var sixth = document.getElementById("mozMouse");
var seventh = document.getElementById("mozLinkScrollStart");
// touchmove and touchend must be performed on the same element as touchstart
// here is press for vertical move
press.addEventListener("touchstart", function(){changePressText("mozLink")}, false);
@ -59,6 +64,9 @@
sixth.addEventListener("mousedown", function(){changeMouseText("MouseDown")}, false);
sixth.addEventListener("mouseup", function(){changeMouseText("MouseUp")}, false);
sixth.addEventListener("click", function(){changeMouseText("MouseClick")}, false);
// here is seventh for a scroll
seventh.addEventListener("touchstart", function(){changePressText("mozLinkScrollStart")}, false);
seventh.addEventListener("touchend", function(){changeScrollText("mozLinkScroll")}, false);
function changeMouseText(strId) {
var mouse = document.getElementById("mozMouse");
switch(strId) {
@ -193,13 +201,23 @@
}
}
function changeScrollText(strId) {
var seventh = document.getElementById(strId);
if (elementInViewport(seventh)) {
seventh.innerHTML = "End";
}
else {
seventh.innerHTML = "Error";
}
}
function changeTimePress() {
var fourth = document.getElementById("mozLinkCopy2");
var d = new Date();
fourth.innerHTML = d.getTime();
var newButton = document.createElement("button");
newButton.id = "delayed";
newButton.setAttribute("style", "position:absolute;left:80px;top:105px;");
newButton.setAttribute("style", "position:absolute;left:220px;top:455px;");
var content = document.createTextNode("Button6");
newButton.appendChild(content);
document.body.appendChild(newButton);
@ -224,6 +242,22 @@
var context = document.getElementById("mozLinkCopy");
context.innerHTML = "Context";
}
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth));
}
</script>
</body>
</html>

Просмотреть файл

@ -747,7 +747,7 @@ function touch(target, duration, xt, yt, then) {
/**
* This function generates the coordinates of the element
* @param 'x0', 'y0', 'x1', and 'y1' are the relative to the viewport.
* @param 'x0', 'y0', 'x1', and 'y1' are the relative to the target.
* If they are not specified, then the center of the target is used.
*/
function coordinates(target, x0, y0, x1, y1) {