appium-android-driver 5.14.7 → 6.0.1

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 (210) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/lib/commands/actions.d.ts +6 -224
  3. package/build/lib/commands/actions.d.ts.map +1 -1
  4. package/build/lib/commands/actions.js +306 -405
  5. package/build/lib/commands/actions.js.map +1 -1
  6. package/build/lib/commands/alert.d.ts +7 -9
  7. package/build/lib/commands/alert.d.ts.map +1 -1
  8. package/build/lib/commands/alert.js +24 -18
  9. package/build/lib/commands/alert.js.map +1 -1
  10. package/build/lib/commands/app-management.d.ts +7 -313
  11. package/build/lib/commands/app-management.d.ts.map +1 -1
  12. package/build/lib/commands/app-management.js +135 -293
  13. package/build/lib/commands/app-management.js.map +1 -1
  14. package/build/lib/commands/context.d.ts +8 -92
  15. package/build/lib/commands/context.d.ts.map +1 -1
  16. package/build/lib/commands/context.js +381 -439
  17. package/build/lib/commands/context.js.map +1 -1
  18. package/build/lib/commands/element.d.ts +8 -35
  19. package/build/lib/commands/element.d.ts.map +1 -1
  20. package/build/lib/commands/element.js +153 -136
  21. package/build/lib/commands/element.js.map +1 -1
  22. package/build/lib/commands/emu-console.d.ts +6 -48
  23. package/build/lib/commands/emu-console.d.ts.map +1 -1
  24. package/build/lib/commands/emu-console.js +19 -34
  25. package/build/lib/commands/emu-console.js.map +1 -1
  26. package/build/lib/commands/execute.d.ts +6 -5
  27. package/build/lib/commands/execute.d.ts.map +1 -1
  28. package/build/lib/commands/execute.js +77 -66
  29. package/build/lib/commands/execute.js.map +1 -1
  30. package/build/lib/commands/file-actions.d.ts +7 -128
  31. package/build/lib/commands/file-actions.d.ts.map +1 -1
  32. package/build/lib/commands/file-actions.js +183 -219
  33. package/build/lib/commands/file-actions.js.map +1 -1
  34. package/build/lib/commands/find.d.ts +8 -12
  35. package/build/lib/commands/find.d.ts.map +1 -1
  36. package/build/lib/commands/find.js +19 -23
  37. package/build/lib/commands/find.js.map +1 -1
  38. package/build/lib/commands/general.d.ts +9 -132
  39. package/build/lib/commands/general.d.ts.map +1 -1
  40. package/build/lib/commands/general.js +281 -312
  41. package/build/lib/commands/general.js.map +1 -1
  42. package/build/lib/commands/ime.d.ts +7 -10
  43. package/build/lib/commands/ime.d.ts.map +1 -1
  44. package/build/lib/commands/ime.js +47 -35
  45. package/build/lib/commands/ime.js.map +1 -1
  46. package/build/lib/commands/index.d.ts +27 -2
  47. package/build/lib/commands/index.d.ts.map +1 -1
  48. package/build/lib/commands/index.js +41 -19
  49. package/build/lib/commands/index.js.map +1 -1
  50. package/build/lib/commands/intent.d.ts +7 -417
  51. package/build/lib/commands/intent.d.ts.map +1 -1
  52. package/build/lib/commands/intent.js +104 -216
  53. package/build/lib/commands/intent.js.map +1 -1
  54. package/build/lib/commands/keyboard.d.ts +6 -5
  55. package/build/lib/commands/keyboard.d.ts.map +1 -1
  56. package/build/lib/commands/keyboard.js +16 -8
  57. package/build/lib/commands/keyboard.js.map +1 -1
  58. package/build/lib/commands/log.d.ts +7 -44
  59. package/build/lib/commands/log.d.ts.map +1 -1
  60. package/build/lib/commands/log.js +146 -108
  61. package/build/lib/commands/log.js.map +1 -1
  62. package/build/lib/commands/media-projection.d.ts +7 -143
  63. package/build/lib/commands/media-projection.d.ts.map +1 -1
  64. package/build/lib/commands/media-projection.js +113 -140
  65. package/build/lib/commands/media-projection.js.map +1 -1
  66. package/build/lib/commands/mixins.d.ts +740 -0
  67. package/build/lib/commands/mixins.d.ts.map +1 -0
  68. package/build/lib/commands/mixins.js +19 -0
  69. package/build/lib/commands/mixins.js.map +1 -0
  70. package/build/lib/commands/network.d.ts +7 -138
  71. package/build/lib/commands/network.d.ts.map +1 -1
  72. package/build/lib/commands/network.js +212 -254
  73. package/build/lib/commands/network.js.map +1 -1
  74. package/build/lib/commands/performance.d.ts +24 -70
  75. package/build/lib/commands/performance.d.ts.map +1 -1
  76. package/build/lib/commands/performance.js +144 -100
  77. package/build/lib/commands/performance.js.map +1 -1
  78. package/build/lib/commands/permissions.d.ts +8 -92
  79. package/build/lib/commands/permissions.d.ts.map +1 -1
  80. package/build/lib/commands/permissions.js +75 -87
  81. package/build/lib/commands/permissions.js.map +1 -1
  82. package/build/lib/commands/recordscreen.d.ts +7 -193
  83. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  84. package/build/lib/commands/recordscreen.js +151 -182
  85. package/build/lib/commands/recordscreen.js.map +1 -1
  86. package/build/lib/commands/shell.d.ts +7 -7
  87. package/build/lib/commands/shell.d.ts.map +1 -1
  88. package/build/lib/commands/shell.js +40 -33
  89. package/build/lib/commands/shell.js.map +1 -1
  90. package/build/lib/commands/streamscreen.d.ts +9 -103
  91. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  92. package/build/lib/commands/streamscreen.js +261 -218
  93. package/build/lib/commands/streamscreen.js.map +1 -1
  94. package/build/lib/commands/system-bars.d.ts +22 -90
  95. package/build/lib/commands/system-bars.d.ts.map +1 -1
  96. package/build/lib/commands/system-bars.js +76 -74
  97. package/build/lib/commands/system-bars.js.map +1 -1
  98. package/build/lib/commands/touch.d.ts +10 -29
  99. package/build/lib/commands/touch.d.ts.map +1 -1
  100. package/build/lib/commands/touch.js +301 -285
  101. package/build/lib/commands/touch.js.map +1 -1
  102. package/build/lib/commands/types.d.ts +978 -0
  103. package/build/lib/commands/types.d.ts.map +1 -0
  104. package/build/lib/commands/types.js +3 -0
  105. package/build/lib/commands/types.js.map +1 -0
  106. package/build/lib/constraints.d.ts +291 -0
  107. package/build/lib/constraints.d.ts.map +1 -0
  108. package/build/lib/{desired-caps.js → constraints.js} +103 -102
  109. package/build/lib/constraints.js.map +1 -0
  110. package/build/lib/driver.d.ts +68 -37
  111. package/build/lib/driver.d.ts.map +1 -1
  112. package/build/lib/driver.js +123 -80
  113. package/build/lib/driver.js.map +1 -1
  114. package/build/lib/helpers/android.d.ts +164 -0
  115. package/build/lib/helpers/android.d.ts.map +1 -0
  116. package/build/lib/helpers/android.js +819 -0
  117. package/build/lib/helpers/android.js.map +1 -0
  118. package/build/lib/helpers/index.d.ts +7 -0
  119. package/build/lib/helpers/index.d.ts.map +1 -0
  120. package/build/lib/helpers/index.js +29 -0
  121. package/build/lib/helpers/index.js.map +1 -0
  122. package/build/lib/helpers/types.d.ts +121 -0
  123. package/build/lib/helpers/types.d.ts.map +1 -0
  124. package/build/lib/helpers/types.js +3 -0
  125. package/build/lib/helpers/types.js.map +1 -0
  126. package/build/lib/helpers/unlock.d.ts +32 -0
  127. package/build/lib/helpers/unlock.d.ts.map +1 -0
  128. package/build/lib/helpers/unlock.js +273 -0
  129. package/build/lib/helpers/unlock.js.map +1 -0
  130. package/build/lib/helpers/webview.d.ts +74 -0
  131. package/build/lib/helpers/webview.d.ts.map +1 -0
  132. package/build/lib/helpers/webview.js +421 -0
  133. package/build/lib/helpers/webview.js.map +1 -0
  134. package/build/lib/index.d.ts +9 -0
  135. package/build/lib/index.d.ts.map +1 -0
  136. package/build/lib/index.js +37 -0
  137. package/build/lib/index.js.map +1 -0
  138. package/build/lib/method-map.d.ts +0 -8
  139. package/build/lib/method-map.d.ts.map +1 -1
  140. package/build/lib/method-map.js +63 -74
  141. package/build/lib/method-map.js.map +1 -1
  142. package/build/lib/stubs.d.ts +0 -1
  143. package/build/lib/stubs.d.ts.map +1 -1
  144. package/build/lib/stubs.js +1 -0
  145. package/build/lib/stubs.js.map +1 -1
  146. package/build/lib/utils.d.ts +1 -1
  147. package/build/lib/utils.d.ts.map +1 -1
  148. package/lib/commands/actions.js +351 -464
  149. package/lib/commands/alert.js +27 -17
  150. package/lib/commands/app-management.js +156 -314
  151. package/lib/commands/context.js +457 -441
  152. package/lib/commands/element.js +201 -157
  153. package/lib/commands/emu-console.js +25 -45
  154. package/lib/commands/execute.js +106 -90
  155. package/lib/commands/file-actions.js +222 -240
  156. package/lib/commands/find.ts +103 -0
  157. package/lib/commands/general.js +327 -339
  158. package/lib/commands/ime.js +50 -34
  159. package/lib/commands/{index.js → index.ts} +20 -24
  160. package/lib/commands/intent.js +108 -249
  161. package/lib/commands/keyboard.js +20 -8
  162. package/lib/commands/log.js +172 -116
  163. package/lib/commands/media-projection.js +134 -161
  164. package/lib/commands/mixins.ts +966 -0
  165. package/lib/commands/network.js +252 -281
  166. package/lib/commands/performance.js +203 -132
  167. package/lib/commands/permissions.js +108 -109
  168. package/lib/commands/recordscreen.js +212 -209
  169. package/lib/commands/shell.js +51 -40
  170. package/lib/commands/streamscreen.js +355 -289
  171. package/lib/commands/system-bars.js +92 -83
  172. package/lib/commands/touch.js +357 -294
  173. package/lib/commands/types.ts +1097 -0
  174. package/lib/{desired-caps.js → constraints.ts} +106 -103
  175. package/lib/{driver.js → driver.ts} +278 -132
  176. package/lib/helpers/android.ts +1143 -0
  177. package/lib/helpers/index.ts +6 -0
  178. package/lib/helpers/types.ts +134 -0
  179. package/lib/helpers/unlock.ts +329 -0
  180. package/lib/helpers/webview.ts +582 -0
  181. package/lib/index.ts +18 -0
  182. package/lib/method-map.js +87 -98
  183. package/lib/stubs.ts +0 -1
  184. package/package.json +26 -19
  185. package/build/index.js +0 -51
  186. package/build/lib/android-helpers.d.ts +0 -136
  187. package/build/lib/android-helpers.d.ts.map +0 -1
  188. package/build/lib/android-helpers.js +0 -855
  189. package/build/lib/android-helpers.js.map +0 -1
  190. package/build/lib/commands/coverage.d.ts +0 -5
  191. package/build/lib/commands/coverage.d.ts.map +0 -1
  192. package/build/lib/commands/coverage.js +0 -19
  193. package/build/lib/commands/coverage.js.map +0 -1
  194. package/build/lib/desired-caps.d.ts +0 -353
  195. package/build/lib/desired-caps.d.ts.map +0 -1
  196. package/build/lib/desired-caps.js.map +0 -1
  197. package/build/lib/unlock-helpers.d.ts +0 -38
  198. package/build/lib/unlock-helpers.d.ts.map +0 -1
  199. package/build/lib/unlock-helpers.js +0 -266
  200. package/build/lib/unlock-helpers.js.map +0 -1
  201. package/build/lib/webview-helpers.d.ts +0 -224
  202. package/build/lib/webview-helpers.d.ts.map +0 -1
  203. package/build/lib/webview-helpers.js +0 -528
  204. package/build/lib/webview-helpers.js.map +0 -1
  205. package/index.js +0 -24
  206. package/lib/android-helpers.js +0 -983
  207. package/lib/commands/coverage.js +0 -18
  208. package/lib/commands/find.js +0 -82
  209. package/lib/unlock-helpers.js +0 -278
  210. package/lib/webview-helpers.js +0 -602
@@ -1,505 +1,392 @@
1
- import androidHelpers from '../android-helpers';
2
- import {fs, util, tempDir, imageUtil} from '@appium/support';
3
- import path from 'path';
1
+ // @ts-check
2
+
3
+ import {fs, tempDir, util, imageUtil} from '@appium/support';
4
4
  import B from 'bluebird';
5
+ import path from 'path';
5
6
  import {exec} from 'teen_process';
7
+ import {AndroidHelpers} from '../helpers';
6
8
  import {requireArgs} from '../utils';
9
+ import {mixin} from './mixins';
7
10
 
8
11
  const swipeStepsPerSec = 28;
9
12
  const dragStepsPerSec = 40;
10
13
 
11
- const commands = {};
12
- const helpers = {};
13
- const extensions = {};
14
-
15
- commands.keyevent = async function keyevent(keycode, metastate = null) {
16
- // TODO deprecate keyevent; currently wd only implements keyevent
17
- this.log.warn('keyevent will be deprecated use pressKeyCode');
18
- return await this.pressKeyCode(keycode, metastate);
19
- };
20
-
21
- commands.pressKeyCode = async function pressKeyCode(keycode, metastate = null) {
22
- return await this.bootstrap.sendAction('pressKeyCode', {keycode, metastate});
23
- };
24
-
25
- commands.longPressKeyCode = async function longPressKeyCode(keycode, metastate = null) {
26
- return await this.bootstrap.sendAction('longPressKeyCode', {keycode, metastate});
27
- };
28
-
29
- commands.getOrientation = async function getOrientation() {
30
- let params = {
31
- naturalOrientation: !!this.opts.androidNaturalOrientation,
32
- };
33
- let orientation = await this.bootstrap.sendAction('orientation', params);
34
- return orientation.toUpperCase();
35
- };
36
-
37
- commands.setOrientation = async function setOrientation(orientation) {
38
- orientation = orientation.toUpperCase();
39
- let params = {
40
- orientation,
41
- naturalOrientation: !!this.opts.androidNaturalOrientation,
42
- };
43
- return await this.bootstrap.sendAction('orientation', params);
44
- };
45
-
46
- commands.fakeFlick = async function fakeFlick(xSpeed, ySpeed) {
47
- return await this.bootstrap.sendAction('flick', {xSpeed, ySpeed});
48
- };
49
-
50
- commands.fakeFlickElement = async function fakeFlickElement(elementId, xoffset, yoffset, speed) {
51
- let params = {xoffset, yoffset, speed, elementId};
52
- return await this.bootstrap.sendAction('element:flick', params);
53
- };
54
-
55
- commands.swipe = async function swipe(startX, startY, endX, endY, duration, touchCount, elId) {
56
- if (startX === 'null') {
57
- startX = 0.5;
58
- }
59
- if (startY === 'null') {
60
- startY = 0.5;
61
- }
62
- let swipeOpts = {startX, startY, endX, endY, steps: Math.round(duration * swipeStepsPerSec)};
63
- // going the long way and checking for undefined and null since
64
- // we can't be assured `elId` is a string and not an int
65
- if (util.hasValue(elId)) {
66
- swipeOpts.elementId = elId;
67
- }
68
- return await this.doSwipe(swipeOpts);
69
- };
70
-
71
- commands.doSwipe = async function doSwipe(swipeOpts) {
72
- if (util.hasValue(swipeOpts.elementId)) {
73
- return await this.bootstrap.sendAction('element:swipe', swipeOpts);
74
- } else {
75
- return await this.bootstrap.sendAction('swipe', swipeOpts);
76
- }
77
- };
78
-
79
- commands.pinchClose = async function pinchClose(
80
- startX,
81
- startY,
82
- endX,
83
- endY,
84
- duration,
85
- percent,
86
- steps,
87
- elId
88
- ) {
89
- let pinchOpts = {
90
- direction: 'in',
91
- elementId: elId,
92
- percent,
93
- steps,
94
- };
95
- return await this.bootstrap.sendAction('element:pinch', pinchOpts);
96
- };
97
-
98
- commands.pinchOpen = async function pinchOpen(
99
- startX,
100
- startY,
101
- endX,
102
- endY,
103
- duration,
104
- percent,
105
- steps,
106
- elId
107
- ) {
108
- let pinchOpts = {direction: 'out', elementId: elId, percent, steps};
109
- return await this.bootstrap.sendAction('element:pinch', pinchOpts);
110
- };
111
-
112
- commands.flick = async function flick(element, xSpeed, ySpeed, xOffset, yOffset, speed) {
113
- if (element) {
114
- await this.fakeFlickElement(element, xOffset, yOffset, speed);
115
- } else {
116
- await this.fakeFlick(xSpeed, ySpeed);
117
- }
118
- };
119
-
120
- commands.drag = async function drag(
121
- startX,
122
- startY,
123
- endX,
124
- endY,
125
- duration,
126
- touchCount,
127
- elementId,
128
- destElId
129
- ) {
130
- let dragOpts = {
131
- elementId,
132
- destElId,
133
- startX,
134
- startY,
135
- endX,
136
- endY,
137
- steps: Math.round(duration * dragStepsPerSec),
138
- };
139
- return await this.doDrag(dragOpts);
140
- };
141
-
142
- commands.doDrag = async function doDrag(dragOpts) {
143
- if (util.hasValue(dragOpts.elementId)) {
144
- return await this.bootstrap.sendAction('element:drag', dragOpts);
145
- } else {
146
- return await this.bootstrap.sendAction('drag', dragOpts);
147
- }
148
- };
149
-
150
- /**
151
- * @typedef {Object} LockOptions
152
- * @property {number?} seconds The number to keep the locked.
153
- * 0 or empty value will keep the device locked.
154
- */
155
-
156
- /**
157
- * Lock the device (and optionally unlock it after a certain amount of time).
158
-
159
- * @param {LockOptions} opts
160
- * @throws {Error} if lock or unlock operation fails
161
- */
162
-
163
- commands.mobileLock = async function mobileLock(opts = {}) {
164
- const {seconds} = opts;
165
- return await this.lock(seconds);
166
- };
167
-
168
- commands.lock = async function lock(seconds) {
169
- await this.adb.lock();
170
- if (isNaN(seconds)) {
171
- return;
172
- }
173
-
174
- const floatSeconds = parseFloat(seconds);
175
- if (floatSeconds <= 0) {
176
- return;
177
- }
178
- await B.delay(1000 * floatSeconds);
179
- await this.unlock();
180
- };
181
-
182
- commands.isLocked = async function isLocked() {
183
- return await this.adb.isScreenLocked();
184
- };
185
-
186
- commands.unlock = async function unlock() {
187
- return await androidHelpers.unlock(this, this.adb, this.caps);
188
- };
189
-
190
- commands.openNotifications = async function openNotifications() {
191
- return await this.bootstrap.sendAction('openNotification');
192
- };
193
-
194
- commands.setLocation = async function setLocation(latitude, longitude) {
195
- return await this.adb.sendTelnetCommand(`geo fix ${longitude} ${latitude}`);
196
- };
197
-
198
- commands.fingerprint = async function fingerprint(fingerprintId) {
199
- if (!this.isEmulator()) {
200
- this.log.errorAndThrow('fingerprint method is only available for emulators');
201
- }
202
- await this.adb.fingerprint(fingerprintId);
203
- };
204
-
205
- /**
206
- * @typedef {Object} FingerprintOpts
207
- * @param {string|number} fingerprintId The value is the finger_id for the finger that
208
- * was "scanned". It is a unique integer that you assign for each virtual fingerprint.
209
- * When the app is running you can run this same command each time the
210
- * emulator prompts you for a fingerprint, you can run the adb command and pass it
211
- * the finger_id to simulate the fingerprint scan.
212
- */
213
-
214
14
  /**
215
- * Emulate fingerprint on Android Emulator.
216
- * Only works on API 23+
217
- *
218
- * @param {FingerprintOpts} opts
15
+ * @type {import('./mixins').ActionsMixin & ThisType<import('../driver').AndroidDriver>}
16
+ * @satisfies {import('@appium/types').ExternalDriver}
219
17
  */
220
- commands.mobileFingerprint = async function mobileFingerprint(opts = {}) {
221
- const {fingerprintId} = requireArgs('fingerprintId', opts);
222
- await this.fingerprint(fingerprintId);
223
- };
224
-
225
- commands.sendSMS = async function sendSMS(phoneNumber, message) {
226
- if (!this.isEmulator()) {
227
- this.log.errorAndThrow('sendSMS method is only available for emulators');
228
- }
229
- await this.adb.sendSMS(phoneNumber, message);
230
- };
18
+ const ActionsMixin = {
19
+ async keyevent(keycode, metastate) {
20
+ // TODO deprecate keyevent; currently wd only implements keyevent
21
+ this.log.warn('keyevent will be deprecated use pressKeyCode');
22
+ return await this.pressKeyCode(keycode, metastate);
23
+ },
24
+
25
+ async pressKeyCode(keycode, metastate) {
26
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('pressKeyCode', {
27
+ keycode,
28
+ metastate: metastate ?? null,
29
+ });
30
+ },
31
+
32
+ async longPressKeyCode(keycode, metastate) {
33
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('longPressKeyCode', {
34
+ keycode,
35
+ metastate: metastate ?? null,
36
+ });
37
+ },
38
+
39
+ async getOrientation() {
40
+ let params = {
41
+ naturalOrientation: !!this.opts.androidNaturalOrientation,
42
+ };
43
+ let orientation = await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction(
44
+ 'orientation',
45
+ params
46
+ );
47
+ return orientation.toUpperCase();
48
+ },
49
+
50
+ async setOrientation(orientation) {
51
+ let params = {
52
+ orientation: orientation.toUpperCase(),
53
+ naturalOrientation: !!this.opts.androidNaturalOrientation,
54
+ };
55
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('orientation', params);
56
+ },
57
+
58
+ async fakeFlick(xSpeed, ySpeed) {
59
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('flick', {
60
+ xSpeed,
61
+ ySpeed,
62
+ });
63
+ },
64
+
65
+ async fakeFlickElement(elementId, xoffset, yoffset, speed) {
66
+ let params = {xoffset, yoffset, speed, elementId};
67
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction(
68
+ 'element:flick',
69
+ params
70
+ );
71
+ },
72
+
73
+ async swipe(startX, startY, endX, endY, duration, touchCount, elId) {
74
+ if (startX === 'null') {
75
+ startX = 0.5;
76
+ }
77
+ if (startY === 'null') {
78
+ startY = 0.5;
79
+ }
80
+ /** @type {import('./types').SwipeOpts} */
81
+ const swipeOpts = {
82
+ startX,
83
+ startY,
84
+ endX,
85
+ endY,
86
+ steps: Math.round(duration * swipeStepsPerSec),
87
+ };
88
+ // going the long way and checking for undefined and null since
89
+ // we can't be assured `elId` is a string and not an int
90
+ if (util.hasValue(elId)) {
91
+ swipeOpts.elementId = elId;
92
+ }
93
+ return await this.doSwipe(swipeOpts);
94
+ },
95
+
96
+ async doSwipe(swipeOpts) {
97
+ if (util.hasValue(swipeOpts.elementId)) {
98
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction(
99
+ 'element:swipe',
100
+ swipeOpts
101
+ );
102
+ } else {
103
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('swipe', swipeOpts);
104
+ }
105
+ },
106
+
107
+ async pinchClose(startX, startY, endX, endY, duration, percent, steps, elId) {
108
+ let pinchOpts = {
109
+ direction: 'in',
110
+ elementId: elId,
111
+ percent,
112
+ steps,
113
+ };
114
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction(
115
+ 'element:pinch',
116
+ pinchOpts
117
+ );
118
+ },
119
+
120
+ async pinchOpen(startX, startY, endX, endY, duration, percent, steps, elId) {
121
+ let pinchOpts = {direction: 'out', elementId: elId, percent, steps};
122
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction(
123
+ 'element:pinch',
124
+ pinchOpts
125
+ );
126
+ },
127
+
128
+ async flick(element, xSpeed, ySpeed, xOffset, yOffset, speed) {
129
+ if (element) {
130
+ await this.fakeFlickElement(element, xOffset, yOffset, speed);
131
+ } else {
132
+ await this.fakeFlick(xSpeed, ySpeed);
133
+ }
134
+ },
135
+
136
+ async drag(startX, startY, endX, endY, duration, touchCount, elementId, destElId) {
137
+ let dragOpts = {
138
+ elementId,
139
+ destElId,
140
+ startX,
141
+ startY,
142
+ endX,
143
+ endY,
144
+ steps: Math.round(duration * dragStepsPerSec),
145
+ };
146
+ return await this.doDrag(dragOpts);
147
+ },
148
+
149
+ async doDrag(dragOpts) {
150
+ if (util.hasValue(dragOpts.elementId)) {
151
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction(
152
+ 'element:drag',
153
+ dragOpts
154
+ );
155
+ } else {
156
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('drag', dragOpts);
157
+ }
158
+ },
231
159
 
232
- /**
233
- * @typedef {Object} SendSmsOptions
234
- * @property {string} phoneNumber The phone number to send SMS to
235
- * @property {string} message The message payload
236
- */
160
+ async mobileLock(opts = {}) {
161
+ const {seconds} = opts;
162
+ return await this.lock(seconds);
163
+ },
237
164
 
238
- /**
239
- * Emulate sending an SMS to the given phone number.
240
- * Only works on emulators.
241
- *
242
- * @param {SendSmsOptions} opts
243
- */
244
- commands.mobileSendSms = async function mobileSendSms(opts = {}) {
245
- const {phoneNumber, message} = requireArgs(['phoneNumber', 'message'], opts);
246
- await this.sendSMS(phoneNumber, message);
247
- };
165
+ async lock(seconds) {
166
+ await /** @type {ADB} */ (this.adb).lock();
167
+ if (Number.isNaN(seconds)) {
168
+ return;
169
+ }
248
170
 
249
- commands.gsmCall = async function gsmCall(phoneNumber, action) {
250
- if (!this.isEmulator()) {
251
- this.log.errorAndThrow('gsmCall method is only available for emulators');
252
- }
253
- await this.adb.gsmCall(phoneNumber, action);
254
- };
171
+ const floatSeconds = parseFloat(String(seconds));
172
+ if (floatSeconds <= 0) {
173
+ return;
174
+ }
175
+ await B.delay(1000 * floatSeconds);
176
+ await this.unlock();
177
+ },
255
178
 
256
- /**
257
- * @typedef {Object} GsmCallOptions
258
- * @property {string} phoneNumber The phone number to call to
259
- * @property {call|accept|cancel|hold} action One of possible actions to take
260
- */
179
+ async isLocked() {
180
+ return await /** @type {ADB} */ (this.adb).isScreenLocked();
181
+ },
261
182
 
262
- /**
263
- * Emulate a GSM call to the given phone number.
264
- * Only works on emulators.
265
- *
266
- * @param {GsmCallOptions} opts
267
- */
268
- commands.mobileGsmCall = async function mobileGsmCall(opts = {}) {
269
- const {phoneNumber, action} = requireArgs(['phoneNumber', 'action'], opts);
270
- await this.gsmCall(phoneNumber, action);
271
- };
183
+ async unlock() {
184
+ return await AndroidHelpers.unlock(this, /** @type {ADB} */ (this.adb), this.caps);
185
+ },
272
186
 
273
- commands.gsmSignal = async function gsmSignal(signalStrengh) {
274
- if (!this.isEmulator()) {
275
- this.log.errorAndThrow('gsmSignal method is only available for emulators');
276
- }
277
- await this.adb.gsmSignal(signalStrengh);
278
- };
187
+ async openNotifications() {
188
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('openNotification');
189
+ },
279
190
 
280
- /**
281
- * @typedef {Object} GsmSignalOptions
282
- * @property {0|1|2|3|4} strength One of possible signal strength values, where 4 is the best signal.
283
- */
191
+ async setLocation(latitude, longitude) {
192
+ await /** @type {ADB} */ (this.adb).sendTelnetCommand(`geo fix ${longitude} ${latitude}`);
193
+ },
284
194
 
285
- /**
286
- * Emulate GSM signal strength change event.
287
- * Only works on emulators.
288
- *
289
- * @param {GsmSignalOptions} opts
290
- */
291
- commands.mobileGsmSignal = async function mobileGsmSignal(opts = {}) {
292
- const {strength} = requireArgs('strength', opts);
293
- await this.gsmSignal(strength);
294
- };
195
+ async fingerprint(fingerprintId) {
196
+ if (!this.isEmulator()) {
197
+ this.log.errorAndThrow('fingerprint method is only available for emulators');
198
+ }
199
+ await /** @type {ADB} */ (this.adb).fingerprint(String(fingerprintId));
200
+ },
295
201
 
296
- commands.gsmVoice = async function gsmVoice(state) {
297
- if (!this.isEmulator()) {
298
- this.log.errorAndThrow('gsmVoice method is only available for emulators');
299
- }
300
- await this.adb.gsmVoice(state);
301
- };
202
+ async mobileFingerprint(opts) {
203
+ const {fingerprintId} = requireArgs('fingerprintId', opts);
204
+ await this.fingerprint(fingerprintId);
205
+ },
302
206
 
303
- /**
304
- * @typedef {Object} GsmVoiceOptions
305
- * @property {on|off} state
306
- */
207
+ async sendSMS(phoneNumber, message) {
208
+ if (!this.isEmulator()) {
209
+ this.log.errorAndThrow('sendSMS method is only available for emulators');
210
+ }
211
+ await /** @type {ADB} */ (this.adb).sendSMS(phoneNumber, message);
212
+ },
307
213
 
308
- /**
309
- * Emulate GSM voice state change event.
310
- * Only works on emulators.
311
- *
312
- * @param {GsmVoiceOptions} opts
313
- */
314
- commands.mobileGsmVoice = async function mobileGsmVoice(opts = {}) {
315
- const {state} = requireArgs('state', opts);
316
- await this.gsmVoice(state);
317
- };
214
+ async mobileSendSms(opts) {
215
+ const {phoneNumber, message} = requireArgs(['phoneNumber', 'message'], opts);
216
+ await this.sendSMS(phoneNumber, message);
217
+ },
318
218
 
319
- commands.powerAC = async function powerAC(state) {
320
- if (!this.isEmulator()) {
321
- this.log.errorAndThrow('powerAC method is only available for emulators');
322
- }
323
- await this.adb.powerAC(state);
324
- };
219
+ async gsmCall(phoneNumber, action) {
220
+ if (!this.isEmulator()) {
221
+ this.log.errorAndThrow('gsmCall method is only available for emulators');
222
+ }
223
+ await /** @type {ADB} */ (this.adb).gsmCall(phoneNumber, action);
224
+ },
325
225
 
326
- /**
327
- * @typedef {Object} PowerAcOptions
328
- * @property {on|off} state
329
- */
226
+ async mobileGsmCall(opts) {
227
+ const {phoneNumber, action} = requireArgs(['phoneNumber', 'action'], opts);
228
+ await this.gsmCall(phoneNumber, action);
229
+ },
330
230
 
331
- /**
332
- * Emulate AC power state change.
333
- * Only works on emulators.
334
- *
335
- * @param {GsmVoiceOptions} opts
336
- */
337
- commands.mobilePowerAc = async function mobilePowerAc(opts = {}) {
338
- const {state} = requireArgs('state', opts);
339
- await this.powerAC(state);
340
- };
231
+ async gsmSignal(signalStrengh) {
232
+ if (!this.isEmulator()) {
233
+ this.log.errorAndThrow('gsmSignal method is only available for emulators');
234
+ }
235
+ await /** @type {ADB} */ (this.adb).gsmSignal(signalStrengh);
236
+ },
341
237
 
342
- commands.powerCapacity = async function powerCapacity(batteryPercent) {
343
- if (!this.isEmulator()) {
344
- this.log.errorAndThrow('powerCapacity method is only available for emulators');
345
- }
346
- await this.adb.powerCapacity(batteryPercent);
347
- };
238
+ async mobileGsmSignal(opts) {
239
+ const {strength} = requireArgs('strength', opts);
240
+ await this.gsmSignal(strength);
241
+ },
348
242
 
349
- /**
350
- * @typedef {Object} PowerCapacityOptions
351
- * @property {number} percent - Percentage value in range [0, 100]
352
- */
243
+ async gsmVoice(state) {
244
+ if (!this.isEmulator()) {
245
+ this.log.errorAndThrow('gsmVoice method is only available for emulators');
246
+ }
247
+ await /** @type {ADB} */ (this.adb).gsmVoice(state);
248
+ },
353
249
 
354
- /**
355
- * Emulate power capacity change.
356
- * Only works on emulators.
357
- *
358
- * @param {PowerCapacityOptions} opts
359
- */
360
- commands.mobilePowerCapacity = async function mobilePowerCapacity(opts = {}) {
361
- const {percent} = requireArgs('percent', opts);
362
- await this.powerCapacity(percent);
363
- };
250
+ async mobileGsmVoice(opts) {
251
+ const {state} = requireArgs('state', opts);
252
+ await this.gsmVoice(state);
253
+ },
364
254
 
365
- commands.networkSpeed = async function networkSpeed(networkSpeed) {
366
- if (!this.isEmulator()) {
367
- this.log.errorAndThrow('networkSpeed method is only available for emulators');
368
- }
369
- await this.adb.networkSpeed(networkSpeed);
370
- };
255
+ async powerAC(state) {
256
+ if (!this.isEmulator()) {
257
+ this.log.errorAndThrow('powerAC method is only available for emulators');
258
+ }
259
+ await /** @type {ADB} */ (this.adb).powerAC(state);
260
+ },
371
261
 
372
- /**
373
- * @typedef {Object} NetworkSpeedOptions
374
- * @property {gsm|scsd|gprs|edge|umts|hsdpa|lte|evdo|full} speed
375
- */
262
+ async mobilePowerAc(opts) {
263
+ const {state} = requireArgs('state', opts);
264
+ await this.powerAC(state);
265
+ },
376
266
 
377
- /**
378
- * Emulate different network connection speed modes.
379
- * Only works on emulators.
380
- *
381
- * @param {NetworkSpeedOptions} opts
382
- */
383
- commands.mobileNetworkSpeed = async function mobileNetworkSpeed(opts = {}) {
384
- const {speed} = requireArgs('speed', opts);
385
- await this.networkSpeed(speed);
386
- };
267
+ async powerCapacity(batteryPercent) {
268
+ if (!this.isEmulator()) {
269
+ this.log.errorAndThrow('powerCapacity method is only available for emulators');
270
+ }
271
+ await /** @type {ADB} */ (this.adb).powerCapacity(batteryPercent);
272
+ },
387
273
 
388
- /**
389
- * Emulate sensors values on the connected emulator.
390
- *
391
- * @typedef {Object} Sensor
392
- * @property {string} sensorType - sensor type declared in adb.SENSORS
393
- * @property {string} value - value to set to the sensor
394
- *
395
- * @param {Object} Sensor
396
- * @throws {Error} - If sensorType is not defined
397
- * @throws {Error} - If value for the se sor is not defined
398
- * @throws {Error} - If deviceType is not an emulator
399
- */
400
- commands.sensorSet = async function sensorSet(sensor = {}) {
401
- const {sensorType, value} = sensor;
402
- if (!util.hasValue(sensorType)) {
403
- this.log.errorAndThrow(`'sensorType' argument is required`);
404
- }
405
- if (!util.hasValue(value)) {
406
- this.log.errorAndThrow(`'value' argument is required`);
407
- }
408
- if (!this.isEmulator()) {
409
- this.log.errorAndThrow('sensorSet method is only available for emulators');
410
- }
411
- await this.adb.sensorSet(sensorType, value);
412
- };
274
+ async mobilePowerCapacity(opts) {
275
+ const {percent} = requireArgs('percent', opts);
276
+ await this.powerCapacity(percent);
277
+ },
413
278
 
414
- /**
415
- * @param {ADB} adb
416
- * @param {Object} opts
417
- * @returns {Promise<Buffer>}
418
- */
419
- helpers.getScreenshotDataWithAdbShell = async function getScreenshotDataWithAdbShell(adb, opts) {
420
- const localFile = await tempDir.path({prefix: 'appium', suffix: '.png'});
421
- if (await fs.exists(localFile)) {
422
- await fs.unlink(localFile);
423
- }
424
- try {
425
- const pngDir = opts.androidScreenshotPath || '/data/local/tmp/';
426
- const png = path.posix.resolve(pngDir, 'screenshot.png');
427
- await adb.shell(['/system/bin/rm', `${png};`, '/system/bin/screencap', '-p', png]);
428
- if (!(await adb.fileSize(png))) {
429
- throw new Error('The size of the taken screenshot equals to zero.');
279
+ async networkSpeed(networkSpeed) {
280
+ if (!this.isEmulator()) {
281
+ this.log.errorAndThrow('networkSpeed method is only available for emulators');
430
282
  }
431
- await adb.pull(png, localFile);
432
- return await fs.readFile(localFile);
433
- } finally {
283
+ await /** @type {ADB} */ (this.adb).networkSpeed(networkSpeed);
284
+ },
285
+
286
+ async mobileNetworkSpeed(opts) {
287
+ const {speed} = requireArgs('speed', opts);
288
+ await this.networkSpeed(speed);
289
+ },
290
+
291
+ async sensorSet(opts) {
292
+ const {sensorType, value} = opts;
293
+ if (!util.hasValue(sensorType)) {
294
+ this.log.errorAndThrow(`'sensorType' argument is required`);
295
+ }
296
+ if (!util.hasValue(value)) {
297
+ this.log.errorAndThrow(`'value' argument is required`);
298
+ }
299
+ if (!this.isEmulator()) {
300
+ this.log.errorAndThrow('sensorSet method is only available for emulators');
301
+ }
302
+ await /** @type {ADB} */ (this.adb).sensorSet(sensorType, value);
303
+ },
304
+
305
+ async getScreenshotDataWithAdbShell(adb, opts) {
306
+ const localFile = await tempDir.path({prefix: 'appium', suffix: '.png'});
434
307
  if (await fs.exists(localFile)) {
435
308
  await fs.unlink(localFile);
436
309
  }
437
- }
438
- };
439
-
440
- /**
441
- * @param {ADB} adb
442
- * @returns {Promise<Buffer>}
443
- */
444
- helpers.getScreenshotDataWithAdbExecOut = async function getScreenshotDataWithAdbExecOut(adb) {
445
- const {stdout, stderr, code} = await exec(
446
- adb.executable.path,
447
- [...adb.executable.defaultArgs, 'exec-out', '/system/bin/screencap', '-p'],
448
- {encoding: 'binary', isBuffer: true}
449
- );
450
- // if there is an error, throw
451
- if (code || stderr.length) {
452
- throw new Error(`Screenshot returned error, code: '${code}', stderr: '${stderr.toString()}'`);
453
- }
454
- // if we don't get anything at all, throw
455
- if (!stdout.length) {
456
- throw new Error('Screenshot returned no data');
457
- }
458
-
459
- return stdout;
460
- };
461
-
462
- commands.getScreenshot = async function getScreenshot() {
463
- const apiLevel = await this.adb.getApiLevel();
464
- let image = null;
465
- if (apiLevel > 20) {
466
310
  try {
467
- // This screenshoting approach is way faster, since it requires less external commands
468
- // to be executed. Unfortunately, exec-out option is only supported by newer Android/SDK versions (5.0 and later)
469
- image = await this.getScreenshotDataWithAdbExecOut(this.adb);
470
- } catch (e) {
471
- this.log.info(
472
- `Cannot get screenshot data with 'adb exec-out' because of '${e.message}'. ` +
473
- `Defaulting to 'adb shell' call`
474
- );
311
+ const pngDir = opts.androidScreenshotPath || '/data/local/tmp/';
312
+ const png = path.posix.resolve(pngDir, 'screenshot.png');
313
+ await adb.shell(['/system/bin/rm', `${png};`, '/system/bin/screencap', '-p', png]);
314
+ if (!(await adb.fileSize(png))) {
315
+ throw new Error('The size of the taken screenshot equals to zero.');
316
+ }
317
+ await adb.pull(png, localFile);
318
+ return await fs.readFile(localFile);
319
+ } finally {
320
+ if (await fs.exists(localFile)) {
321
+ await fs.unlink(localFile);
322
+ }
475
323
  }
476
- }
477
- if (!image) {
478
- try {
479
- image = await this.getScreenshotDataWithAdbShell(this.adb, this.opts);
480
- } catch (e) {
481
- const err =
482
- `Cannot get screenshot data because of '${e.message}'. ` +
483
- `Make sure the 'LayoutParams.FLAG_SECURE' is not set for ` +
484
- `the current view`;
485
- this.log.errorAndThrow(err);
324
+ },
325
+
326
+ async getScreenshotDataWithAdbExecOut(adb) {
327
+ const {stdout, stderr, code} = await exec(
328
+ adb.executable.path,
329
+ [...adb.executable.defaultArgs, 'exec-out', '/system/bin/screencap', '-p'],
330
+ {encoding: 'binary', isBuffer: true}
331
+ );
332
+ // if there is an error, throw
333
+ if (code || stderr.length) {
334
+ throw new Error(`Screenshot returned error, code: '${code}', stderr: '${stderr.toString()}'`);
486
335
  }
487
- }
488
- if (apiLevel < 23) {
489
- // Android bug 8433742 - rotate screenshot if screen is rotated
490
- let screenOrientation = await this.adb.getScreenOrientation();
491
- try {
492
- image = await imageUtil
493
- .requireSharp()(image)
494
- .rotate(-90 * screenOrientation)
495
- .toBuffer();
496
- } catch (err) {
497
- this.log.warn(`Could not rotate screenshot due to error: ${err}`);
336
+ // if we don't get anything at all, throw
337
+ if (!stdout.length) {
338
+ throw new Error('Screenshot returned no data');
498
339
  }
499
- }
500
- return image.toString('base64');
340
+
341
+ return stdout;
342
+ },
343
+
344
+ async getScreenshot() {
345
+ const apiLevel = await /** @type {ADB} */ (this.adb).getApiLevel();
346
+ let image = null;
347
+ if (apiLevel > 20) {
348
+ try {
349
+ // This screenshoting approach is way faster, since it requires less external commands
350
+ // to be executed. Unfortunately, exec-out option is only supported by newer Android/SDK versions (5.0 and later)
351
+ image = await this.getScreenshotDataWithAdbExecOut(/** @type {ADB} */ (this.adb));
352
+ } catch (e) {
353
+ this.log.info(
354
+ `Cannot get screenshot data with 'adb exec-out' because of '${
355
+ /** @type {Error} */ (e).message
356
+ }'. ` + `Defaulting to 'adb shell' call`
357
+ );
358
+ }
359
+ }
360
+ if (!image) {
361
+ try {
362
+ image = await this.getScreenshotDataWithAdbShell(/** @type {ADB} */ (this.adb), this.opts);
363
+ } catch (e) {
364
+ const err =
365
+ `Cannot get screenshot data because of '${/** @type {Error} */ (e).message}'. ` +
366
+ `Make sure the 'LayoutParams.FLAG_SECURE' is not set for ` +
367
+ `the current view`;
368
+ this.log.error(err);
369
+ throw new Error(err);
370
+ }
371
+ }
372
+ if (apiLevel < 23) {
373
+ // Android bug 8433742 - rotate screenshot if screen is rotated
374
+ let screenOrientation = await /** @type {ADB} */ (this.adb).getScreenOrientation();
375
+ try {
376
+ image = await imageUtil.requireSharp()(image).rotate(-90 * screenOrientation).toBuffer();
377
+ } catch (err) {
378
+ this.log.warn(`Could not rotate screenshot due to error: ${err}`);
379
+ }
380
+ }
381
+ return image.toString('base64');
382
+ },
501
383
  };
502
384
 
503
- Object.assign(extensions, commands, helpers);
504
- export {commands, helpers};
505
- export default extensions;
385
+ mixin(ActionsMixin);
386
+
387
+ export default ActionsMixin;
388
+
389
+ /**
390
+ * @typedef {import('../bootstrap').AndroidBootstrap} AndroidBootstrap
391
+ * @typedef {import('appium-adb').ADB} ADB
392
+ */