Make android gestures use offsets

This commit is contained in:
Isaac Murchie 2015-04-12 15:05:15 -04:00
Родитель cebff91c2c
Коммит 665890b23e
3 изменённых файлов: 113 добавлений и 42 удалений

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

@ -1001,6 +1001,12 @@ androidController.performTouch = function (gestures, cb) {
// some things are special
doTouchDrag(gestures, cb);
} else {
// `press` without a wait is too slow and gets interpretted as a `longPress`
if (actions[actions.length - 2] === 'press' && actions[actions.length - 1] === 'release') {
actions[actions.length - 2] = 'tap';
gestures[gestures.length - 2].action = 'tap';
}
// the `longPress` and `tap` methods release on their own
if ((actions[actions.length - 2] === 'tap' ||
actions[actions.length - 2] === 'longPress') && actions[actions.length - 1] === 'release') {
@ -1011,12 +1017,15 @@ androidController.performTouch = function (gestures, cb) {
// fix release action then perform all actions
fixRelease(function (err) {
if (err) return cb(err);
async.eachSeries(gestures, performGesture, cb);
});
this.parseTouch(gestures, false, function (err, fixedGestures) {
if (err) return cb(err);
async.eachSeries(fixedGestures, performGesture, cb);
});
}.bind(this));
}
};
androidController.parseTouch = function (gestures, cb) {
androidController.parseTouch = function (gestures, multi, cb) {
if (_.last(gestures).action === 'release') {
gestures.pop();
}
@ -1027,8 +1036,9 @@ androidController.parseTouch = function (gestures, cb) {
var touchStateObjects = [];
async.eachSeries(gestures, function (gesture, done) {
var tapPoint = false;
if (needsPoint(gesture.action)) { // press, longPress, moveTo and tap all need a position
var options = gesture.options;
if (needsPoint(gesture.action)) {
options.offset = false;
var elementId = gesture.options.element;
if (elementId) {
this.getLocation(elementId, function (err, res) {
@ -1040,22 +1050,17 @@ androidController.parseTouch = function (gestures, cb) {
var size = {w: res.value.width, h: res.value.height};
if (gesture.options.x || gesture.options.y) {
tapPoint = {
offset: false,
x: pos.x + (gesture.options.x || 0),
y: pos.y + (gesture.options.y || 0)
};
options.x = pos.x + (gesture.options.x || 0);
options.y = pos.y + (gesture.options.y || 0);
} else {
tapPoint = {
offset: false,
x: pos.x + (size.w / 2),
y: pos.y + (size.h / 2)
};
options.x = pos.x + (size.w / 2);
options.y = pos.y + (size.h / 2);
}
var touchStateObject = {
action: gesture.action,
options: options,
timeOffset: 0.005,
touch: tapPoint
};
touchStateObjects.push(touchStateObject);
done();
@ -1064,31 +1069,28 @@ androidController.parseTouch = function (gestures, cb) {
} else {
// expects absolute coordinates, so we need to save these as offsets
// and then translate when everything is done
tapPoint = {
offset: true,
x: (gesture.options.x || 0),
y: (gesture.options.y || 0)
};
options.offset = true;
options.x = (gesture.options.x || 0);
options.y = (gesture.options.y || 0);
touchStateObject = {
action: gesture.action,
options: options,
timeOffset: 0.005,
touch: tapPoint
};
touchStateObjects.push(touchStateObject);
done();
}
} else {
// in this case we need the previous entry's tap point
tapPoint = false; // temporary marker
var offset = 0.005;
if (gesture.action === 'wait') {
if (typeof gesture.options.ms !== 'undefined' || gesture.options.ms !== null) {
offset = (parseInt(gesture.options.ms) / 1000);
}
options = gesture.options;
offset = (parseInt(gesture.options.ms) / 1000);
}
var touchStateObject = {
action: gesture.action,
options: options,
timeOffset: offset,
touch: tapPoint
};
touchStateObjects.push(touchStateObject);
done();
@ -1101,20 +1103,28 @@ androidController.parseTouch = function (gestures, cb) {
var prevPos = null,
time = 0;
_.each(touchStateObjects, function (state) {
if (state.touch === false) {
// if we have no position (this happens with `wait`) we need the previous one
state.touch = prevPos;
} else if (state.touch.offset && prevPos) {
// the current position is an offset
state.touch.x += prevPos.x;
state.touch.y += prevPos.y;
if (typeof state.options.x === 'undefined' && typeof state.options.x === 'undefined') {
// this happens with wait
state.options.x = prevPos.x;
state.options.y = prevPos.y;
}
delete state.touch.offset;
prevPos = state.touch;
if (state.options.offset && prevPos) {
// the current position is an offset
state.options.x += prevPos.x;
state.options.y += prevPos.y;
}
delete state.options.offset;
prevPos = state.options;
var timeOffset = state.timeOffset;
time += timeOffset;
state.time = helpers.truncateDecimals(time, 3);
if (multi) {
var timeOffset = state.timeOffset;
time += timeOffset;
state.time = helpers.truncateDecimals(time, 3);
// multi gestures require 'touch' rather than 'options'
state.touch = state.options;
delete state.options;
}
delete state.timeOffset;
});
@ -1132,7 +1142,7 @@ androidController.performMultiAction = function (elementId, actions, cb) {
var states = [];
async.eachSeries(actions, function (action, done) {
this.parseTouch(action, function (err, val) {
this.parseTouch(action, true, function (err, val) {
if (err) return done(err);
states.push(val);

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

@ -0,0 +1,37 @@
"use strict";
var chai = require('chai')
, controller_path = '../../lib/devices/android/android-controller.js'
, controller = require(controller_path)
, _ = require('underscore');
chai.should();
describe('android-controller', function () {
describe('#parseTouch', function () {
describe('given a touch sequence with absolute coordinates', function () {
it('should use offsets for moveTo', function (done) {
var actions = [ { action: 'press', options: { x: 100, y: 101 } },
{ action: 'moveTo', options: { x: 50, y: 51 } },
{ action: 'wait', options: { ms: 5000 } },
{ action: 'moveTo', options: { x: -40, y: -41 } },
{ action: 'release', options: {} } ];
controller.parseTouch(actions, false, function (err, touchStates) {
touchStates.length.should.equal(4);
var actions = [{action: 'press', x: 100, y: 101},
{action: 'moveTo', x: 150, y: 152},
{action: 'wait', x: 150, y: 152},
{action: 'moveTo', x: 110, y: 111}];
_.each(touchStates, function (state, index) {
state.action.should.equal(actions[index].action);
state.options.x.should.equal(actions[index].x);
state.options.y.should.equal(actions[index].y);
});
done();
});
});
});
});
});

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

@ -4,7 +4,8 @@ var chai = require('chai')
, controller_path = '../../lib/devices/ios/ios-controller.js'
, controller = require(controller_path)
, createGetElementCommand = controller.createGetElementCommand
, getSelectorForStrategy = controller.getSelectorForStrategy;
, getSelectorForStrategy = controller.getSelectorForStrategy
, _ = require('underscore');
chai.should();
@ -71,4 +72,27 @@ describe('ios-controller', function () {
});
});
});
describe('#parseTouch', function () {
describe('given a touch sequence with absolute coordinates', function () {
it('should use offsets for moveTo', function (done) {
var actions = [ { action: 'press', options: { x: 100, y: 101 } },
{ action: 'moveTo', options: { x: 50, y: 51 } },
{ action: 'wait', options: { ms: 5000 } },
{ action: 'moveTo', options: { x: -40, y: -41 } },
{ action: 'release', options: {} } ];
controller.parseTouch(actions, function (err, touchStates) {
touchStates.length.should.equal(4); // `release` is removed
var locs = [{x: 100, y: 101}, {x: 150, y: 152}, {x: 150, y: 152}, {x: 110, y: 111}];
_.each(touchStates, function (state, index) {
var action = state.touch[0];
action.x.should.equal(locs[index].x);
action.y.should.equal(locs[index].y);
});
done();
});
});
});
});
});