зеркало из https://github.com/mozilla/gecko-dev.git
Bug 845925 - Add scroll/pinch actions using touch action chains to the python touch layer, r=mdas
This commit is contained in:
Родитель
80dfb44965
Коммит
89729a754e
|
@ -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'])
|
self.action_chain.append(['cancel'])
|
||||||
return self
|
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):
|
def long_press(self, element, time_in_seconds):
|
||||||
element = element.id
|
element = element.id
|
||||||
self.action_chain.append(['press', element])
|
self.action_chain.append(['press', element])
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from errors import ElementNotVisibleException
|
from errors import ElementNotVisibleException
|
||||||
|
from marionette import Actions
|
||||||
|
from gestures import pinch
|
||||||
"""
|
"""
|
||||||
Adds touch support in Marionette
|
Adds touch support in Marionette
|
||||||
"""
|
"""
|
||||||
|
@ -35,8 +36,9 @@ class MarionetteTouchMixin(object):
|
||||||
|
|
||||||
def flick(self, element, x1, y1, x2, y2, duration=200):
|
def flick(self, element, x1, y1, x2, y2, duration=200):
|
||||||
self.check_element(element)
|
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.
|
action = Actions(self.marionette)
|
||||||
self.execute_script("%s.swipe.apply(this, arguments);" % self.library_name, [element, x1, y1, x2, y2, duration])
|
action.flick(element, x1, y1, x2, y2, duration).perform()
|
||||||
|
|
||||||
def pinch(self, *args, **kwargs):
|
def pinch(self, element, x1, y1, x2, y2, x3, y3, x4, y4, duration = 200):
|
||||||
raise Exception("Pinch is unsupported")
|
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_test import MarionetteTestCase
|
||||||
from marionette import Actions
|
from marionette import Actions
|
||||||
from errors import NoSuchElementException, MarionetteException
|
from errors import NoSuchElementException, MarionetteException
|
||||||
|
from unittest import skip
|
||||||
|
|
||||||
class testSingleFinger(MarionetteTestCase):
|
class testSingleFinger(MarionetteTestCase):
|
||||||
def test_wait(self):
|
def test_wait(self):
|
||||||
|
@ -131,6 +132,7 @@ class testSingleFinger(MarionetteTestCase):
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
self.assertEqual("ContextEnd", self.marionette.execute_script("return document.getElementById('mozLinkCopy').innerHTML;"))
|
self.assertEqual("ContextEnd", self.marionette.execute_script("return document.getElementById('mozLinkCopy').innerHTML;"))
|
||||||
|
|
||||||
|
@skip("Skipping due to Bug 865334")
|
||||||
def test_long_press_fail(self):
|
def test_long_press_fail(self):
|
||||||
testTouch = self.marionette.absolute_url("testAction.html")
|
testTouch = self.marionette.absolute_url("testAction.html")
|
||||||
self.marionette.navigate(testTouch)
|
self.marionette.navigate(testTouch)
|
||||||
|
@ -144,3 +146,13 @@ class testSingleFinger(MarionetteTestCase):
|
||||||
self.marionette.navigate(testTouch)
|
self.marionette.navigate(testTouch)
|
||||||
self.assertRaises(MarionetteException, self.marionette.send_mouse_event, "boolean")
|
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
|
; true if the test should be skipped
|
||||||
skip = false
|
skip = false
|
||||||
|
|
||||||
|
; true if the test requires unagi
|
||||||
|
unagi = false
|
||||||
|
|
||||||
[test_getstatus.py]
|
[test_getstatus.py]
|
||||||
[test_import_script.py]
|
[test_import_script.py]
|
||||||
[test_import_script_content.py.py]
|
[test_import_script_content.py.py]
|
||||||
|
@ -48,14 +51,15 @@ b2g = false
|
||||||
b2g = true
|
b2g = true
|
||||||
browser = false
|
browser = false
|
||||||
|
|
||||||
[test_cancel.py]
|
|
||||||
b2g = true
|
|
||||||
browser = false
|
|
||||||
|
|
||||||
[test_press_release.py]
|
[test_press_release.py]
|
||||||
b2g = true
|
b2g = true
|
||||||
browser = false
|
browser = false
|
||||||
|
|
||||||
|
[test_gesture.py]
|
||||||
|
b2g = true
|
||||||
|
browser = false
|
||||||
|
unagi = true
|
||||||
|
|
||||||
[test_single_finger.py]
|
[test_single_finger.py]
|
||||||
b2g = true
|
b2g = true
|
||||||
browser = false
|
browser = false
|
||||||
|
@ -68,6 +72,10 @@ browser = false
|
||||||
b2g = true
|
b2g = true
|
||||||
browser = false
|
browser = false
|
||||||
|
|
||||||
|
[test_cancel.py]
|
||||||
|
b2g = true
|
||||||
|
browser = false
|
||||||
|
|
||||||
[test_simpletest_pass.js]
|
[test_simpletest_pass.js]
|
||||||
[test_simpletest_sanity.py]
|
[test_simpletest_sanity.py]
|
||||||
[test_simpletest_chrome.js]
|
[test_simpletest_chrome.js]
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
<button id="mozLinkPos" style="position:absolute;left:0px;top:355px;" type="button" allowevents=true>Button2</button>
|
<button id="mozLinkPos" style="position:absolute;left:0px;top:355px;" type="button" allowevents=true>Button2</button>
|
||||||
<!-- "mozLinkCopy" listens for a touchdown and touchup -->
|
<!-- "mozLinkCopy" listens for a touchdown and touchup -->
|
||||||
<button id="mozLinkCopy" style="position:absolute;left:0px;top:455px;" type="button" allowevents=true>Button3</button>
|
<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 -->
|
<!-- "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="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>
|
<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 fourth = document.getElementById("mozLinkCopy2");
|
||||||
var fifth = document.getElementById("mozLinkCancel");
|
var fifth = document.getElementById("mozLinkCancel");
|
||||||
var sixth = document.getElementById("mozMouse");
|
var sixth = document.getElementById("mozMouse");
|
||||||
|
var seventh = document.getElementById("mozLinkScrollStart");
|
||||||
// touchmove and touchend must be performed on the same element as touchstart
|
// touchmove and touchend must be performed on the same element as touchstart
|
||||||
// here is press for vertical move
|
// here is press for vertical move
|
||||||
press.addEventListener("touchstart", function(){changePressText("mozLink")}, false);
|
press.addEventListener("touchstart", function(){changePressText("mozLink")}, false);
|
||||||
|
@ -59,6 +64,9 @@
|
||||||
sixth.addEventListener("mousedown", function(){changeMouseText("MouseDown")}, false);
|
sixth.addEventListener("mousedown", function(){changeMouseText("MouseDown")}, false);
|
||||||
sixth.addEventListener("mouseup", function(){changeMouseText("MouseUp")}, false);
|
sixth.addEventListener("mouseup", function(){changeMouseText("MouseUp")}, false);
|
||||||
sixth.addEventListener("click", function(){changeMouseText("MouseClick")}, 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) {
|
function changeMouseText(strId) {
|
||||||
var mouse = document.getElementById("mozMouse");
|
var mouse = document.getElementById("mozMouse");
|
||||||
switch(strId) {
|
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() {
|
function changeTimePress() {
|
||||||
var fourth = document.getElementById("mozLinkCopy2");
|
var fourth = document.getElementById("mozLinkCopy2");
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
fourth.innerHTML = d.getTime();
|
fourth.innerHTML = d.getTime();
|
||||||
var newButton = document.createElement("button");
|
var newButton = document.createElement("button");
|
||||||
newButton.id = "delayed";
|
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");
|
var content = document.createTextNode("Button6");
|
||||||
newButton.appendChild(content);
|
newButton.appendChild(content);
|
||||||
document.body.appendChild(newButton);
|
document.body.appendChild(newButton);
|
||||||
|
@ -224,6 +242,22 @@
|
||||||
var context = document.getElementById("mozLinkCopy");
|
var context = document.getElementById("mozLinkCopy");
|
||||||
context.innerHTML = "Context";
|
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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -747,7 +747,7 @@ function touch(target, duration, xt, yt, then) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function generates the coordinates of the element
|
* 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.
|
* If they are not specified, then the center of the target is used.
|
||||||
*/
|
*/
|
||||||
function coordinates(target, x0, y0, x1, y1) {
|
function coordinates(target, x0, y0, x1, y1) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче