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.
- package/CHANGELOG.md +7 -0
- package/build/lib/commands/actions.d.ts +6 -224
- package/build/lib/commands/actions.d.ts.map +1 -1
- package/build/lib/commands/actions.js +306 -405
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.d.ts +7 -9
- package/build/lib/commands/alert.d.ts.map +1 -1
- package/build/lib/commands/alert.js +24 -18
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +7 -313
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +135 -293
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/context.d.ts +8 -92
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +381 -439
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/element.d.ts +8 -35
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +153 -136
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/emu-console.d.ts +6 -48
- package/build/lib/commands/emu-console.d.ts.map +1 -1
- package/build/lib/commands/emu-console.js +19 -34
- package/build/lib/commands/emu-console.js.map +1 -1
- package/build/lib/commands/execute.d.ts +6 -5
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +77 -66
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +7 -128
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +183 -219
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +8 -12
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +19 -23
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +9 -132
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +281 -312
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/ime.d.ts +7 -10
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +47 -35
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/index.d.ts +27 -2
- package/build/lib/commands/index.d.ts.map +1 -1
- package/build/lib/commands/index.js +41 -19
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/intent.d.ts +7 -417
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +104 -216
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +6 -5
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +16 -8
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/log.d.ts +7 -44
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +146 -108
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +7 -143
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +113 -140
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/mixins.d.ts +740 -0
- package/build/lib/commands/mixins.d.ts.map +1 -0
- package/build/lib/commands/mixins.js +19 -0
- package/build/lib/commands/mixins.js.map +1 -0
- package/build/lib/commands/network.d.ts +7 -138
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +212 -254
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +24 -70
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +144 -100
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +8 -92
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +75 -87
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +7 -193
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +151 -182
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/shell.d.ts +7 -7
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +40 -33
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +9 -103
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +261 -218
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +22 -90
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +76 -74
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/touch.d.ts +10 -29
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +301 -285
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/types.d.ts +978 -0
- package/build/lib/commands/types.d.ts.map +1 -0
- package/build/lib/commands/types.js +3 -0
- package/build/lib/commands/types.js.map +1 -0
- package/build/lib/constraints.d.ts +291 -0
- package/build/lib/constraints.d.ts.map +1 -0
- package/build/lib/{desired-caps.js → constraints.js} +103 -102
- package/build/lib/constraints.js.map +1 -0
- package/build/lib/driver.d.ts +68 -37
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +123 -80
- package/build/lib/driver.js.map +1 -1
- package/build/lib/helpers/android.d.ts +164 -0
- package/build/lib/helpers/android.d.ts.map +1 -0
- package/build/lib/helpers/android.js +819 -0
- package/build/lib/helpers/android.js.map +1 -0
- package/build/lib/helpers/index.d.ts +7 -0
- package/build/lib/helpers/index.d.ts.map +1 -0
- package/build/lib/helpers/index.js +29 -0
- package/build/lib/helpers/index.js.map +1 -0
- package/build/lib/helpers/types.d.ts +121 -0
- package/build/lib/helpers/types.d.ts.map +1 -0
- package/build/lib/helpers/types.js +3 -0
- package/build/lib/helpers/types.js.map +1 -0
- package/build/lib/helpers/unlock.d.ts +32 -0
- package/build/lib/helpers/unlock.d.ts.map +1 -0
- package/build/lib/helpers/unlock.js +273 -0
- package/build/lib/helpers/unlock.js.map +1 -0
- package/build/lib/helpers/webview.d.ts +74 -0
- package/build/lib/helpers/webview.d.ts.map +1 -0
- package/build/lib/helpers/webview.js +421 -0
- package/build/lib/helpers/webview.js.map +1 -0
- package/build/lib/index.d.ts +9 -0
- package/build/lib/index.d.ts.map +1 -0
- package/build/lib/index.js +37 -0
- package/build/lib/index.js.map +1 -0
- package/build/lib/method-map.d.ts +0 -8
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js +63 -74
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/stubs.d.ts +0 -1
- package/build/lib/stubs.d.ts.map +1 -1
- package/build/lib/stubs.js +1 -0
- package/build/lib/stubs.js.map +1 -1
- package/build/lib/utils.d.ts +1 -1
- package/build/lib/utils.d.ts.map +1 -1
- package/lib/commands/actions.js +351 -464
- package/lib/commands/alert.js +27 -17
- package/lib/commands/app-management.js +156 -314
- package/lib/commands/context.js +457 -441
- package/lib/commands/element.js +201 -157
- package/lib/commands/emu-console.js +25 -45
- package/lib/commands/execute.js +106 -90
- package/lib/commands/file-actions.js +222 -240
- package/lib/commands/find.ts +103 -0
- package/lib/commands/general.js +327 -339
- package/lib/commands/ime.js +50 -34
- package/lib/commands/{index.js → index.ts} +20 -24
- package/lib/commands/intent.js +108 -249
- package/lib/commands/keyboard.js +20 -8
- package/lib/commands/log.js +172 -116
- package/lib/commands/media-projection.js +134 -161
- package/lib/commands/mixins.ts +966 -0
- package/lib/commands/network.js +252 -281
- package/lib/commands/performance.js +203 -132
- package/lib/commands/permissions.js +108 -109
- package/lib/commands/recordscreen.js +212 -209
- package/lib/commands/shell.js +51 -40
- package/lib/commands/streamscreen.js +355 -289
- package/lib/commands/system-bars.js +92 -83
- package/lib/commands/touch.js +357 -294
- package/lib/commands/types.ts +1097 -0
- package/lib/{desired-caps.js → constraints.ts} +106 -103
- package/lib/{driver.js → driver.ts} +278 -132
- package/lib/helpers/android.ts +1143 -0
- package/lib/helpers/index.ts +6 -0
- package/lib/helpers/types.ts +134 -0
- package/lib/helpers/unlock.ts +329 -0
- package/lib/helpers/webview.ts +582 -0
- package/lib/index.ts +18 -0
- package/lib/method-map.js +87 -98
- package/lib/stubs.ts +0 -1
- package/package.json +26 -19
- package/build/index.js +0 -51
- package/build/lib/android-helpers.d.ts +0 -136
- package/build/lib/android-helpers.d.ts.map +0 -1
- package/build/lib/android-helpers.js +0 -855
- package/build/lib/android-helpers.js.map +0 -1
- package/build/lib/commands/coverage.d.ts +0 -5
- package/build/lib/commands/coverage.d.ts.map +0 -1
- package/build/lib/commands/coverage.js +0 -19
- package/build/lib/commands/coverage.js.map +0 -1
- package/build/lib/desired-caps.d.ts +0 -353
- package/build/lib/desired-caps.d.ts.map +0 -1
- package/build/lib/desired-caps.js.map +0 -1
- package/build/lib/unlock-helpers.d.ts +0 -38
- package/build/lib/unlock-helpers.d.ts.map +0 -1
- package/build/lib/unlock-helpers.js +0 -266
- package/build/lib/unlock-helpers.js.map +0 -1
- package/build/lib/webview-helpers.d.ts +0 -224
- package/build/lib/webview-helpers.d.ts.map +0 -1
- package/build/lib/webview-helpers.js +0 -528
- package/build/lib/webview-helpers.js.map +0 -1
- package/index.js +0 -24
- package/lib/android-helpers.js +0 -983
- package/lib/commands/coverage.js +0 -18
- package/lib/commands/find.js +0 -82
- package/lib/unlock-helpers.js +0 -278
- package/lib/webview-helpers.js +0 -602
package/lib/commands/actions.js
CHANGED
|
@@ -1,505 +1,392 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
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
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* @param {FingerprintOpts} opts
|
|
15
|
+
* @type {import('./mixins').ActionsMixin & ThisType<import('../driver').AndroidDriver>}
|
|
16
|
+
* @satisfies {import('@appium/types').ExternalDriver}
|
|
219
17
|
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
*/
|
|
160
|
+
async mobileLock(opts = {}) {
|
|
161
|
+
const {seconds} = opts;
|
|
162
|
+
return await this.lock(seconds);
|
|
163
|
+
},
|
|
237
164
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
258
|
-
|
|
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
|
-
|
|
264
|
-
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
*/
|
|
191
|
+
async setLocation(latitude, longitude) {
|
|
192
|
+
await /** @type {ADB} */ (this.adb).sendTelnetCommand(`geo fix ${longitude} ${latitude}`);
|
|
193
|
+
},
|
|
284
194
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
this.
|
|
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
|
-
|
|
305
|
-
|
|
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
|
-
|
|
310
|
-
|
|
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
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
226
|
+
async mobileGsmCall(opts) {
|
|
227
|
+
const {phoneNumber, action} = requireArgs(['phoneNumber', 'action'], opts);
|
|
228
|
+
await this.gsmCall(phoneNumber, action);
|
|
229
|
+
},
|
|
330
230
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
this.
|
|
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
|
-
|
|
351
|
-
|
|
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
|
-
|
|
356
|
-
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
-
|
|
374
|
-
|
|
375
|
-
|
|
262
|
+
async mobilePowerAc(opts) {
|
|
263
|
+
const {state} = requireArgs('state', opts);
|
|
264
|
+
await this.powerAC(state);
|
|
265
|
+
},
|
|
376
266
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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
|
-
|
|
416
|
-
|
|
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.
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
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
|
-
|
|
489
|
-
|
|
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
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
export default
|
|
385
|
+
mixin(ActionsMixin);
|
|
386
|
+
|
|
387
|
+
export default ActionsMixin;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* @typedef {import('../bootstrap').AndroidBootstrap} AndroidBootstrap
|
|
391
|
+
* @typedef {import('appium-adb').ADB} ADB
|
|
392
|
+
*/
|