appium-android-driver 7.8.3 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/build/lib/commands/app-management.d.ts +129 -5
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +433 -128
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.d.ts +17 -4
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +32 -33
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/context/cache.d.ts +19 -0
- package/build/lib/commands/context/cache.d.ts.map +1 -0
- package/build/lib/commands/context/cache.js +32 -0
- package/build/lib/commands/context/cache.js.map +1 -0
- package/build/lib/commands/context/exports.d.ts +141 -0
- package/build/lib/commands/context/exports.d.ts.map +1 -0
- package/build/lib/commands/context/exports.js +351 -0
- package/build/lib/commands/context/exports.js.map +1 -0
- package/build/lib/commands/context/helpers.d.ts +98 -0
- package/build/lib/commands/context/helpers.d.ts.map +1 -0
- package/build/lib/commands/context/helpers.js +715 -0
- package/build/lib/commands/context/helpers.js.map +1 -0
- package/build/lib/commands/device/common.d.ts +23 -0
- package/build/lib/commands/device/common.d.ts.map +1 -0
- package/build/lib/commands/device/common.js +230 -0
- package/build/lib/commands/device/common.js.map +1 -0
- package/build/lib/commands/device/emulator-actions.d.ts +114 -0
- package/build/lib/commands/device/emulator-actions.d.ts.map +1 -0
- package/build/lib/commands/device/emulator-actions.js +197 -0
- package/build/lib/commands/device/emulator-actions.js.map +1 -0
- package/build/lib/commands/device/emulator-console.d.ts +7 -0
- package/build/lib/commands/device/emulator-console.d.ts.map +1 -0
- package/build/lib/commands/device/emulator-console.js +24 -0
- package/build/lib/commands/device/emulator-console.js.map +1 -0
- package/build/lib/commands/device/utils.d.ts +50 -0
- package/build/lib/commands/device/utils.d.ts.map +1 -0
- package/build/lib/commands/device/utils.js +238 -0
- package/build/lib/commands/device/utils.js.map +1 -0
- package/build/lib/commands/deviceidle.d.ts +8 -5
- package/build/lib/commands/deviceidle.d.ts.map +1 -1
- package/build/lib/commands/deviceidle.js +31 -37
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/element.d.ts +99 -5
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +152 -116
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +12 -4
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +83 -78
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +42 -5
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +230 -194
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +5 -4
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +7 -10
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts +45 -0
- package/build/lib/commands/geolocation.d.ts.map +1 -0
- package/build/lib/commands/geolocation.js +182 -0
- package/build/lib/commands/geolocation.js.map +1 -0
- package/build/lib/commands/ime.d.ts +25 -5
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +59 -42
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/intent.d.ts +56 -5
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +135 -83
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +58 -4
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +119 -17
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/lock/exports.d.ts +301 -0
- package/build/lib/commands/lock/exports.d.ts.map +1 -0
- package/build/lib/commands/lock/exports.js +121 -0
- package/build/lib/commands/lock/exports.js.map +1 -0
- package/build/lib/commands/lock/helpers.d.ts +349 -0
- package/build/lib/commands/lock/helpers.d.ts.map +1 -0
- package/build/lib/commands/lock/helpers.js +375 -0
- package/build/lib/commands/lock/helpers.js.map +1 -0
- package/build/lib/commands/log.d.ts +59 -5
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +150 -140
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +16 -5
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +69 -58
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/memory.d.ts +9 -5
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +19 -24
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/misc.d.ts +42 -0
- package/build/lib/commands/misc.d.ts.map +1 -0
- package/build/lib/commands/misc.js +100 -0
- package/build/lib/commands/misc.js.map +1 -0
- package/build/lib/commands/network.d.ts +61 -5
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +196 -189
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +67 -27
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +105 -80
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +12 -6
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +65 -62
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +44 -5
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +131 -126
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/resources.d.ts +16 -0
- package/build/lib/commands/resources.d.ts.map +1 -0
- package/build/lib/commands/resources.js +91 -0
- package/build/lib/commands/resources.js.map +1 -0
- package/build/lib/commands/shell.d.ts +8 -5
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +29 -33
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +34 -6
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +166 -162
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +18 -13
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +68 -64
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/time.d.ts +14 -0
- package/build/lib/commands/time.d.ts.map +1 -0
- package/build/lib/commands/time.js +39 -0
- package/build/lib/commands/time.js.map +1 -0
- package/build/lib/commands/touch.d.ts +99 -6
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +399 -280
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/types.d.ts +110 -2
- package/build/lib/commands/types.d.ts.map +1 -1
- package/build/lib/doctor/checks.d.ts.map +1 -1
- package/build/lib/doctor/checks.js +4 -4
- package/build/lib/doctor/checks.js.map +1 -1
- package/build/lib/driver.d.ts +224 -27
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +232 -7
- package/build/lib/driver.js.map +1 -1
- package/build/lib/index.d.ts +1 -4
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +1 -13
- package/build/lib/index.js.map +1 -1
- package/build/lib/logger.js.map +1 -1
- package/build/lib/method-map.d.ts +0 -23
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js +0 -11
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/utils.d.ts +12 -0
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +38 -2
- package/build/lib/utils.js.map +1 -1
- package/lib/commands/app-management.js +470 -145
- package/lib/commands/appearance.js +29 -36
- package/lib/commands/context/cache.js +29 -0
- package/lib/commands/context/exports.js +379 -0
- package/lib/commands/context/helpers.js +802 -0
- package/lib/commands/device/common.js +264 -0
- package/lib/commands/device/emulator-actions.js +194 -0
- package/lib/commands/device/emulator-console.js +24 -0
- package/lib/commands/device/utils.js +285 -0
- package/lib/commands/deviceidle.js +31 -44
- package/lib/commands/element.js +149 -142
- package/lib/commands/execute.js +86 -87
- package/lib/commands/file-actions.js +249 -222
- package/lib/commands/find.ts +13 -19
- package/lib/commands/geolocation.js +179 -0
- package/lib/commands/ime.js +53 -45
- package/lib/commands/intent.js +149 -91
- package/lib/commands/keyboard.js +114 -17
- package/lib/commands/lock/exports.js +139 -0
- package/lib/commands/lock/helpers.js +379 -0
- package/lib/commands/log.js +170 -166
- package/lib/commands/media-projection.js +75 -70
- package/lib/commands/memory.js +17 -29
- package/lib/commands/misc.js +94 -0
- package/lib/commands/network.js +209 -223
- package/lib/commands/performance.js +88 -73
- package/lib/commands/permissions.js +83 -84
- package/lib/commands/recordscreen.js +171 -170
- package/lib/commands/resources.js +96 -0
- package/lib/commands/shell.js +28 -42
- package/lib/commands/streamscreen.js +207 -206
- package/lib/commands/system-bars.js +76 -77
- package/lib/commands/time.js +36 -0
- package/lib/commands/touch.js +442 -346
- package/lib/commands/types.ts +123 -2
- package/lib/doctor/checks.js +24 -16
- package/lib/driver.ts +454 -12
- package/lib/index.ts +1 -13
- package/lib/logger.js +1 -1
- package/lib/method-map.js +0 -11
- package/lib/utils.js +40 -3
- package/package.json +1 -1
- package/build/lib/commands/actions.d.ts +0 -8
- package/build/lib/commands/actions.d.ts.map +0 -1
- package/build/lib/commands/actions.js +0 -207
- package/build/lib/commands/actions.js.map +0 -1
- package/build/lib/commands/alert.d.ts +0 -8
- package/build/lib/commands/alert.d.ts.map +0 -1
- package/build/lib/commands/alert.js +0 -29
- package/build/lib/commands/alert.js.map +0 -1
- package/build/lib/commands/context.d.ts +0 -10
- package/build/lib/commands/context.d.ts.map +0 -1
- package/build/lib/commands/context.js +0 -431
- package/build/lib/commands/context.js.map +0 -1
- package/build/lib/commands/emu-console.d.ts +0 -7
- package/build/lib/commands/emu-console.d.ts.map +0 -1
- package/build/lib/commands/emu-console.js +0 -27
- package/build/lib/commands/emu-console.js.map +0 -1
- package/build/lib/commands/general.d.ts +0 -9
- package/build/lib/commands/general.d.ts.map +0 -1
- package/build/lib/commands/general.js +0 -293
- package/build/lib/commands/general.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -28
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -57
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/commands/mixins.d.ts +0 -747
- package/build/lib/commands/mixins.d.ts.map +0 -1
- package/build/lib/commands/mixins.js +0 -19
- package/build/lib/commands/mixins.js.map +0 -1
- package/build/lib/helpers/android.d.ts +0 -163
- package/build/lib/helpers/android.d.ts.map +0 -1
- package/build/lib/helpers/android.js +0 -818
- package/build/lib/helpers/android.js.map +0 -1
- package/build/lib/helpers/index.d.ts +0 -7
- package/build/lib/helpers/index.d.ts.map +0 -1
- package/build/lib/helpers/index.js +0 -29
- package/build/lib/helpers/index.js.map +0 -1
- package/build/lib/helpers/types.d.ts +0 -122
- package/build/lib/helpers/types.d.ts.map +0 -1
- package/build/lib/helpers/types.js +0 -3
- package/build/lib/helpers/types.js.map +0 -1
- package/build/lib/helpers/unlock.d.ts +0 -32
- package/build/lib/helpers/unlock.d.ts.map +0 -1
- package/build/lib/helpers/unlock.js +0 -273
- package/build/lib/helpers/unlock.js.map +0 -1
- package/build/lib/helpers/webview.d.ts +0 -74
- package/build/lib/helpers/webview.d.ts.map +0 -1
- package/build/lib/helpers/webview.js +0 -448
- package/build/lib/helpers/webview.js.map +0 -1
- package/lib/commands/actions.js +0 -244
- package/lib/commands/alert.js +0 -34
- package/lib/commands/context.js +0 -507
- package/lib/commands/emu-console.js +0 -31
- package/lib/commands/general.js +0 -343
- package/lib/commands/index.ts +0 -54
- package/lib/commands/mixins.ts +0 -976
- package/lib/helpers/android.ts +0 -1153
- package/lib/helpers/index.ts +0 -6
- package/lib/helpers/types.ts +0 -136
- package/lib/helpers/unlock.ts +0 -329
- package/lib/helpers/webview.ts +0 -610
package/lib/commands/touch.js
CHANGED
|
@@ -1,15 +1,248 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
|
|
3
3
|
import {util} from '@appium/support';
|
|
4
4
|
import {errors, isErrorType} from 'appium/driver';
|
|
5
5
|
import {asyncmap} from 'asyncbox';
|
|
6
6
|
import B from 'bluebird';
|
|
7
7
|
import _ from 'lodash';
|
|
8
|
-
import androidHelpers from '../helpers/android';
|
|
9
|
-
import {mixin} from './mixins';
|
|
10
8
|
|
|
11
9
|
/**
|
|
12
|
-
*
|
|
10
|
+
* @deprecated
|
|
11
|
+
* @this {import('../driver').AndroidDriver}
|
|
12
|
+
* @param {string?} [elementId=null]
|
|
13
|
+
* @param {number?} [x=null]
|
|
14
|
+
* @param {number?} [y=null]
|
|
15
|
+
* @param {number} [count=1]
|
|
16
|
+
* @returns {Promise<void>}
|
|
17
|
+
*/
|
|
18
|
+
export async function tap(elementId = null, x = null, y = null, count = 1) {
|
|
19
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated
|
|
24
|
+
* @this {import('../driver').AndroidDriver}
|
|
25
|
+
* @param {string} elementId
|
|
26
|
+
* @param {number} x
|
|
27
|
+
* @param {number} y
|
|
28
|
+
* @param {number} duration
|
|
29
|
+
* @returns {Promise<void>}
|
|
30
|
+
*/
|
|
31
|
+
export async function touchLongClick(elementId, x, y, duration) {
|
|
32
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated
|
|
37
|
+
* @this {import('../driver').AndroidDriver}
|
|
38
|
+
* @param {string} elementId
|
|
39
|
+
* @param {number} x
|
|
40
|
+
* @param {number} y
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
export async function touchDown(elementId, x, y) {
|
|
44
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated
|
|
49
|
+
* @this {import('../driver').AndroidDriver}
|
|
50
|
+
* @param {string} elementId
|
|
51
|
+
* @param {number} x
|
|
52
|
+
* @param {number} y
|
|
53
|
+
* @returns {Promise<void>}
|
|
54
|
+
*/
|
|
55
|
+
export async function touchUp(elementId, x, y) {
|
|
56
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @deprecated
|
|
61
|
+
* @this {import('../driver').AndroidDriver}
|
|
62
|
+
* @param {string} elementId
|
|
63
|
+
* @param {number} x
|
|
64
|
+
* @param {number} y
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
*/
|
|
67
|
+
export async function touchMove(elementId, x, y) {
|
|
68
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @deprecated
|
|
73
|
+
* @this {import('../driver').AndroidDriver}
|
|
74
|
+
* @param {import('./types').SwipeOpts} opts
|
|
75
|
+
* @returns {Promise<void>}
|
|
76
|
+
*/
|
|
77
|
+
export async function doSwipe(opts) {
|
|
78
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @deprecated
|
|
83
|
+
* @this {import('../driver').AndroidDriver}
|
|
84
|
+
* @param {import('./types').TouchDragAction} opts
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
export async function doTouchDrag(opts) {
|
|
88
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @deprecated
|
|
93
|
+
* @this {import('../driver').AndroidDriver}
|
|
94
|
+
* @param {import('./types').TouchActionKind} action
|
|
95
|
+
* @param {import('./types').TouchActionOpts} [opts={}]
|
|
96
|
+
* @returns {Promise<void>}
|
|
97
|
+
*/
|
|
98
|
+
export async function doTouchAction(action, opts = {}) {
|
|
99
|
+
const {element, x, y, count, ms, duration} = opts;
|
|
100
|
+
// parseTouch precalculates absolute element positions
|
|
101
|
+
// so there is no need to pass `element` to the affected gestures
|
|
102
|
+
switch (action) {
|
|
103
|
+
case 'tap':
|
|
104
|
+
return await this.tap('', x, y, count);
|
|
105
|
+
case 'press':
|
|
106
|
+
return await this.touchDown('', /** @type {number} */ (x), /** @type {number} */ (y));
|
|
107
|
+
case 'release':
|
|
108
|
+
return await this.touchUp(
|
|
109
|
+
String(element),
|
|
110
|
+
/** @type {number} */ (x),
|
|
111
|
+
/** @type {number} */ (y),
|
|
112
|
+
);
|
|
113
|
+
case 'moveTo':
|
|
114
|
+
return await this.touchMove('', /** @type {number} */ (x), /** @type {number} */ (y));
|
|
115
|
+
case 'wait':
|
|
116
|
+
return await B.delay(/** @type {number} */ (ms));
|
|
117
|
+
case 'longPress':
|
|
118
|
+
return await this.touchLongClick(
|
|
119
|
+
'',
|
|
120
|
+
/** @type {number} */ (x),
|
|
121
|
+
/** @type {number} */ (y),
|
|
122
|
+
duration ?? 1000,
|
|
123
|
+
);
|
|
124
|
+
case 'cancel':
|
|
125
|
+
// TODO: clarify behavior of 'cancel' action and fix this
|
|
126
|
+
this.log.warn('Cancel action currently has no effect');
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
this.log.errorAndThrow(`unknown action ${action}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @deprecated
|
|
135
|
+
* @this {import('../driver').AndroidDriver}
|
|
136
|
+
* @param {import('./types').TouchAction[]} gestures
|
|
137
|
+
* @returns {Promise<void>}
|
|
138
|
+
*/
|
|
139
|
+
export async function performTouch(gestures) {
|
|
140
|
+
// press-wait-moveTo-release is `swipe`, so use native method
|
|
141
|
+
if (
|
|
142
|
+
gestures.length === 4 &&
|
|
143
|
+
gestures[0].action === 'press' &&
|
|
144
|
+
gestures[1].action === 'wait' &&
|
|
145
|
+
gestures[2].action === 'moveTo' &&
|
|
146
|
+
gestures[3].action === 'release'
|
|
147
|
+
) {
|
|
148
|
+
let swipeOpts = await getSwipeOptions.bind(this)(
|
|
149
|
+
/** @type {import('./types').SwipeAction} */ (gestures),
|
|
150
|
+
);
|
|
151
|
+
return await this.doSwipe(swipeOpts);
|
|
152
|
+
}
|
|
153
|
+
let actions = /** @type {(import('./types').TouchActionKind|TouchAction)[]} */ (
|
|
154
|
+
_.map(gestures, 'action')
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (actions[0] === 'longPress' && actions[1] === 'moveTo' && actions[2] === 'release') {
|
|
158
|
+
// some things are special
|
|
159
|
+
return await this.doTouchDrag(/** @type {import('./types').TouchDragAction} */ (gestures));
|
|
160
|
+
} else {
|
|
161
|
+
if (actions.length === 2) {
|
|
162
|
+
// `press` without a wait is too slow and gets interpretted as a `longPress`
|
|
163
|
+
if (_.head(actions) === 'press' && _.last(actions) === 'release') {
|
|
164
|
+
actions[0] = 'tap';
|
|
165
|
+
gestures[0].action = 'tap';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// the `longPress` and `tap` methods release on their own
|
|
169
|
+
if (
|
|
170
|
+
(_.head(actions) === 'tap' || _.head(actions) === 'longPress') &&
|
|
171
|
+
_.last(actions) === 'release'
|
|
172
|
+
) {
|
|
173
|
+
gestures.pop();
|
|
174
|
+
actions.pop();
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
// longpress followed by anything other than release should become a press and wait
|
|
178
|
+
if (actions[0] === 'longPress') {
|
|
179
|
+
actions = ['press', 'wait', ...actions.slice(1)];
|
|
180
|
+
|
|
181
|
+
let press = /** @type {NonReleaseTouchAction} */ (gestures.shift());
|
|
182
|
+
press.action = 'press';
|
|
183
|
+
/** @type {NonReleaseTouchAction} */
|
|
184
|
+
let wait = {
|
|
185
|
+
action: 'wait',
|
|
186
|
+
options: {ms: press.options.duration || 1000},
|
|
187
|
+
};
|
|
188
|
+
delete press.options.duration;
|
|
189
|
+
gestures = [press, wait, ...gestures];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let fixedGestures = await parseTouch.bind(this)(gestures, false);
|
|
194
|
+
// fix release action then perform all actions
|
|
195
|
+
if (actions[actions.length - 1] === 'release') {
|
|
196
|
+
actions[actions.length - 1] = /** @type {TouchAction} */ (
|
|
197
|
+
await fixRelease.bind(this)(gestures)
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
for (let g of fixedGestures) {
|
|
201
|
+
await performGesture.bind(this)(g);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @deprecated
|
|
208
|
+
* @this {import('../driver').AndroidDriver}
|
|
209
|
+
* @param {import('./types').TouchAction[]} actions
|
|
210
|
+
* @param {string} elementId
|
|
211
|
+
* @returns {Promise<void>}
|
|
212
|
+
*/
|
|
213
|
+
export async function performMultiAction(actions, elementId) {
|
|
214
|
+
// Android needs at least two actions to be able to perform a multi pointer gesture
|
|
215
|
+
if (actions.length === 1) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
'Multi Pointer Gestures need at least two actions. ' +
|
|
218
|
+
'Use Touch Actions for a single action.',
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const states = await asyncmap(
|
|
223
|
+
actions,
|
|
224
|
+
async (action) => await parseTouch.bind(this)(action, true),
|
|
225
|
+
false,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return await this.doPerformMultiAction(elementId, states);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @deprecated
|
|
233
|
+
* @this {import('../driver').AndroidDriver}
|
|
234
|
+
* @param {string} elementId
|
|
235
|
+
* @param {import('./types').TouchState[]} states
|
|
236
|
+
* @returns {Promise<void>}
|
|
237
|
+
*/
|
|
238
|
+
export async function doPerformMultiAction(elementId, states) {
|
|
239
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// #region Internal helpers
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @deprecated
|
|
13
246
|
* @param {number|null} [val]
|
|
14
247
|
* @returns {number}
|
|
15
248
|
*/
|
|
@@ -21,7 +254,21 @@ function getCoordDefault(val) {
|
|
|
21
254
|
}
|
|
22
255
|
|
|
23
256
|
/**
|
|
24
|
-
*
|
|
257
|
+
* @deprecated
|
|
258
|
+
* @param {number} number
|
|
259
|
+
* @param {number} digits
|
|
260
|
+
* @returns {number}
|
|
261
|
+
*/
|
|
262
|
+
export function truncateDecimals(number, digits) {
|
|
263
|
+
const multiplier = Math.pow(10, digits),
|
|
264
|
+
adjustedNum = number * multiplier,
|
|
265
|
+
truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum);
|
|
266
|
+
|
|
267
|
+
return truncatedNum / multiplier;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @deprecated
|
|
25
272
|
* @param {NonReleaseTouchAction} waitGesture
|
|
26
273
|
* @returns {number}
|
|
27
274
|
*/
|
|
@@ -41,370 +288,219 @@ function getSwipeTouchDuration(waitGesture) {
|
|
|
41
288
|
}
|
|
42
289
|
|
|
43
290
|
/**
|
|
44
|
-
* @
|
|
45
|
-
* @
|
|
291
|
+
* @deprecated
|
|
292
|
+
* @this {import('../driver').AndroidDriver}
|
|
293
|
+
* @param {import('./types').SwipeAction} gestures
|
|
294
|
+
* @param {number} [touchCount=1]
|
|
295
|
+
* @returns {Promise<import('./types').TouchSwipeOpts>}
|
|
46
296
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
case 'press':
|
|
56
|
-
return await this.touchDown('', /** @type {number} */ (x), /** @type {number} */ (y));
|
|
57
|
-
case 'release':
|
|
58
|
-
return await this.touchUp(
|
|
59
|
-
String(element),
|
|
60
|
-
/** @type {number} */ (x),
|
|
61
|
-
/** @type {number} */ (y)
|
|
62
|
-
);
|
|
63
|
-
case 'moveTo':
|
|
64
|
-
return await this.touchMove('', /** @type {number} */ (x), /** @type {number} */ (y));
|
|
65
|
-
case 'wait':
|
|
66
|
-
return await B.delay(/** @type {number} */ (ms));
|
|
67
|
-
case 'longPress':
|
|
68
|
-
return await this.touchLongClick(
|
|
69
|
-
'',
|
|
70
|
-
/** @type {number} */ (x),
|
|
71
|
-
/** @type {number} */ (y),
|
|
72
|
-
duration ?? 1000
|
|
73
|
-
);
|
|
74
|
-
case 'cancel':
|
|
75
|
-
// TODO: clarify behavior of 'cancel' action and fix this
|
|
76
|
-
this.log.warn('Cancel action currently has no effect');
|
|
77
|
-
break;
|
|
78
|
-
default:
|
|
79
|
-
this.log.errorAndThrow(`unknown action ${action}`);
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
async doTouchDrag(gestures) {
|
|
84
|
-
let longPress = gestures[0];
|
|
85
|
-
let moveTo = gestures[1];
|
|
86
|
-
let startX = longPress.options.x || 0,
|
|
87
|
-
startY = longPress.options.y || 0,
|
|
88
|
-
endX = moveTo.options.x || 0,
|
|
89
|
-
endY = moveTo.options.y || 0;
|
|
90
|
-
if (longPress.options.element) {
|
|
91
|
-
let {x, y} = await this.getLocationInView(longPress.options.element);
|
|
92
|
-
startX += x || 0;
|
|
93
|
-
startY += y || 0;
|
|
94
|
-
}
|
|
95
|
-
if (moveTo.options.element) {
|
|
96
|
-
let {x, y} = await this.getLocationInView(moveTo.options.element);
|
|
97
|
-
endX += x || 0;
|
|
98
|
-
endY += y || 0;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let apiLevel = await this.adb.getApiLevel();
|
|
102
|
-
// lollipop takes a little longer to get things rolling
|
|
103
|
-
let duration = apiLevel >= 5 ? 2 : 1;
|
|
104
|
-
// make sure that if the long press has a duration, we use it.
|
|
105
|
-
if (longPress.options && longPress.options.duration) {
|
|
106
|
-
duration = Math.max(longPress.options.duration / 1000, duration);
|
|
107
|
-
}
|
|
297
|
+
async function getSwipeOptions(gestures, touchCount = 1) {
|
|
298
|
+
let startX = getCoordDefault(gestures[0].options.x),
|
|
299
|
+
startY = getCoordDefault(gestures[0].options.y),
|
|
300
|
+
endX = getCoordDefault(gestures[2].options.x),
|
|
301
|
+
endY = getCoordDefault(gestures[2].options.y),
|
|
302
|
+
duration = getSwipeTouchDuration(gestures[1]),
|
|
303
|
+
element = /** @type {string} */ (gestures[0].options.element),
|
|
304
|
+
destElement = gestures[2].options.element || gestures[0].options.element;
|
|
108
305
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
async fixRelease(gestures) {
|
|
123
|
-
let release = /** @type {import('./types').ReleaseTouchAction} */ (_.last(gestures));
|
|
124
|
-
// sometimes there are no options
|
|
125
|
-
release.options = release.options || {};
|
|
126
|
-
// nothing to do if release options are already set
|
|
127
|
-
if (release.options.element || (release.options.x && release.options.y)) {
|
|
128
|
-
return;
|
|
306
|
+
// there's no destination element handling in bootstrap and since it applies to all platforms, we handle it here
|
|
307
|
+
if (util.hasValue(destElement)) {
|
|
308
|
+
let locResult = await this.getLocationInView(destElement);
|
|
309
|
+
let sizeResult = await this.getSize(destElement);
|
|
310
|
+
let offsetX = Math.abs(endX) < 1 && Math.abs(endX) > 0 ? sizeResult.width * endX : endX;
|
|
311
|
+
let offsetY = Math.abs(endY) < 1 && Math.abs(endY) > 0 ? sizeResult.height * endY : endY;
|
|
312
|
+
endX = locResult.x + offsetX;
|
|
313
|
+
endY = locResult.y + offsetY;
|
|
314
|
+
// if the target element was provided, the coordinates for the destination need to be relative to it.
|
|
315
|
+
if (util.hasValue(element)) {
|
|
316
|
+
let firstElLocation = await this.getLocationInView(element);
|
|
317
|
+
endX -= firstElLocation.x;
|
|
318
|
+
endY -= firstElLocation.y;
|
|
129
319
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
gestures = _.clone(gestures);
|
|
135
|
-
let ref = null;
|
|
136
|
-
for (let gesture of /** @type {NonReleaseTouchAction[]} */ (gestures.reverse())) {
|
|
137
|
-
let opts = gesture.options;
|
|
138
|
-
if (opts.element || (opts.x && opts.y)) {
|
|
139
|
-
ref = gesture;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (ref) {
|
|
144
|
-
let opts = ref.options;
|
|
145
|
-
if (opts.element) {
|
|
146
|
-
let loc = await this.getLocationInView(opts.element);
|
|
147
|
-
if (opts.x && opts.y) {
|
|
148
|
-
// this is an offset from the element
|
|
149
|
-
release.options = {
|
|
150
|
-
x: loc.x + opts.x,
|
|
151
|
-
y: loc.y + opts.y,
|
|
152
|
-
};
|
|
153
|
-
} else {
|
|
154
|
-
// this is the center of the element
|
|
155
|
-
let size = await this.getSize(opts.element);
|
|
156
|
-
release.options = {
|
|
157
|
-
x: loc.x + size.width / 2,
|
|
158
|
-
y: loc.y + size.height / 2,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
} else {
|
|
162
|
-
release.options = _.pick(opts, 'x', 'y');
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return release;
|
|
166
|
-
},
|
|
167
|
-
|
|
168
|
-
async performGesture(gesture) {
|
|
169
|
-
try {
|
|
170
|
-
return await this.doTouchAction(gesture.action, gesture.options || {});
|
|
171
|
-
} catch (e) {
|
|
172
|
-
// sometime the element is not available when releasing, retry without it
|
|
173
|
-
if (
|
|
174
|
-
isErrorType(e, errors.NoSuchElementError) &&
|
|
175
|
-
gesture.action === 'release' &&
|
|
176
|
-
gesture.options?.element
|
|
177
|
-
) {
|
|
178
|
-
delete gesture.options.element;
|
|
179
|
-
this.log.debug(`retrying release without element opts: ${gesture.options}.`);
|
|
180
|
-
return await this.doTouchAction(gesture.action, gesture.options || {});
|
|
181
|
-
}
|
|
182
|
-
throw e;
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
|
|
186
|
-
async getSwipeOptions(gestures, touchCount = 1) {
|
|
187
|
-
let startX = getCoordDefault(gestures[0].options.x),
|
|
188
|
-
startY = getCoordDefault(gestures[0].options.y),
|
|
189
|
-
endX = getCoordDefault(gestures[2].options.x),
|
|
190
|
-
endY = getCoordDefault(gestures[2].options.y),
|
|
191
|
-
duration = getSwipeTouchDuration(gestures[1]),
|
|
192
|
-
element = /** @type {string} */ (gestures[0].options.element),
|
|
193
|
-
destElement = gestures[2].options.element || gestures[0].options.element;
|
|
194
|
-
|
|
195
|
-
// there's no destination element handling in bootstrap and since it applies to all platforms, we handle it here
|
|
196
|
-
if (util.hasValue(destElement)) {
|
|
197
|
-
let locResult = await this.getLocationInView(destElement);
|
|
198
|
-
let sizeResult = await this.getSize(destElement);
|
|
199
|
-
let offsetX = Math.abs(endX) < 1 && Math.abs(endX) > 0 ? sizeResult.width * endX : endX;
|
|
200
|
-
let offsetY = Math.abs(endY) < 1 && Math.abs(endY) > 0 ? sizeResult.height * endY : endY;
|
|
201
|
-
endX = locResult.x + offsetX;
|
|
202
|
-
endY = locResult.y + offsetY;
|
|
203
|
-
// if the target element was provided, the coordinates for the destination need to be relative to it.
|
|
204
|
-
if (util.hasValue(element)) {
|
|
205
|
-
let firstElLocation = await this.getLocationInView(element);
|
|
206
|
-
endX -= firstElLocation.x;
|
|
207
|
-
endY -= firstElLocation.y;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// clients are responsible to use these options correctly
|
|
211
|
-
return {startX, startY, endX, endY, duration, touchCount, element};
|
|
212
|
-
},
|
|
213
|
-
|
|
214
|
-
async performTouch(gestures) {
|
|
215
|
-
// press-wait-moveTo-release is `swipe`, so use native method
|
|
216
|
-
if (
|
|
217
|
-
gestures.length === 4 &&
|
|
218
|
-
gestures[0].action === 'press' &&
|
|
219
|
-
gestures[1].action === 'wait' &&
|
|
220
|
-
gestures[2].action === 'moveTo' &&
|
|
221
|
-
gestures[3].action === 'release'
|
|
222
|
-
) {
|
|
223
|
-
let swipeOpts = await this.getSwipeOptions(
|
|
224
|
-
/** @type {import('./types').SwipeAction} */ (gestures)
|
|
225
|
-
);
|
|
226
|
-
return await this.swipe(
|
|
227
|
-
swipeOpts.startX,
|
|
228
|
-
swipeOpts.startY,
|
|
229
|
-
swipeOpts.endX,
|
|
230
|
-
swipeOpts.endY,
|
|
231
|
-
swipeOpts.duration,
|
|
232
|
-
swipeOpts.touchCount,
|
|
233
|
-
swipeOpts.element
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
let actions = /** @type {(import('./types').TouchActionKind|TouchAction)[]} */ (
|
|
237
|
-
_.map(gestures, 'action')
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
if (actions[0] === 'longPress' && actions[1] === 'moveTo' && actions[2] === 'release') {
|
|
241
|
-
// some things are special
|
|
242
|
-
return await this.doTouchDrag(/** @type {import('./types').TouchDragAction} */ (gestures));
|
|
243
|
-
} else {
|
|
244
|
-
if (actions.length === 2) {
|
|
245
|
-
// `press` without a wait is too slow and gets interpretted as a `longPress`
|
|
246
|
-
if (_.head(actions) === 'press' && _.last(actions) === 'release') {
|
|
247
|
-
actions[0] = 'tap';
|
|
248
|
-
gestures[0].action = 'tap';
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// the `longPress` and `tap` methods release on their own
|
|
252
|
-
if (
|
|
253
|
-
(_.head(actions) === 'tap' || _.head(actions) === 'longPress') &&
|
|
254
|
-
_.last(actions) === 'release'
|
|
255
|
-
) {
|
|
256
|
-
gestures.pop();
|
|
257
|
-
actions.pop();
|
|
258
|
-
}
|
|
259
|
-
} else {
|
|
260
|
-
// longpress followed by anything other than release should become a press and wait
|
|
261
|
-
if (actions[0] === 'longPress') {
|
|
262
|
-
actions = ['press', 'wait', ...actions.slice(1)];
|
|
263
|
-
|
|
264
|
-
let press = /** @type {NonReleaseTouchAction} */ (gestures.shift());
|
|
265
|
-
press.action = 'press';
|
|
266
|
-
/** @type {NonReleaseTouchAction} */
|
|
267
|
-
let wait = {
|
|
268
|
-
action: 'wait',
|
|
269
|
-
options: {ms: press.options.duration || 1000},
|
|
270
|
-
};
|
|
271
|
-
delete press.options.duration;
|
|
272
|
-
gestures = [press, wait, ...gestures];
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
let fixedGestures = await this.parseTouch(gestures, false);
|
|
277
|
-
// fix release action then perform all actions
|
|
278
|
-
if (actions[actions.length - 1] === 'release') {
|
|
279
|
-
actions[actions.length - 1] = /** @type {TouchAction} */ (await this.fixRelease(gestures));
|
|
280
|
-
}
|
|
281
|
-
for (let g of fixedGestures) {
|
|
282
|
-
await this.performGesture(g);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
},
|
|
320
|
+
}
|
|
321
|
+
// clients are responsible to use these options correctly
|
|
322
|
+
return {startX, startY, endX, endY, duration, touchCount, element};
|
|
323
|
+
}
|
|
286
324
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
325
|
+
/**
|
|
326
|
+
* @deprecated
|
|
327
|
+
* @this {import('../driver').AndroidDriver}
|
|
328
|
+
* @param {import('./types').TouchAction[]} gestures
|
|
329
|
+
* @param {boolean} [multi]
|
|
330
|
+
* @returns {Promise<import('./types').TouchState[]>}
|
|
331
|
+
*/
|
|
332
|
+
async function parseTouch(gestures, multi) {
|
|
333
|
+
// because multi-touch releases at the end by default
|
|
334
|
+
if (multi && /** @type {TouchAction} */ (_.last(gestures)).action === 'release') {
|
|
335
|
+
gestures.pop();
|
|
336
|
+
}
|
|
292
337
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
} else {
|
|
306
|
-
const {width, height} = await this.getSize(elementId);
|
|
307
|
-
options.x = pos.x + width / 2;
|
|
308
|
-
options.y = pos.y + height / 2;
|
|
309
|
-
}
|
|
310
|
-
let touchStateObject = {
|
|
311
|
-
action: gesture.action,
|
|
312
|
-
options,
|
|
313
|
-
timeOffset: 0.005,
|
|
314
|
-
};
|
|
315
|
-
return touchStateObject;
|
|
338
|
+
let touchStateObjects = await asyncmap(
|
|
339
|
+
gestures,
|
|
340
|
+
async (gesture) => {
|
|
341
|
+
let options = gesture.options || {};
|
|
342
|
+
if (_.includes(['press', 'moveTo', 'tap', 'longPress'], gesture.action)) {
|
|
343
|
+
options.offset = false;
|
|
344
|
+
let elementId = gesture.options.element;
|
|
345
|
+
if (elementId) {
|
|
346
|
+
let pos = await this.getLocationInView(elementId);
|
|
347
|
+
if (gesture.options.x || gesture.options.y) {
|
|
348
|
+
options.x = pos.x + (gesture.options.x || 0);
|
|
349
|
+
options.y = pos.y + (gesture.options.y || 0);
|
|
316
350
|
} else {
|
|
317
|
-
|
|
318
|
-
options.
|
|
319
|
-
|
|
320
|
-
let touchStateObject = {
|
|
321
|
-
action: gesture.action,
|
|
322
|
-
options,
|
|
323
|
-
timeOffset: 0.005,
|
|
324
|
-
};
|
|
325
|
-
return touchStateObject;
|
|
326
|
-
}
|
|
327
|
-
} else {
|
|
328
|
-
let offset = 0.005;
|
|
329
|
-
if (gesture.action === 'wait') {
|
|
330
|
-
options = gesture.options;
|
|
331
|
-
offset = parseInt(gesture.options.ms, 10) / 1000;
|
|
351
|
+
const {width, height} = await this.getSize(elementId);
|
|
352
|
+
options.x = pos.x + width / 2;
|
|
353
|
+
options.y = pos.y + height / 2;
|
|
332
354
|
}
|
|
333
355
|
let touchStateObject = {
|
|
334
356
|
action: gesture.action,
|
|
335
357
|
options,
|
|
336
|
-
timeOffset:
|
|
358
|
+
timeOffset: 0.005,
|
|
337
359
|
};
|
|
338
360
|
return touchStateObject;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
);
|
|
343
|
-
// we need to change the time (which is now an offset)
|
|
344
|
-
// and the position (which may be an offset)
|
|
345
|
-
let prevPos = null,
|
|
346
|
-
time = 0;
|
|
347
|
-
for (let state of touchStateObjects) {
|
|
348
|
-
if (_.isUndefined(state.options.x) && _.isUndefined(state.options.y) && prevPos !== null) {
|
|
349
|
-
// this happens with wait
|
|
350
|
-
state.options.x = prevPos.x;
|
|
351
|
-
state.options.y = prevPos.y;
|
|
352
|
-
}
|
|
353
|
-
if (state.options.offset && prevPos) {
|
|
354
|
-
// the current position is an offset
|
|
355
|
-
state.options.x += prevPos.x;
|
|
356
|
-
state.options.y += prevPos.y;
|
|
357
|
-
}
|
|
358
|
-
delete state.options.offset;
|
|
359
|
-
if (!_.isUndefined(state.options.x) && !_.isUndefined(state.options.y)) {
|
|
360
|
-
prevPos = state.options;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (multi) {
|
|
364
|
-
let timeOffset = state.timeOffset;
|
|
365
|
-
time += timeOffset;
|
|
366
|
-
state.time = androidHelpers.truncateDecimals(time, 3);
|
|
361
|
+
} else {
|
|
362
|
+
options.x = gesture.options.x || 0;
|
|
363
|
+
options.y = gesture.options.y || 0;
|
|
367
364
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
y: state.options.y,
|
|
365
|
+
let touchStateObject = {
|
|
366
|
+
action: gesture.action,
|
|
367
|
+
options,
|
|
368
|
+
timeOffset: 0.005,
|
|
373
369
|
};
|
|
370
|
+
return touchStateObject;
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
let offset = 0.005;
|
|
374
|
+
if (gesture.action === 'wait') {
|
|
375
|
+
options = gesture.options;
|
|
376
|
+
offset = parseInt(gesture.options.ms, 10) / 1000;
|
|
374
377
|
}
|
|
375
|
-
|
|
378
|
+
let touchStateObject = {
|
|
379
|
+
action: gesture.action,
|
|
380
|
+
options,
|
|
381
|
+
timeOffset: offset,
|
|
382
|
+
};
|
|
383
|
+
return touchStateObject;
|
|
376
384
|
}
|
|
377
|
-
|
|
385
|
+
},
|
|
386
|
+
false,
|
|
387
|
+
);
|
|
388
|
+
// we need to change the time (which is now an offset)
|
|
389
|
+
// and the position (which may be an offset)
|
|
390
|
+
let prevPos = null,
|
|
391
|
+
time = 0;
|
|
392
|
+
for (let state of touchStateObjects) {
|
|
393
|
+
if (_.isUndefined(state.options.x) && _.isUndefined(state.options.y) && prevPos !== null) {
|
|
394
|
+
// this happens with wait
|
|
395
|
+
state.options.x = prevPos.x;
|
|
396
|
+
state.options.y = prevPos.y;
|
|
378
397
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
'Use Touch Actions for a single action.'
|
|
388
|
-
);
|
|
398
|
+
if (state.options.offset && prevPos) {
|
|
399
|
+
// the current position is an offset
|
|
400
|
+
state.options.x += prevPos.x;
|
|
401
|
+
state.options.y += prevPos.y;
|
|
402
|
+
}
|
|
403
|
+
delete state.options.offset;
|
|
404
|
+
if (!_.isUndefined(state.options.x) && !_.isUndefined(state.options.y)) {
|
|
405
|
+
prevPos = state.options;
|
|
389
406
|
}
|
|
390
407
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
);
|
|
408
|
+
if (multi) {
|
|
409
|
+
let timeOffset = state.timeOffset;
|
|
410
|
+
time += timeOffset;
|
|
411
|
+
state.time = truncateDecimals(time, 3);
|
|
396
412
|
|
|
397
|
-
|
|
398
|
-
|
|
413
|
+
// multi gestures require 'touch' rather than 'options'
|
|
414
|
+
if (!_.isUndefined(state.options.x) && !_.isUndefined(state.options.y)) {
|
|
415
|
+
state.touch = {
|
|
416
|
+
x: state.options.x,
|
|
417
|
+
y: state.options.y,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
delete state.options;
|
|
421
|
+
}
|
|
422
|
+
delete state.timeOffset;
|
|
423
|
+
}
|
|
424
|
+
return touchStateObjects;
|
|
425
|
+
}
|
|
399
426
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
427
|
+
/**
|
|
428
|
+
* @deprecated
|
|
429
|
+
* @this {import('../driver').AndroidDriver}
|
|
430
|
+
* @param {import('./types').TouchAction[]} gestures
|
|
431
|
+
* @returns {Promise<import('./types').ReleaseTouchAction|undefined>}
|
|
432
|
+
*/
|
|
433
|
+
async function fixRelease(gestures) {
|
|
434
|
+
let release = /** @type {import('./types').ReleaseTouchAction} */ (_.last(gestures));
|
|
435
|
+
// sometimes there are no options
|
|
436
|
+
release.options = release.options || {};
|
|
437
|
+
// nothing to do if release options are already set
|
|
438
|
+
if (release.options.element || (release.options.x && release.options.y)) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
// without coordinates, `release` uses the center of the screen, which,
|
|
442
|
+
// generally speaking, is not what we want
|
|
443
|
+
// therefore: loop backwards and use the last command with an element and/or
|
|
444
|
+
// offset coordinates
|
|
445
|
+
gestures = _.clone(gestures);
|
|
446
|
+
let ref = null;
|
|
447
|
+
for (let gesture of /** @type {NonReleaseTouchAction[]} */ (gestures.reverse())) {
|
|
448
|
+
let opts = gesture.options;
|
|
449
|
+
if (opts.element || (opts.x && opts.y)) {
|
|
450
|
+
ref = gesture;
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (ref) {
|
|
455
|
+
let opts = ref.options;
|
|
456
|
+
if (opts.element) {
|
|
457
|
+
let loc = await this.getLocationInView(opts.element);
|
|
458
|
+
if (opts.x && opts.y) {
|
|
459
|
+
// this is an offset from the element
|
|
460
|
+
release.options = {
|
|
461
|
+
x: loc.x + opts.x,
|
|
462
|
+
y: loc.y + opts.y,
|
|
463
|
+
};
|
|
464
|
+
} else {
|
|
465
|
+
// this is the center of the element
|
|
466
|
+
let size = await this.getSize(opts.element);
|
|
467
|
+
release.options = {
|
|
468
|
+
x: loc.x + size.width / 2,
|
|
469
|
+
y: loc.y + size.height / 2,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
release.options = _.pick(opts, 'x', 'y');
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return release;
|
|
477
|
+
}
|
|
404
478
|
|
|
405
|
-
|
|
479
|
+
/**
|
|
480
|
+
* @deprecated
|
|
481
|
+
* @this {import('../driver').AndroidDriver}
|
|
482
|
+
* @param {import('./types').TouchAction} gesture
|
|
483
|
+
* @returns {Promise<void>}
|
|
484
|
+
*/
|
|
485
|
+
async function performGesture(gesture) {
|
|
486
|
+
try {
|
|
487
|
+
return await this.doTouchAction(gesture.action, gesture.options || {});
|
|
488
|
+
} catch (e) {
|
|
489
|
+
// sometime the element is not available when releasing, retry without it
|
|
490
|
+
if (
|
|
491
|
+
isErrorType(e, errors.NoSuchElementError) &&
|
|
492
|
+
gesture.action === 'release' &&
|
|
493
|
+
gesture.options?.element
|
|
494
|
+
) {
|
|
495
|
+
delete gesture.options.element;
|
|
496
|
+
this.log.debug(`retrying release without element opts: ${gesture.options}.`);
|
|
497
|
+
return await this.doTouchAction(gesture.action, gesture.options || {});
|
|
498
|
+
}
|
|
499
|
+
throw e;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
406
502
|
|
|
407
|
-
|
|
503
|
+
// #endregion
|
|
408
504
|
|
|
409
505
|
/**
|
|
410
506
|
* @typedef {import('appium-adb').ADB} ADB
|