appium-android-driver 7.1.2 → 7.1.4
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 +14 -0
- package/build/lib/commands/actions.js +13 -13
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +14 -17
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/context.d.ts.map +1 -1
- package/build/lib/commands/context.js +7 -9
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/deviceidle.js +1 -1
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/element.js +2 -2
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +14 -16
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +23 -27
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +6 -7
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/intent.js +7 -7
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +2 -3
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +6 -9
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +30 -37
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.js +5 -5
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +9 -12
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +8 -10
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +3 -4
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +3 -4
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.js +2 -2
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/touch.js +1 -1
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/constraints.d.ts +0 -21
- package/build/lib/constraints.d.ts.map +1 -1
- package/build/lib/constraints.js +0 -26
- package/build/lib/constraints.js.map +1 -1
- package/lib/commands/actions.js +13 -13
- package/lib/commands/app-management.js +14 -17
- package/lib/commands/context.js +9 -7
- package/lib/commands/deviceidle.js +1 -1
- package/lib/commands/element.js +2 -2
- package/lib/commands/file-actions.js +14 -16
- package/lib/commands/general.js +23 -26
- package/lib/commands/ime.js +6 -7
- package/lib/commands/intent.js +7 -7
- package/lib/commands/log.js +2 -3
- package/lib/commands/media-projection.js +6 -9
- package/lib/commands/network.js +30 -37
- package/lib/commands/performance.js +5 -5
- package/lib/commands/permissions.js +9 -11
- package/lib/commands/recordscreen.js +8 -10
- package/lib/commands/shell.js +3 -4
- package/lib/commands/streamscreen.js +3 -4
- package/lib/commands/system-bars.js +2 -2
- package/lib/commands/touch.js +1 -1
- package/lib/constraints.ts +0 -28
- package/package.json +1 -1
|
@@ -85,7 +85,6 @@ function escapePath(p) {
|
|
|
85
85
|
*/
|
|
86
86
|
const FileActionsMixin = {
|
|
87
87
|
async pullFile(remotePath) {
|
|
88
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
89
88
|
if (remotePath.endsWith('/')) {
|
|
90
89
|
throw new errors.InvalidArgumentError(
|
|
91
90
|
`It is expected that remote path points to a file and not to a folder. ` +
|
|
@@ -100,8 +99,8 @@ const FileActionsMixin = {
|
|
|
100
99
|
);
|
|
101
100
|
tmpDestination = `/data/local/tmp/${path.posix.basename(pathInContainer)}`;
|
|
102
101
|
try {
|
|
103
|
-
await adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
104
|
-
await adb.shell([
|
|
102
|
+
await this.adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
103
|
+
await this.adb.shell([
|
|
105
104
|
'run-as',
|
|
106
105
|
packageId,
|
|
107
106
|
`cp -f '${escapePath(pathInContainer)}' '${escapePath(tmpDestination)}'`,
|
|
@@ -116,14 +115,14 @@ const FileActionsMixin = {
|
|
|
116
115
|
}
|
|
117
116
|
const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
|
|
118
117
|
try {
|
|
119
|
-
await adb.pull(tmpDestination || remotePath, localFile);
|
|
118
|
+
await this.adb.pull(tmpDestination || remotePath, localFile);
|
|
120
119
|
return (await util.toInMemoryBase64(localFile)).toString();
|
|
121
120
|
} finally {
|
|
122
121
|
if (await fs.exists(localFile)) {
|
|
123
122
|
await fs.unlink(localFile);
|
|
124
123
|
}
|
|
125
124
|
if (tmpDestination) {
|
|
126
|
-
await adb.shell(['rm', '-f', tmpDestination]);
|
|
125
|
+
await this.adb.shell(['rm', '-f', tmpDestination]);
|
|
127
126
|
}
|
|
128
127
|
}
|
|
129
128
|
},
|
|
@@ -148,7 +147,6 @@ const FileActionsMixin = {
|
|
|
148
147
|
}
|
|
149
148
|
const content = Buffer.from(base64Data, 'base64');
|
|
150
149
|
let tmpDestination = null;
|
|
151
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
152
150
|
try {
|
|
153
151
|
await fs.writeFile(localFile, content.toString('binary'), 'binary');
|
|
154
152
|
if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
|
|
@@ -159,15 +157,15 @@ const FileActionsMixin = {
|
|
|
159
157
|
);
|
|
160
158
|
tmpDestination = `/data/local/tmp/${path.posix.basename(pathInContainer)}`;
|
|
161
159
|
try {
|
|
162
|
-
await adb.shell([
|
|
160
|
+
await this.adb.shell([
|
|
163
161
|
'run-as',
|
|
164
162
|
packageId,
|
|
165
163
|
`mkdir -p '${escapePath(path.posix.dirname(pathInContainer))}'`,
|
|
166
164
|
]);
|
|
167
|
-
await adb.shell(['run-as', packageId, `touch '${escapePath(pathInContainer)}'`]);
|
|
168
|
-
await adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
169
|
-
await adb.push(localFile, tmpDestination);
|
|
170
|
-
await adb.shell([
|
|
165
|
+
await this.adb.shell(['run-as', packageId, `touch '${escapePath(pathInContainer)}'`]);
|
|
166
|
+
await this.adb.shell(['run-as', packageId, `chmod 777 '${escapePath(pathInContainer)}'`]);
|
|
167
|
+
await this.adb.push(localFile, tmpDestination);
|
|
168
|
+
await this.adb.shell([
|
|
171
169
|
'run-as',
|
|
172
170
|
packageId,
|
|
173
171
|
`cp -f '${escapePath(tmpDestination)}' '${escapePath(pathInContainer)}'`,
|
|
@@ -181,18 +179,18 @@ const FileActionsMixin = {
|
|
|
181
179
|
}
|
|
182
180
|
} else {
|
|
183
181
|
// adb push creates folders and overwrites existing files.
|
|
184
|
-
await adb.push(localFile, remotePath);
|
|
182
|
+
await this.adb.push(localFile, remotePath);
|
|
185
183
|
|
|
186
184
|
// if we have pushed a file, it might be a media file, so ensure that
|
|
187
185
|
// apps know about it
|
|
188
|
-
await scanMedia(adb, remotePath, this.log);
|
|
186
|
+
await scanMedia(this.adb, remotePath, this.log);
|
|
189
187
|
}
|
|
190
188
|
} finally {
|
|
191
189
|
if (await fs.exists(localFile)) {
|
|
192
190
|
await fs.unlink(localFile);
|
|
193
191
|
}
|
|
194
192
|
if (tmpDestination) {
|
|
195
|
-
await adb.shell(['rm', '-f', tmpDestination]);
|
|
193
|
+
await this.adb.shell(['rm', '-f', tmpDestination]);
|
|
196
194
|
}
|
|
197
195
|
}
|
|
198
196
|
},
|
|
@@ -205,7 +203,7 @@ const FileActionsMixin = {
|
|
|
205
203
|
async pullFolder(remotePath) {
|
|
206
204
|
const tmpRoot = await tempDir.openDir();
|
|
207
205
|
try {
|
|
208
|
-
await
|
|
206
|
+
await this.adb.pull(remotePath, tmpRoot);
|
|
209
207
|
return (
|
|
210
208
|
await zip.toInMemoryZip(tmpRoot, {
|
|
211
209
|
encodeToBase64: true,
|
|
@@ -229,7 +227,7 @@ const FileActionsMixin = {
|
|
|
229
227
|
`'${remotePath}' is given instead`
|
|
230
228
|
);
|
|
231
229
|
}
|
|
232
|
-
return await deleteFileOrFolder.call(this,
|
|
230
|
+
return await deleteFileOrFolder.call(this, this.adb, remotePath);
|
|
233
231
|
},
|
|
234
232
|
};
|
|
235
233
|
|
package/lib/commands/general.js
CHANGED
|
@@ -41,7 +41,7 @@ const GeneralMixin = {
|
|
|
41
41
|
'Attempting to capture android device date and time. ' + `The format specifier is '${format}'`
|
|
42
42
|
);
|
|
43
43
|
const deviceTimestamp = (
|
|
44
|
-
await
|
|
44
|
+
await this.adb.shell(['date', '+%Y-%m-%dT%T%z'])
|
|
45
45
|
).trim();
|
|
46
46
|
this.log.debug(`Got device timestamp: ${deviceTimestamp}`);
|
|
47
47
|
const parsedTimestamp = moment.utc(deviceTimestamp, 'YYYY-MM-DDTHH:mm:ssZZ');
|
|
@@ -66,10 +66,9 @@ const GeneralMixin = {
|
|
|
66
66
|
},
|
|
67
67
|
|
|
68
68
|
async openSettingsActivity(setting) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
await adb.
|
|
72
|
-
await adb.waitForNotActivity(
|
|
69
|
+
let {appPackage, appActivity} = await this.adb.getFocusedPackageAndActivity();
|
|
70
|
+
await this.adb.shell(['am', 'start', '-a', `android.settings.${setting}`]);
|
|
71
|
+
await this.adb.waitForNotActivity(
|
|
73
72
|
/** @type {string} */ (appPackage),
|
|
74
73
|
/** @type {string} */ (appActivity),
|
|
75
74
|
5000
|
|
@@ -95,26 +94,25 @@ const GeneralMixin = {
|
|
|
95
94
|
* @returns {Promise<string>}
|
|
96
95
|
*/
|
|
97
96
|
async getCurrentActivity() {
|
|
98
|
-
return /** @type {string} */ ((await
|
|
97
|
+
return /** @type {string} */ ((await this.adb.getFocusedPackageAndActivity()).appActivity);
|
|
99
98
|
},
|
|
100
99
|
|
|
101
100
|
/**
|
|
102
101
|
* @returns {Promise<string>}
|
|
103
102
|
*/
|
|
104
103
|
async getCurrentPackage() {
|
|
105
|
-
return /** @type {string} */ ((await
|
|
104
|
+
return /** @type {string} */ ((await this.adb.getFocusedPackageAndActivity()).appPackage);
|
|
106
105
|
},
|
|
107
106
|
|
|
108
107
|
async background(seconds) {
|
|
109
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
110
108
|
if (seconds < 0) {
|
|
111
109
|
// if user passes in a negative seconds value, interpret that as the instruction
|
|
112
110
|
// to not bring the app back at all
|
|
113
|
-
await adb.goToHome();
|
|
111
|
+
await this.adb.goToHome();
|
|
114
112
|
return true;
|
|
115
113
|
}
|
|
116
|
-
let {appPackage, appActivity} = await adb.getFocusedPackageAndActivity();
|
|
117
|
-
await adb.goToHome();
|
|
114
|
+
let {appPackage, appActivity} = await this.adb.getFocusedPackageAndActivity();
|
|
115
|
+
await this.adb.goToHome();
|
|
118
116
|
|
|
119
117
|
// people can wait for a long time, so to be safe let's use the longSleep function and log
|
|
120
118
|
// progress periodically.
|
|
@@ -178,13 +176,12 @@ const GeneralMixin = {
|
|
|
178
176
|
this.log.debug(
|
|
179
177
|
`Bringing application back to foreground with arguments: ${JSON.stringify(args)}`
|
|
180
178
|
);
|
|
181
|
-
return await adb.startApp(args);
|
|
179
|
+
return await this.adb.startApp(args);
|
|
182
180
|
},
|
|
183
181
|
|
|
184
182
|
async getStrings(language) {
|
|
185
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
186
183
|
if (!language) {
|
|
187
|
-
language = await adb.getDeviceLanguage();
|
|
184
|
+
language = await this.adb.getDeviceLanguage();
|
|
188
185
|
this.log.info(`No language specified, returning strings for: ${language}`);
|
|
189
186
|
}
|
|
190
187
|
|
|
@@ -205,7 +202,7 @@ const GeneralMixin = {
|
|
|
205
202
|
return preprocessStringsMap(this.apkStrings[language]);
|
|
206
203
|
}
|
|
207
204
|
|
|
208
|
-
this.apkStrings[language] = await androidHelpers.pushStrings(language, adb, this.opts);
|
|
205
|
+
this.apkStrings[language] = await androidHelpers.pushStrings(language, this.adb, this.opts);
|
|
209
206
|
|
|
210
207
|
return preprocessStringsMap(this.apkStrings[language]);
|
|
211
208
|
},
|
|
@@ -247,12 +244,12 @@ const GeneralMixin = {
|
|
|
247
244
|
};
|
|
248
245
|
this._cachedActivityArgs = this._cachedActivityArgs || {};
|
|
249
246
|
this._cachedActivityArgs[`${args.waitPkg}/${args.waitActivity}`] = args;
|
|
250
|
-
await
|
|
247
|
+
await this.adb.startApp(args);
|
|
251
248
|
},
|
|
252
249
|
|
|
253
250
|
async reset() {
|
|
254
251
|
await androidHelpers.resetApp(
|
|
255
|
-
|
|
252
|
+
this.adb,
|
|
256
253
|
Object.assign({}, this.opts, {fastReset: true})
|
|
257
254
|
);
|
|
258
255
|
// reset context since we don't know what kind on context we will end up after app launch.
|
|
@@ -261,7 +258,7 @@ const GeneralMixin = {
|
|
|
261
258
|
},
|
|
262
259
|
|
|
263
260
|
async startAUT() {
|
|
264
|
-
await
|
|
261
|
+
await this.adb.startApp({
|
|
265
262
|
pkg: /** @type {string} */ (this.opts.appPackage),
|
|
266
263
|
activity: this.opts.appActivity,
|
|
267
264
|
action: this.opts.intentAction,
|
|
@@ -280,19 +277,19 @@ const GeneralMixin = {
|
|
|
280
277
|
// we override setUrl to take an android URI which can be used for deep-linking
|
|
281
278
|
// inside an app, similar to starting an intent
|
|
282
279
|
async setUrl(uri) {
|
|
283
|
-
await
|
|
280
|
+
await this.adb.startUri(uri, /** @type {string} */ (this.opts.appPackage));
|
|
284
281
|
},
|
|
285
282
|
|
|
286
283
|
// closing app using force stop
|
|
287
284
|
async closeApp() {
|
|
288
|
-
await
|
|
285
|
+
await this.adb.forceStop(/** @type {string} */ (this.opts.appPackage));
|
|
289
286
|
// reset context since we don't know what kind on context we will end up after app launch.
|
|
290
287
|
await this.setContext();
|
|
291
288
|
},
|
|
292
289
|
|
|
293
290
|
async getDisplayDensity() {
|
|
294
291
|
// first try the property for devices
|
|
295
|
-
let out = await
|
|
292
|
+
let out = await this.adb.shell(['getprop', 'ro.sf.lcd_density']);
|
|
296
293
|
if (out) {
|
|
297
294
|
let val = parseInt(out, 10);
|
|
298
295
|
// if the value is NaN, try getting the emulator property
|
|
@@ -302,7 +299,7 @@ const GeneralMixin = {
|
|
|
302
299
|
this.log.debug(`Parsed density value was NaN: "${out}"`);
|
|
303
300
|
}
|
|
304
301
|
// fallback to trying property for emulators
|
|
305
|
-
out = await
|
|
302
|
+
out = await this.adb.shell(['getprop', 'qemu.sf.lcd_density']);
|
|
306
303
|
if (out) {
|
|
307
304
|
let val = parseInt(out, 10);
|
|
308
305
|
if (!isNaN(val)) {
|
|
@@ -317,15 +314,15 @@ const GeneralMixin = {
|
|
|
317
314
|
|
|
318
315
|
async mobilePerformEditorAction(opts) {
|
|
319
316
|
const {action} = requireArgs('action', opts);
|
|
320
|
-
await
|
|
317
|
+
await this.adb.performEditorAction(action);
|
|
321
318
|
},
|
|
322
319
|
|
|
323
320
|
async mobileGetNotifications() {
|
|
324
|
-
return await
|
|
321
|
+
return await this.adb.getNotifications();
|
|
325
322
|
},
|
|
326
323
|
|
|
327
324
|
async mobileListSms(opts) {
|
|
328
|
-
return await
|
|
325
|
+
return await this.adb.getSmsList(opts);
|
|
329
326
|
},
|
|
330
327
|
|
|
331
328
|
async mobileUnlock(opts = {}) {
|
|
@@ -334,7 +331,7 @@ const GeneralMixin = {
|
|
|
334
331
|
await this.unlock();
|
|
335
332
|
} else {
|
|
336
333
|
// @ts-expect-error XXX: these caps should be defined in the constraints!!
|
|
337
|
-
await androidHelpers.unlock(this,
|
|
334
|
+
await androidHelpers.unlock(this, this.adb, {
|
|
338
335
|
unlockKey: key,
|
|
339
336
|
unlockType: type,
|
|
340
337
|
unlockStrategy: strategy,
|
package/lib/commands/ime.js
CHANGED
|
@@ -16,27 +16,26 @@ const IMEMixin = {
|
|
|
16
16
|
|
|
17
17
|
async availableIMEEngines() {
|
|
18
18
|
this.log.debug('Retrieving available IMEs');
|
|
19
|
-
let engines = await
|
|
19
|
+
let engines = await this.adb.availableIMEs();
|
|
20
20
|
this.log.debug(`Engines: ${JSON.stringify(engines)}`);
|
|
21
21
|
return engines;
|
|
22
22
|
},
|
|
23
23
|
|
|
24
24
|
async getActiveIMEEngine() {
|
|
25
25
|
this.log.debug('Retrieving current default IME');
|
|
26
|
-
return String(await
|
|
26
|
+
return String(await this.adb.defaultIME());
|
|
27
27
|
},
|
|
28
28
|
|
|
29
29
|
async activateIMEEngine(imeId) {
|
|
30
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
31
30
|
this.log.debug(`Attempting to activate IME ${imeId}`);
|
|
32
|
-
let availableEngines = await adb.availableIMEs();
|
|
31
|
+
let availableEngines = await this.adb.availableIMEs();
|
|
33
32
|
if (availableEngines.indexOf(imeId) === -1) {
|
|
34
33
|
this.log.debug('IME not found, failing');
|
|
35
34
|
throw new errors.IMENotAvailableError();
|
|
36
35
|
}
|
|
37
36
|
this.log.debug('Found installed IME, attempting to activate');
|
|
38
|
-
await adb.enableIME(imeId);
|
|
39
|
-
await adb.setIME(imeId);
|
|
37
|
+
await this.adb.enableIME(imeId);
|
|
38
|
+
await this.adb.setIME(imeId);
|
|
40
39
|
},
|
|
41
40
|
|
|
42
41
|
async deactivateIMEEngine() {
|
|
@@ -44,7 +43,7 @@ const IMEMixin = {
|
|
|
44
43
|
// XXX: this allowed 'null' to be passed into `adb.shell`
|
|
45
44
|
if (currentEngine) {
|
|
46
45
|
this.log.debug(`Attempting to deactivate ${currentEngine}`);
|
|
47
|
-
await
|
|
46
|
+
await this.adb.disableIME(currentEngine);
|
|
48
47
|
}
|
|
49
48
|
},
|
|
50
49
|
};
|
package/lib/commands/intent.js
CHANGED
|
@@ -108,7 +108,7 @@ const ActivityMixin = {
|
|
|
108
108
|
const {user, wait, stop, windowingMode, activityType, display} = opts;
|
|
109
109
|
const cmd = [
|
|
110
110
|
'am',
|
|
111
|
-
(await
|
|
111
|
+
(await this.adb.getApiLevel()) < API_LEVEL_ANDROID_8
|
|
112
112
|
? 'start'
|
|
113
113
|
: 'start-activity',
|
|
114
114
|
];
|
|
@@ -131,7 +131,7 @@ const ActivityMixin = {
|
|
|
131
131
|
cmd.push('--display', String(display));
|
|
132
132
|
}
|
|
133
133
|
cmd.push(...parseIntentSpec(opts));
|
|
134
|
-
return await
|
|
134
|
+
return await this.adb.shell(cmd);
|
|
135
135
|
},
|
|
136
136
|
|
|
137
137
|
async mobileBroadcast(opts = {}) {
|
|
@@ -147,13 +147,13 @@ const ActivityMixin = {
|
|
|
147
147
|
cmd.push('--allow-background-activity-starts');
|
|
148
148
|
}
|
|
149
149
|
cmd.push(...parseIntentSpec(opts));
|
|
150
|
-
return await
|
|
150
|
+
return await this.adb.shell(cmd);
|
|
151
151
|
},
|
|
152
152
|
|
|
153
153
|
async mobileStartService(opts = {}) {
|
|
154
154
|
const {user, foreground} = opts;
|
|
155
155
|
const cmd = ['am'];
|
|
156
|
-
if ((await
|
|
156
|
+
if ((await this.adb.getApiLevel()) < API_LEVEL_ANDROID_8) {
|
|
157
157
|
cmd.push('startservice');
|
|
158
158
|
} else {
|
|
159
159
|
cmd.push(foreground ? 'start-foreground-service' : 'start-service');
|
|
@@ -162,14 +162,14 @@ const ActivityMixin = {
|
|
|
162
162
|
cmd.push('--user', String(user));
|
|
163
163
|
}
|
|
164
164
|
cmd.push(...parseIntentSpec(opts));
|
|
165
|
-
return await
|
|
165
|
+
return await this.adb.shell(cmd);
|
|
166
166
|
},
|
|
167
167
|
|
|
168
168
|
async mobileStopService(opts = {}) {
|
|
169
169
|
const {user} = opts;
|
|
170
170
|
const cmd = [
|
|
171
171
|
'am',
|
|
172
|
-
(await
|
|
172
|
+
(await this.adb.getApiLevel()) < API_LEVEL_ANDROID_8
|
|
173
173
|
? 'stopservice'
|
|
174
174
|
: 'stop-service',
|
|
175
175
|
];
|
|
@@ -177,7 +177,7 @@ const ActivityMixin = {
|
|
|
177
177
|
cmd.push('--user', String(user));
|
|
178
178
|
}
|
|
179
179
|
cmd.push(...parseIntentSpec(opts));
|
|
180
|
-
return await
|
|
180
|
+
return await this.adb.shell(cmd);
|
|
181
181
|
},
|
|
182
182
|
};
|
|
183
183
|
|
package/lib/commands/log.js
CHANGED
|
@@ -91,7 +91,6 @@ const LogMixin = {
|
|
|
91
91
|
*/
|
|
92
92
|
async mobileStartLogsBroadcast() {
|
|
93
93
|
const server = /** @type {import('@appium/types').AppiumServer} */ (this.server);
|
|
94
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
95
94
|
const pathname = WEBSOCKET_ENDPOINT(/** @type {string} */ (this.sessionId));
|
|
96
95
|
if (!_.isEmpty(await server.getWebSocketHandlers(pathname))) {
|
|
97
96
|
log.debug(`The logcat broadcasting web socket server is already listening at ${pathname}`);
|
|
@@ -123,12 +122,12 @@ const LogMixin = {
|
|
|
123
122
|
}
|
|
124
123
|
};
|
|
125
124
|
}
|
|
126
|
-
adb.setLogcatListener(this._logcatWebsocketListener);
|
|
125
|
+
this.adb.setLogcatListener(this._logcatWebsocketListener);
|
|
127
126
|
|
|
128
127
|
ws.on('close', (code, reason) => {
|
|
129
128
|
if (!_.isEmpty(this._logcatWebsocketListener)) {
|
|
130
129
|
try {
|
|
131
|
-
adb.removeLogcatListener(this._logcatWebsocketListener);
|
|
130
|
+
this.adb.removeLogcatListener(this._logcatWebsocketListener);
|
|
132
131
|
} catch (ign) {}
|
|
133
132
|
this._logcatWebsocketListener = undefined;
|
|
134
133
|
}
|
|
@@ -191,11 +191,10 @@ class MediaProjectionRecorder {
|
|
|
191
191
|
*/
|
|
192
192
|
const MediaProjectionMixin = {
|
|
193
193
|
async mobileStartMediaProjectionRecording(options = {}) {
|
|
194
|
-
|
|
195
|
-
await verifyMediaProjectionRecordingIsSupported(adb);
|
|
194
|
+
await verifyMediaProjectionRecordingIsSupported(this.adb);
|
|
196
195
|
|
|
197
196
|
const {resolution, priority, maxDurationSec, filename} = options;
|
|
198
|
-
const recorder = new MediaProjectionRecorder(adb);
|
|
197
|
+
const recorder = new MediaProjectionRecorder(this.adb);
|
|
199
198
|
const fname = adjustMediaExtension(filename || moment().format(DEFAULT_FILENAME_FORMAT));
|
|
200
199
|
const didStart = await recorder.start({
|
|
201
200
|
resolution,
|
|
@@ -214,18 +213,16 @@ const MediaProjectionMixin = {
|
|
|
214
213
|
},
|
|
215
214
|
|
|
216
215
|
async mobileIsMediaProjectionRecordingRunning() {
|
|
217
|
-
|
|
218
|
-
await verifyMediaProjectionRecordingIsSupported(adb);
|
|
216
|
+
await verifyMediaProjectionRecordingIsSupported(this.adb);
|
|
219
217
|
|
|
220
|
-
const recorder = new MediaProjectionRecorder(adb);
|
|
218
|
+
const recorder = new MediaProjectionRecorder(this.adb);
|
|
221
219
|
return await recorder.isRunning();
|
|
222
220
|
},
|
|
223
221
|
|
|
224
222
|
async mobileStopMediaProjectionRecording(options = {}) {
|
|
225
|
-
|
|
226
|
-
await verifyMediaProjectionRecordingIsSupported(adb);
|
|
223
|
+
await verifyMediaProjectionRecordingIsSupported(this.adb);
|
|
227
224
|
|
|
228
|
-
const recorder = new MediaProjectionRecorder(adb);
|
|
225
|
+
const recorder = new MediaProjectionRecorder(this.adb);
|
|
229
226
|
if (await recorder.stop()) {
|
|
230
227
|
this.log.info(
|
|
231
228
|
'Successfully stopped a media projection recording. Pulling the recorded media'
|
package/lib/commands/network.js
CHANGED
|
@@ -30,16 +30,15 @@ const SUPPORTED_SERVICE_NAMES = /** @type {const} */ ([
|
|
|
30
30
|
*/
|
|
31
31
|
const NetworkMixin = {
|
|
32
32
|
async getNetworkConnection() {
|
|
33
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
34
33
|
this.log.info('Getting network connection');
|
|
35
|
-
let airplaneModeOn = await adb.isAirplaneModeOn();
|
|
34
|
+
let airplaneModeOn = await this.adb.isAirplaneModeOn();
|
|
36
35
|
let connection = airplaneModeOn ? AIRPLANE_MODE_MASK : 0;
|
|
37
36
|
|
|
38
37
|
// no need to check anything else if we are in airplane mode
|
|
39
38
|
if (!airplaneModeOn) {
|
|
40
39
|
let wifiOn = await this.isWifiOn();
|
|
41
40
|
connection |= wifiOn ? WIFI_MASK : 0;
|
|
42
|
-
let dataOn = await adb.isDataOn();
|
|
41
|
+
let dataOn = await this.adb.isDataOn();
|
|
43
42
|
connection |= dataOn ? DATA_MASK : 0;
|
|
44
43
|
}
|
|
45
44
|
|
|
@@ -47,12 +46,11 @@ const NetworkMixin = {
|
|
|
47
46
|
},
|
|
48
47
|
|
|
49
48
|
async isWifiOn() {
|
|
50
|
-
return await
|
|
49
|
+
return await this.adb.isWifiOn();
|
|
51
50
|
},
|
|
52
51
|
|
|
53
52
|
async mobileSetConnectivity(opts = {}) {
|
|
54
53
|
const {wifi, data, airplaneMode} = opts;
|
|
55
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
56
54
|
if (_.every([wifi, data, airplaneMode], _.isUndefined)) {
|
|
57
55
|
throw new errors.InvalidArgumentError(
|
|
58
56
|
`Either one of ${JSON.stringify(SUPPORTED_SERVICE_NAMES)} options must be provided`
|
|
@@ -69,16 +67,16 @@ const NetworkMixin = {
|
|
|
69
67
|
/** @type {(Promise<any>|(() => Promise<any>))[]} */
|
|
70
68
|
const setters = [];
|
|
71
69
|
if (!_.isUndefined(wifi) && currentState.wifi !== Boolean(wifi)) {
|
|
72
|
-
setters.push(adb.setWifiState(wifi, this.isEmulator()));
|
|
70
|
+
setters.push(this.adb.setWifiState(wifi, this.isEmulator()));
|
|
73
71
|
}
|
|
74
72
|
if (!_.isUndefined(data) && currentState.data !== Boolean(data)) {
|
|
75
|
-
setters.push(adb.setDataState(data, this.isEmulator()));
|
|
73
|
+
setters.push(this.adb.setDataState(data, this.isEmulator()));
|
|
76
74
|
}
|
|
77
75
|
if (!_.isUndefined(airplaneMode) && currentState.airplaneMode !== Boolean(airplaneMode)) {
|
|
78
76
|
setters.push(async () => {
|
|
79
|
-
await adb.setAirplaneMode(airplaneMode);
|
|
80
|
-
if ((await adb.getApiLevel()) < 30) {
|
|
81
|
-
await adb.broadcastAirplaneMode(airplaneMode);
|
|
77
|
+
await this.adb.setAirplaneMode(airplaneMode);
|
|
78
|
+
if ((await this.adb.getApiLevel()) < 30) {
|
|
79
|
+
await this.adb.broadcastAirplaneMode(airplaneMode);
|
|
82
80
|
}
|
|
83
81
|
});
|
|
84
82
|
}
|
|
@@ -104,13 +102,12 @@ const NetworkMixin = {
|
|
|
104
102
|
`suported: ${SUPPORTED_SERVICE_NAMES}`
|
|
105
103
|
);
|
|
106
104
|
}
|
|
107
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
108
105
|
|
|
109
106
|
const statePromises = {
|
|
110
|
-
wifi: B.resolve(svcs.includes(WIFI_KEY_NAME) ? adb.isWifiOn() : undefined),
|
|
111
|
-
data: B.resolve(svcs.includes(DATA_KEY_NAME) ? adb.isDataOn() : undefined),
|
|
107
|
+
wifi: B.resolve(svcs.includes(WIFI_KEY_NAME) ? this.adb.isWifiOn() : undefined),
|
|
108
|
+
data: B.resolve(svcs.includes(DATA_KEY_NAME) ? this.adb.isDataOn() : undefined),
|
|
112
109
|
airplaneMode: B.resolve(
|
|
113
|
-
svcs.includes(AIRPLANE_MODE_KEY_NAME) ? adb.isAirplaneModeOn() : undefined
|
|
110
|
+
svcs.includes(AIRPLANE_MODE_KEY_NAME) ? this.adb.isAirplaneModeOn() : undefined
|
|
114
111
|
),
|
|
115
112
|
};
|
|
116
113
|
await B.all(_.values(statePromises));
|
|
@@ -133,11 +130,10 @@ const NetworkMixin = {
|
|
|
133
130
|
const isWiFiEnabled = (currentState & WIFI_MASK) !== 0;
|
|
134
131
|
const isDataEnabled = (currentState & DATA_MASK) !== 0;
|
|
135
132
|
|
|
136
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
137
133
|
if (shouldEnableAirplaneMode !== isAirplaneModeEnabled) {
|
|
138
|
-
await adb.setAirplaneMode(shouldEnableAirplaneMode);
|
|
139
|
-
if ((await adb.getApiLevel()) < 30) {
|
|
140
|
-
await adb.broadcastAirplaneMode(shouldEnableAirplaneMode);
|
|
134
|
+
await this.adb.setAirplaneMode(shouldEnableAirplaneMode);
|
|
135
|
+
if ((await this.adb.getApiLevel()) < 30) {
|
|
136
|
+
await this.adb.broadcastAirplaneMode(shouldEnableAirplaneMode);
|
|
141
137
|
}
|
|
142
138
|
} else {
|
|
143
139
|
this.log.info(
|
|
@@ -151,7 +147,7 @@ const NetworkMixin = {
|
|
|
151
147
|
this.log.info(
|
|
152
148
|
'Not changing data connection/Wi-Fi states, since they are already set to expected values'
|
|
153
149
|
);
|
|
154
|
-
if (await adb.isAirplaneModeOn()) {
|
|
150
|
+
if (await this.adb.isAirplaneModeOn()) {
|
|
155
151
|
return AIRPLANE_MODE_MASK | currentState;
|
|
156
152
|
}
|
|
157
153
|
return ~AIRPLANE_MODE_MASK & currentState;
|
|
@@ -174,46 +170,43 @@ const NetworkMixin = {
|
|
|
174
170
|
`${shouldEnableDataConnection ? 'enabled' : 'disabled'}`
|
|
175
171
|
);
|
|
176
172
|
} else {
|
|
177
|
-
await adb.setDataState(shouldEnableDataConnection, this.isEmulator());
|
|
173
|
+
await this.adb.setDataState(shouldEnableDataConnection, this.isEmulator());
|
|
178
174
|
}
|
|
179
175
|
|
|
180
176
|
return await this.getNetworkConnection();
|
|
181
177
|
},
|
|
182
178
|
|
|
183
179
|
async setWifiState(wifi) {
|
|
184
|
-
await
|
|
180
|
+
await this.adb.setWifiState(wifi, this.isEmulator());
|
|
185
181
|
},
|
|
186
182
|
|
|
187
183
|
async toggleData() {
|
|
188
|
-
|
|
189
|
-
let data = !(await adb.isDataOn());
|
|
184
|
+
let data = !(await this.adb.isDataOn());
|
|
190
185
|
this.log.info(`Turning network data ${data ? 'on' : 'off'}`);
|
|
191
|
-
await adb.setWifiAndData({data}, this.isEmulator());
|
|
186
|
+
await this.adb.setWifiAndData({data}, this.isEmulator());
|
|
192
187
|
},
|
|
193
188
|
|
|
194
189
|
async toggleWiFi() {
|
|
195
|
-
|
|
196
|
-
let wifi = !(await adb.isWifiOn());
|
|
190
|
+
let wifi = !(await this.adb.isWifiOn());
|
|
197
191
|
this.log.info(`Turning WiFi ${wifi ? 'on' : 'off'}`);
|
|
198
|
-
await adb.setWifiAndData({wifi}, this.isEmulator());
|
|
192
|
+
await this.adb.setWifiAndData({wifi}, this.isEmulator());
|
|
199
193
|
},
|
|
200
194
|
|
|
201
195
|
async toggleFlightMode() {
|
|
202
|
-
const adb = /** @type {ADB} */ (this.adb);
|
|
203
196
|
/*
|
|
204
197
|
* TODO: Implement isRealDevice(). This method fails on
|
|
205
198
|
* real devices, it should throw a NotYetImplementedError
|
|
206
199
|
*/
|
|
207
|
-
let flightMode = !(await adb.isAirplaneModeOn());
|
|
200
|
+
let flightMode = !(await this.adb.isAirplaneModeOn());
|
|
208
201
|
this.log.info(`Turning flight mode ${flightMode ? 'on' : 'off'}`);
|
|
209
|
-
await adb.setAirplaneMode(flightMode);
|
|
210
|
-
if ((await adb.getApiLevel()) < 30) {
|
|
211
|
-
await adb.broadcastAirplaneMode(flightMode);
|
|
202
|
+
await this.adb.setAirplaneMode(flightMode);
|
|
203
|
+
if ((await this.adb.getApiLevel()) < 30) {
|
|
204
|
+
await this.adb.broadcastAirplaneMode(flightMode);
|
|
212
205
|
}
|
|
213
206
|
},
|
|
214
207
|
|
|
215
208
|
async setGeoLocation(location) {
|
|
216
|
-
await
|
|
209
|
+
await this.adb.setGeoLocation(location, this.isEmulator());
|
|
217
210
|
try {
|
|
218
211
|
return await this.getGeoLocation();
|
|
219
212
|
} catch (e) {
|
|
@@ -231,11 +224,11 @@ const NetworkMixin = {
|
|
|
231
224
|
|
|
232
225
|
async mobileRefreshGpsCache(opts = {}) {
|
|
233
226
|
const {timeoutMs} = opts;
|
|
234
|
-
await
|
|
227
|
+
await this.adb.refreshGeoLocationCache(timeoutMs);
|
|
235
228
|
},
|
|
236
229
|
|
|
237
230
|
async getGeoLocation() {
|
|
238
|
-
const {latitude, longitude, altitude} = await
|
|
231
|
+
const {latitude, longitude, altitude} = await this.adb.getGeoLocation();
|
|
239
232
|
return {
|
|
240
233
|
latitude: parseFloat(String(latitude)) || GEO_EPSILON,
|
|
241
234
|
longitude: parseFloat(String(longitude)) || GEO_EPSILON,
|
|
@@ -244,7 +237,7 @@ const NetworkMixin = {
|
|
|
244
237
|
},
|
|
245
238
|
|
|
246
239
|
async isLocationServicesEnabled() {
|
|
247
|
-
return (await
|
|
240
|
+
return (await this.adb.getLocationProviders()).includes('gps');
|
|
248
241
|
},
|
|
249
242
|
|
|
250
243
|
async toggleLocationServices() {
|
|
@@ -254,7 +247,7 @@ const NetworkMixin = {
|
|
|
254
247
|
`Current GPS state: ${isGpsEnabled}. ` +
|
|
255
248
|
`The service is going to be ${isGpsEnabled ? 'disabled' : 'enabled'}`
|
|
256
249
|
);
|
|
257
|
-
await
|
|
250
|
+
await this.adb.toggleGPSLocationProvider(!isGpsEnabled);
|
|
258
251
|
},
|
|
259
252
|
};
|
|
260
253
|
|
|
@@ -163,12 +163,12 @@ async function getMemoryInfo(packageName, retries = 2) {
|
|
|
163
163
|
`'${MEMINFO_TITLES.NATIVE}|${MEMINFO_TITLES.DALVIK}|${MEMINFO_TITLES.EGL}` +
|
|
164
164
|
`|${MEMINFO_TITLES.GL}|${MEMINFO_TITLES.TOTAL}'`,
|
|
165
165
|
];
|
|
166
|
-
const data = await
|
|
166
|
+
const data = await this.adb.shell(cmd);
|
|
167
167
|
if (!data) {
|
|
168
168
|
throw new Error('No data from dumpsys');
|
|
169
169
|
}
|
|
170
170
|
const valDict = {totalPrivateDirty: ''};
|
|
171
|
-
const apiLevel = await
|
|
171
|
+
const apiLevel = await this.adb.getApiLevel();
|
|
172
172
|
for (const line of data.split('\n')) {
|
|
173
173
|
const entries = line.trim().split(/\s+/).filter(Boolean);
|
|
174
174
|
if (apiLevel >= 30) {
|
|
@@ -199,7 +199,7 @@ async function getNetworkTrafficInfo(retries = 2) {
|
|
|
199
199
|
let bucketDuration, bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations;
|
|
200
200
|
|
|
201
201
|
let cmd = ['dumpsys', 'netstats'];
|
|
202
|
-
let data = await
|
|
202
|
+
let data = await this.adb.shell(cmd);
|
|
203
203
|
if (!data) throw new Error('No data from dumpsys'); //eslint-disable-line curly
|
|
204
204
|
|
|
205
205
|
// In case of network traffic information, it is different for the return data between emulator and real device.
|
|
@@ -389,7 +389,7 @@ async function getCPUInfo(packageName, retries = 2) {
|
|
|
389
389
|
/** @type {string} */
|
|
390
390
|
let output;
|
|
391
391
|
try {
|
|
392
|
-
output = await
|
|
392
|
+
output = await this.adb.shell(['dumpsys', 'cpuinfo']);
|
|
393
393
|
} catch (e) {
|
|
394
394
|
const err = /** @type {import('teen_process').ExecError} */ (e);
|
|
395
395
|
if (err.stderr) {
|
|
@@ -423,7 +423,7 @@ async function getCPUInfo(packageName, retries = 2) {
|
|
|
423
423
|
async function getBatteryInfo(retries = 2) {
|
|
424
424
|
return await retryInterval(retries, RETRY_PAUSE_MS, async () => {
|
|
425
425
|
let cmd = ['dumpsys', 'battery', '|', 'grep', 'level'];
|
|
426
|
-
let data = await
|
|
426
|
+
let data = await this.adb.shell(cmd);
|
|
427
427
|
if (!data) throw new Error('No data from dumpsys'); //eslint-disable-line curly
|
|
428
428
|
|
|
429
429
|
let power = parseInt((data.split(':')[1] || '').trim(), 10);
|