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.
Files changed (261) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/lib/commands/app-management.d.ts +129 -5
  3. package/build/lib/commands/app-management.d.ts.map +1 -1
  4. package/build/lib/commands/app-management.js +433 -128
  5. package/build/lib/commands/app-management.js.map +1 -1
  6. package/build/lib/commands/appearance.d.ts +17 -4
  7. package/build/lib/commands/appearance.d.ts.map +1 -1
  8. package/build/lib/commands/appearance.js +32 -33
  9. package/build/lib/commands/appearance.js.map +1 -1
  10. package/build/lib/commands/context/cache.d.ts +19 -0
  11. package/build/lib/commands/context/cache.d.ts.map +1 -0
  12. package/build/lib/commands/context/cache.js +32 -0
  13. package/build/lib/commands/context/cache.js.map +1 -0
  14. package/build/lib/commands/context/exports.d.ts +141 -0
  15. package/build/lib/commands/context/exports.d.ts.map +1 -0
  16. package/build/lib/commands/context/exports.js +351 -0
  17. package/build/lib/commands/context/exports.js.map +1 -0
  18. package/build/lib/commands/context/helpers.d.ts +98 -0
  19. package/build/lib/commands/context/helpers.d.ts.map +1 -0
  20. package/build/lib/commands/context/helpers.js +715 -0
  21. package/build/lib/commands/context/helpers.js.map +1 -0
  22. package/build/lib/commands/device/common.d.ts +23 -0
  23. package/build/lib/commands/device/common.d.ts.map +1 -0
  24. package/build/lib/commands/device/common.js +230 -0
  25. package/build/lib/commands/device/common.js.map +1 -0
  26. package/build/lib/commands/device/emulator-actions.d.ts +114 -0
  27. package/build/lib/commands/device/emulator-actions.d.ts.map +1 -0
  28. package/build/lib/commands/device/emulator-actions.js +197 -0
  29. package/build/lib/commands/device/emulator-actions.js.map +1 -0
  30. package/build/lib/commands/device/emulator-console.d.ts +7 -0
  31. package/build/lib/commands/device/emulator-console.d.ts.map +1 -0
  32. package/build/lib/commands/device/emulator-console.js +24 -0
  33. package/build/lib/commands/device/emulator-console.js.map +1 -0
  34. package/build/lib/commands/device/utils.d.ts +50 -0
  35. package/build/lib/commands/device/utils.d.ts.map +1 -0
  36. package/build/lib/commands/device/utils.js +238 -0
  37. package/build/lib/commands/device/utils.js.map +1 -0
  38. package/build/lib/commands/deviceidle.d.ts +8 -5
  39. package/build/lib/commands/deviceidle.d.ts.map +1 -1
  40. package/build/lib/commands/deviceidle.js +31 -37
  41. package/build/lib/commands/deviceidle.js.map +1 -1
  42. package/build/lib/commands/element.d.ts +99 -5
  43. package/build/lib/commands/element.d.ts.map +1 -1
  44. package/build/lib/commands/element.js +152 -116
  45. package/build/lib/commands/element.js.map +1 -1
  46. package/build/lib/commands/execute.d.ts +12 -4
  47. package/build/lib/commands/execute.d.ts.map +1 -1
  48. package/build/lib/commands/execute.js +83 -78
  49. package/build/lib/commands/execute.js.map +1 -1
  50. package/build/lib/commands/file-actions.d.ts +42 -5
  51. package/build/lib/commands/file-actions.d.ts.map +1 -1
  52. package/build/lib/commands/file-actions.js +230 -194
  53. package/build/lib/commands/file-actions.js.map +1 -1
  54. package/build/lib/commands/find.d.ts +5 -4
  55. package/build/lib/commands/find.d.ts.map +1 -1
  56. package/build/lib/commands/find.js +7 -10
  57. package/build/lib/commands/find.js.map +1 -1
  58. package/build/lib/commands/geolocation.d.ts +45 -0
  59. package/build/lib/commands/geolocation.d.ts.map +1 -0
  60. package/build/lib/commands/geolocation.js +182 -0
  61. package/build/lib/commands/geolocation.js.map +1 -0
  62. package/build/lib/commands/ime.d.ts +25 -5
  63. package/build/lib/commands/ime.d.ts.map +1 -1
  64. package/build/lib/commands/ime.js +59 -42
  65. package/build/lib/commands/ime.js.map +1 -1
  66. package/build/lib/commands/intent.d.ts +56 -5
  67. package/build/lib/commands/intent.d.ts.map +1 -1
  68. package/build/lib/commands/intent.js +135 -83
  69. package/build/lib/commands/intent.js.map +1 -1
  70. package/build/lib/commands/keyboard.d.ts +58 -4
  71. package/build/lib/commands/keyboard.d.ts.map +1 -1
  72. package/build/lib/commands/keyboard.js +119 -17
  73. package/build/lib/commands/keyboard.js.map +1 -1
  74. package/build/lib/commands/lock/exports.d.ts +301 -0
  75. package/build/lib/commands/lock/exports.d.ts.map +1 -0
  76. package/build/lib/commands/lock/exports.js +121 -0
  77. package/build/lib/commands/lock/exports.js.map +1 -0
  78. package/build/lib/commands/lock/helpers.d.ts +349 -0
  79. package/build/lib/commands/lock/helpers.d.ts.map +1 -0
  80. package/build/lib/commands/lock/helpers.js +375 -0
  81. package/build/lib/commands/lock/helpers.js.map +1 -0
  82. package/build/lib/commands/log.d.ts +59 -5
  83. package/build/lib/commands/log.d.ts.map +1 -1
  84. package/build/lib/commands/log.js +150 -140
  85. package/build/lib/commands/log.js.map +1 -1
  86. package/build/lib/commands/media-projection.d.ts +16 -5
  87. package/build/lib/commands/media-projection.d.ts.map +1 -1
  88. package/build/lib/commands/media-projection.js +69 -58
  89. package/build/lib/commands/media-projection.js.map +1 -1
  90. package/build/lib/commands/memory.d.ts +9 -5
  91. package/build/lib/commands/memory.d.ts.map +1 -1
  92. package/build/lib/commands/memory.js +19 -24
  93. package/build/lib/commands/memory.js.map +1 -1
  94. package/build/lib/commands/misc.d.ts +42 -0
  95. package/build/lib/commands/misc.d.ts.map +1 -0
  96. package/build/lib/commands/misc.js +100 -0
  97. package/build/lib/commands/misc.js.map +1 -0
  98. package/build/lib/commands/network.d.ts +61 -5
  99. package/build/lib/commands/network.d.ts.map +1 -1
  100. package/build/lib/commands/network.js +196 -189
  101. package/build/lib/commands/network.js.map +1 -1
  102. package/build/lib/commands/performance.d.ts +67 -27
  103. package/build/lib/commands/performance.d.ts.map +1 -1
  104. package/build/lib/commands/performance.js +105 -80
  105. package/build/lib/commands/performance.js.map +1 -1
  106. package/build/lib/commands/permissions.d.ts +12 -6
  107. package/build/lib/commands/permissions.d.ts.map +1 -1
  108. package/build/lib/commands/permissions.js +65 -62
  109. package/build/lib/commands/permissions.js.map +1 -1
  110. package/build/lib/commands/recordscreen.d.ts +44 -5
  111. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  112. package/build/lib/commands/recordscreen.js +131 -126
  113. package/build/lib/commands/recordscreen.js.map +1 -1
  114. package/build/lib/commands/resources.d.ts +16 -0
  115. package/build/lib/commands/resources.d.ts.map +1 -0
  116. package/build/lib/commands/resources.js +91 -0
  117. package/build/lib/commands/resources.js.map +1 -0
  118. package/build/lib/commands/shell.d.ts +8 -5
  119. package/build/lib/commands/shell.d.ts.map +1 -1
  120. package/build/lib/commands/shell.js +29 -33
  121. package/build/lib/commands/shell.js.map +1 -1
  122. package/build/lib/commands/streamscreen.d.ts +34 -6
  123. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  124. package/build/lib/commands/streamscreen.js +166 -162
  125. package/build/lib/commands/streamscreen.js.map +1 -1
  126. package/build/lib/commands/system-bars.d.ts +18 -13
  127. package/build/lib/commands/system-bars.d.ts.map +1 -1
  128. package/build/lib/commands/system-bars.js +68 -64
  129. package/build/lib/commands/system-bars.js.map +1 -1
  130. package/build/lib/commands/time.d.ts +14 -0
  131. package/build/lib/commands/time.d.ts.map +1 -0
  132. package/build/lib/commands/time.js +39 -0
  133. package/build/lib/commands/time.js.map +1 -0
  134. package/build/lib/commands/touch.d.ts +99 -6
  135. package/build/lib/commands/touch.d.ts.map +1 -1
  136. package/build/lib/commands/touch.js +399 -280
  137. package/build/lib/commands/touch.js.map +1 -1
  138. package/build/lib/commands/types.d.ts +110 -2
  139. package/build/lib/commands/types.d.ts.map +1 -1
  140. package/build/lib/doctor/checks.d.ts.map +1 -1
  141. package/build/lib/doctor/checks.js +4 -4
  142. package/build/lib/doctor/checks.js.map +1 -1
  143. package/build/lib/driver.d.ts +224 -27
  144. package/build/lib/driver.d.ts.map +1 -1
  145. package/build/lib/driver.js +232 -7
  146. package/build/lib/driver.js.map +1 -1
  147. package/build/lib/index.d.ts +1 -4
  148. package/build/lib/index.d.ts.map +1 -1
  149. package/build/lib/index.js +1 -13
  150. package/build/lib/index.js.map +1 -1
  151. package/build/lib/logger.js.map +1 -1
  152. package/build/lib/method-map.d.ts +0 -23
  153. package/build/lib/method-map.d.ts.map +1 -1
  154. package/build/lib/method-map.js +0 -11
  155. package/build/lib/method-map.js.map +1 -1
  156. package/build/lib/utils.d.ts +12 -0
  157. package/build/lib/utils.d.ts.map +1 -1
  158. package/build/lib/utils.js +38 -2
  159. package/build/lib/utils.js.map +1 -1
  160. package/lib/commands/app-management.js +470 -145
  161. package/lib/commands/appearance.js +29 -36
  162. package/lib/commands/context/cache.js +29 -0
  163. package/lib/commands/context/exports.js +379 -0
  164. package/lib/commands/context/helpers.js +802 -0
  165. package/lib/commands/device/common.js +264 -0
  166. package/lib/commands/device/emulator-actions.js +194 -0
  167. package/lib/commands/device/emulator-console.js +24 -0
  168. package/lib/commands/device/utils.js +285 -0
  169. package/lib/commands/deviceidle.js +31 -44
  170. package/lib/commands/element.js +149 -142
  171. package/lib/commands/execute.js +86 -87
  172. package/lib/commands/file-actions.js +249 -222
  173. package/lib/commands/find.ts +13 -19
  174. package/lib/commands/geolocation.js +179 -0
  175. package/lib/commands/ime.js +53 -45
  176. package/lib/commands/intent.js +149 -91
  177. package/lib/commands/keyboard.js +114 -17
  178. package/lib/commands/lock/exports.js +139 -0
  179. package/lib/commands/lock/helpers.js +379 -0
  180. package/lib/commands/log.js +170 -166
  181. package/lib/commands/media-projection.js +75 -70
  182. package/lib/commands/memory.js +17 -29
  183. package/lib/commands/misc.js +94 -0
  184. package/lib/commands/network.js +209 -223
  185. package/lib/commands/performance.js +88 -73
  186. package/lib/commands/permissions.js +83 -84
  187. package/lib/commands/recordscreen.js +171 -170
  188. package/lib/commands/resources.js +96 -0
  189. package/lib/commands/shell.js +28 -42
  190. package/lib/commands/streamscreen.js +207 -206
  191. package/lib/commands/system-bars.js +76 -77
  192. package/lib/commands/time.js +36 -0
  193. package/lib/commands/touch.js +442 -346
  194. package/lib/commands/types.ts +123 -2
  195. package/lib/doctor/checks.js +24 -16
  196. package/lib/driver.ts +454 -12
  197. package/lib/index.ts +1 -13
  198. package/lib/logger.js +1 -1
  199. package/lib/method-map.js +0 -11
  200. package/lib/utils.js +40 -3
  201. package/package.json +1 -1
  202. package/build/lib/commands/actions.d.ts +0 -8
  203. package/build/lib/commands/actions.d.ts.map +0 -1
  204. package/build/lib/commands/actions.js +0 -207
  205. package/build/lib/commands/actions.js.map +0 -1
  206. package/build/lib/commands/alert.d.ts +0 -8
  207. package/build/lib/commands/alert.d.ts.map +0 -1
  208. package/build/lib/commands/alert.js +0 -29
  209. package/build/lib/commands/alert.js.map +0 -1
  210. package/build/lib/commands/context.d.ts +0 -10
  211. package/build/lib/commands/context.d.ts.map +0 -1
  212. package/build/lib/commands/context.js +0 -431
  213. package/build/lib/commands/context.js.map +0 -1
  214. package/build/lib/commands/emu-console.d.ts +0 -7
  215. package/build/lib/commands/emu-console.d.ts.map +0 -1
  216. package/build/lib/commands/emu-console.js +0 -27
  217. package/build/lib/commands/emu-console.js.map +0 -1
  218. package/build/lib/commands/general.d.ts +0 -9
  219. package/build/lib/commands/general.d.ts.map +0 -1
  220. package/build/lib/commands/general.js +0 -293
  221. package/build/lib/commands/general.js.map +0 -1
  222. package/build/lib/commands/index.d.ts +0 -28
  223. package/build/lib/commands/index.d.ts.map +0 -1
  224. package/build/lib/commands/index.js +0 -57
  225. package/build/lib/commands/index.js.map +0 -1
  226. package/build/lib/commands/mixins.d.ts +0 -747
  227. package/build/lib/commands/mixins.d.ts.map +0 -1
  228. package/build/lib/commands/mixins.js +0 -19
  229. package/build/lib/commands/mixins.js.map +0 -1
  230. package/build/lib/helpers/android.d.ts +0 -163
  231. package/build/lib/helpers/android.d.ts.map +0 -1
  232. package/build/lib/helpers/android.js +0 -818
  233. package/build/lib/helpers/android.js.map +0 -1
  234. package/build/lib/helpers/index.d.ts +0 -7
  235. package/build/lib/helpers/index.d.ts.map +0 -1
  236. package/build/lib/helpers/index.js +0 -29
  237. package/build/lib/helpers/index.js.map +0 -1
  238. package/build/lib/helpers/types.d.ts +0 -122
  239. package/build/lib/helpers/types.d.ts.map +0 -1
  240. package/build/lib/helpers/types.js +0 -3
  241. package/build/lib/helpers/types.js.map +0 -1
  242. package/build/lib/helpers/unlock.d.ts +0 -32
  243. package/build/lib/helpers/unlock.d.ts.map +0 -1
  244. package/build/lib/helpers/unlock.js +0 -273
  245. package/build/lib/helpers/unlock.js.map +0 -1
  246. package/build/lib/helpers/webview.d.ts +0 -74
  247. package/build/lib/helpers/webview.d.ts.map +0 -1
  248. package/build/lib/helpers/webview.js +0 -448
  249. package/build/lib/helpers/webview.js.map +0 -1
  250. package/lib/commands/actions.js +0 -244
  251. package/lib/commands/alert.js +0 -34
  252. package/lib/commands/context.js +0 -507
  253. package/lib/commands/emu-console.js +0 -31
  254. package/lib/commands/general.js +0 -343
  255. package/lib/commands/index.ts +0 -54
  256. package/lib/commands/mixins.ts +0 -976
  257. package/lib/helpers/android.ts +0 -1153
  258. package/lib/helpers/index.ts +0 -6
  259. package/lib/helpers/types.ts +0 -136
  260. package/lib/helpers/unlock.ts +0 -329
  261. package/lib/helpers/webview.ts +0 -610
@@ -1,15 +1,248 @@
1
- // @ts-check
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
- * @type {import('./mixins').TouchMixin & ThisType<import('../driver').AndroidDriver>}
45
- * @satisfies {import('@appium/types').ExternalDriver}
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
- const TouchMixin = {
48
- async doTouchAction(action, opts = {}) {
49
- const {element, x, y, count, ms, duration} = opts;
50
- // parseTouch precalculates absolute element positions
51
- // so there is no need to pass `element` to the affected gestures
52
- switch (action) {
53
- case 'tap':
54
- return await this.tap('', x, y, count);
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
- // `drag` will take care of whether there is an element or not at that level
110
- return await this.drag(
111
- startX,
112
- startY,
113
- endX,
114
- endY,
115
- duration,
116
- 1,
117
- longPress.options.element,
118
- moveTo.options.element
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
- // without coordinates, `release` uses the center of the screen, which,
131
- // generally speaking, is not what we want
132
- // therefore: loop backwards and use the last command with an element and/or
133
- // offset coordinates
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
- async parseTouch(gestures, multi) {
288
- // because multi-touch releases at the end by default
289
- if (multi && /** @type {TouchAction} */ (_.last(gestures)).action === 'release') {
290
- gestures.pop();
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
- let touchStateObjects = await asyncmap(
294
- gestures,
295
- async (gesture) => {
296
- let options = gesture.options || {};
297
- if (_.includes(['press', 'moveTo', 'tap', 'longPress'], gesture.action)) {
298
- options.offset = false;
299
- let elementId = gesture.options.element;
300
- if (elementId) {
301
- let pos = await this.getLocationInView(elementId);
302
- if (gesture.options.x || gesture.options.y) {
303
- options.x = pos.x + (gesture.options.x || 0);
304
- options.y = pos.y + (gesture.options.y || 0);
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
- options.x = gesture.options.x || 0;
318
- options.y = gesture.options.y || 0;
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: offset,
358
+ timeOffset: 0.005,
337
359
  };
338
360
  return touchStateObject;
339
- }
340
- },
341
- false
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
- // multi gestures require 'touch' rather than 'options'
369
- if (!_.isUndefined(state.options.x) && !_.isUndefined(state.options.y)) {
370
- state.touch = {
371
- x: state.options.x,
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
- delete state.options;
378
+ let touchStateObject = {
379
+ action: gesture.action,
380
+ options,
381
+ timeOffset: offset,
382
+ };
383
+ return touchStateObject;
376
384
  }
377
- delete state.timeOffset;
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
- return touchStateObjects;
380
- },
381
-
382
- async performMultiAction(actions, elementId) {
383
- // Android needs at least two actions to be able to perform a multi pointer gesture
384
- if (actions.length === 1) {
385
- throw new Error(
386
- 'Multi Pointer Gestures need at least two actions. ' +
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
- const states = await asyncmap(
392
- actions,
393
- async (action) => await this.parseTouch(action, true),
394
- false
395
- );
408
+ if (multi) {
409
+ let timeOffset = state.timeOffset;
410
+ time += timeOffset;
411
+ state.time = truncateDecimals(time, 3);
396
412
 
397
- return await this.doPerformMultiAction(elementId, states);
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
- async doPerformMultiAction(elementId, states) {
401
- throw new errors.NotImplementedError('Not implemented');
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
- mixin(TouchMixin);
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
- export default TouchMixin;
503
+ // #endregion
408
504
 
409
505
  /**
410
506
  * @typedef {import('appium-adb').ADB} ADB