appium-android-driver 7.8.3 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/build/lib/commands/app-management.d.ts +129 -5
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +433 -128
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.d.ts +17 -4
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js +32 -33
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/context/cache.d.ts +19 -0
- package/build/lib/commands/context/cache.d.ts.map +1 -0
- package/build/lib/commands/context/cache.js +32 -0
- package/build/lib/commands/context/cache.js.map +1 -0
- package/build/lib/commands/context/exports.d.ts +141 -0
- package/build/lib/commands/context/exports.d.ts.map +1 -0
- package/build/lib/commands/context/exports.js +351 -0
- package/build/lib/commands/context/exports.js.map +1 -0
- package/build/lib/commands/context/helpers.d.ts +98 -0
- package/build/lib/commands/context/helpers.d.ts.map +1 -0
- package/build/lib/commands/context/helpers.js +715 -0
- package/build/lib/commands/context/helpers.js.map +1 -0
- package/build/lib/commands/device/common.d.ts +23 -0
- package/build/lib/commands/device/common.d.ts.map +1 -0
- package/build/lib/commands/device/common.js +230 -0
- package/build/lib/commands/device/common.js.map +1 -0
- package/build/lib/commands/device/emulator-actions.d.ts +114 -0
- package/build/lib/commands/device/emulator-actions.d.ts.map +1 -0
- package/build/lib/commands/device/emulator-actions.js +197 -0
- package/build/lib/commands/device/emulator-actions.js.map +1 -0
- package/build/lib/commands/device/emulator-console.d.ts +7 -0
- package/build/lib/commands/device/emulator-console.d.ts.map +1 -0
- package/build/lib/commands/device/emulator-console.js +24 -0
- package/build/lib/commands/device/emulator-console.js.map +1 -0
- package/build/lib/commands/device/utils.d.ts +50 -0
- package/build/lib/commands/device/utils.d.ts.map +1 -0
- package/build/lib/commands/device/utils.js +238 -0
- package/build/lib/commands/device/utils.js.map +1 -0
- package/build/lib/commands/deviceidle.d.ts +8 -5
- package/build/lib/commands/deviceidle.d.ts.map +1 -1
- package/build/lib/commands/deviceidle.js +31 -37
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/element.d.ts +99 -5
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +152 -116
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts +12 -4
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +83 -78
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +42 -5
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +230 -194
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +5 -4
- package/build/lib/commands/find.d.ts.map +1 -1
- package/build/lib/commands/find.js +7 -10
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts +45 -0
- package/build/lib/commands/geolocation.d.ts.map +1 -0
- package/build/lib/commands/geolocation.js +182 -0
- package/build/lib/commands/geolocation.js.map +1 -0
- package/build/lib/commands/ime.d.ts +25 -5
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js +59 -42
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/intent.d.ts +56 -5
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +135 -83
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +58 -4
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js +119 -17
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/lock/exports.d.ts +301 -0
- package/build/lib/commands/lock/exports.d.ts.map +1 -0
- package/build/lib/commands/lock/exports.js +121 -0
- package/build/lib/commands/lock/exports.js.map +1 -0
- package/build/lib/commands/lock/helpers.d.ts +349 -0
- package/build/lib/commands/lock/helpers.d.ts.map +1 -0
- package/build/lib/commands/lock/helpers.js +375 -0
- package/build/lib/commands/lock/helpers.js.map +1 -0
- package/build/lib/commands/log.d.ts +59 -5
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +150 -140
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +16 -5
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +69 -58
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/memory.d.ts +9 -5
- package/build/lib/commands/memory.d.ts.map +1 -1
- package/build/lib/commands/memory.js +19 -24
- package/build/lib/commands/memory.js.map +1 -1
- package/build/lib/commands/misc.d.ts +42 -0
- package/build/lib/commands/misc.d.ts.map +1 -0
- package/build/lib/commands/misc.js +100 -0
- package/build/lib/commands/misc.js.map +1 -0
- package/build/lib/commands/network.d.ts +61 -5
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +196 -189
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +67 -27
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js +105 -80
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +12 -6
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +65 -62
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +44 -5
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js +131 -126
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/resources.d.ts +16 -0
- package/build/lib/commands/resources.d.ts.map +1 -0
- package/build/lib/commands/resources.js +91 -0
- package/build/lib/commands/resources.js.map +1 -0
- package/build/lib/commands/shell.d.ts +8 -5
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/shell.js +29 -33
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +34 -6
- package/build/lib/commands/streamscreen.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js +166 -162
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +18 -13
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +68 -64
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/time.d.ts +14 -0
- package/build/lib/commands/time.d.ts.map +1 -0
- package/build/lib/commands/time.js +39 -0
- package/build/lib/commands/time.js.map +1 -0
- package/build/lib/commands/touch.d.ts +99 -6
- package/build/lib/commands/touch.d.ts.map +1 -1
- package/build/lib/commands/touch.js +399 -280
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/commands/types.d.ts +110 -2
- package/build/lib/commands/types.d.ts.map +1 -1
- package/build/lib/doctor/checks.d.ts.map +1 -1
- package/build/lib/doctor/checks.js +4 -4
- package/build/lib/doctor/checks.js.map +1 -1
- package/build/lib/driver.d.ts +224 -27
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +232 -7
- package/build/lib/driver.js.map +1 -1
- package/build/lib/index.d.ts +1 -4
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +1 -13
- package/build/lib/index.js.map +1 -1
- package/build/lib/logger.js.map +1 -1
- package/build/lib/method-map.d.ts +0 -23
- package/build/lib/method-map.d.ts.map +1 -1
- package/build/lib/method-map.js +0 -11
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/utils.d.ts +12 -0
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +38 -2
- package/build/lib/utils.js.map +1 -1
- package/lib/commands/app-management.js +470 -145
- package/lib/commands/appearance.js +29 -36
- package/lib/commands/context/cache.js +29 -0
- package/lib/commands/context/exports.js +379 -0
- package/lib/commands/context/helpers.js +802 -0
- package/lib/commands/device/common.js +264 -0
- package/lib/commands/device/emulator-actions.js +194 -0
- package/lib/commands/device/emulator-console.js +24 -0
- package/lib/commands/device/utils.js +285 -0
- package/lib/commands/deviceidle.js +31 -44
- package/lib/commands/element.js +149 -142
- package/lib/commands/execute.js +86 -87
- package/lib/commands/file-actions.js +249 -222
- package/lib/commands/find.ts +13 -19
- package/lib/commands/geolocation.js +179 -0
- package/lib/commands/ime.js +53 -45
- package/lib/commands/intent.js +149 -91
- package/lib/commands/keyboard.js +114 -17
- package/lib/commands/lock/exports.js +139 -0
- package/lib/commands/lock/helpers.js +379 -0
- package/lib/commands/log.js +170 -166
- package/lib/commands/media-projection.js +75 -70
- package/lib/commands/memory.js +17 -29
- package/lib/commands/misc.js +94 -0
- package/lib/commands/network.js +209 -223
- package/lib/commands/performance.js +88 -73
- package/lib/commands/permissions.js +83 -84
- package/lib/commands/recordscreen.js +171 -170
- package/lib/commands/resources.js +96 -0
- package/lib/commands/shell.js +28 -42
- package/lib/commands/streamscreen.js +207 -206
- package/lib/commands/system-bars.js +76 -77
- package/lib/commands/time.js +36 -0
- package/lib/commands/touch.js +442 -346
- package/lib/commands/types.ts +123 -2
- package/lib/doctor/checks.js +24 -16
- package/lib/driver.ts +454 -12
- package/lib/index.ts +1 -13
- package/lib/logger.js +1 -1
- package/lib/method-map.js +0 -11
- package/lib/utils.js +40 -3
- package/package.json +1 -1
- package/build/lib/commands/actions.d.ts +0 -8
- package/build/lib/commands/actions.d.ts.map +0 -1
- package/build/lib/commands/actions.js +0 -207
- package/build/lib/commands/actions.js.map +0 -1
- package/build/lib/commands/alert.d.ts +0 -8
- package/build/lib/commands/alert.d.ts.map +0 -1
- package/build/lib/commands/alert.js +0 -29
- package/build/lib/commands/alert.js.map +0 -1
- package/build/lib/commands/context.d.ts +0 -10
- package/build/lib/commands/context.d.ts.map +0 -1
- package/build/lib/commands/context.js +0 -431
- package/build/lib/commands/context.js.map +0 -1
- package/build/lib/commands/emu-console.d.ts +0 -7
- package/build/lib/commands/emu-console.d.ts.map +0 -1
- package/build/lib/commands/emu-console.js +0 -27
- package/build/lib/commands/emu-console.js.map +0 -1
- package/build/lib/commands/general.d.ts +0 -9
- package/build/lib/commands/general.d.ts.map +0 -1
- package/build/lib/commands/general.js +0 -293
- package/build/lib/commands/general.js.map +0 -1
- package/build/lib/commands/index.d.ts +0 -28
- package/build/lib/commands/index.d.ts.map +0 -1
- package/build/lib/commands/index.js +0 -57
- package/build/lib/commands/index.js.map +0 -1
- package/build/lib/commands/mixins.d.ts +0 -747
- package/build/lib/commands/mixins.d.ts.map +0 -1
- package/build/lib/commands/mixins.js +0 -19
- package/build/lib/commands/mixins.js.map +0 -1
- package/build/lib/helpers/android.d.ts +0 -163
- package/build/lib/helpers/android.d.ts.map +0 -1
- package/build/lib/helpers/android.js +0 -818
- package/build/lib/helpers/android.js.map +0 -1
- package/build/lib/helpers/index.d.ts +0 -7
- package/build/lib/helpers/index.d.ts.map +0 -1
- package/build/lib/helpers/index.js +0 -29
- package/build/lib/helpers/index.js.map +0 -1
- package/build/lib/helpers/types.d.ts +0 -122
- package/build/lib/helpers/types.d.ts.map +0 -1
- package/build/lib/helpers/types.js +0 -3
- package/build/lib/helpers/types.js.map +0 -1
- package/build/lib/helpers/unlock.d.ts +0 -32
- package/build/lib/helpers/unlock.d.ts.map +0 -1
- package/build/lib/helpers/unlock.js +0 -273
- package/build/lib/helpers/unlock.js.map +0 -1
- package/build/lib/helpers/webview.d.ts +0 -74
- package/build/lib/helpers/webview.d.ts.map +0 -1
- package/build/lib/helpers/webview.js +0 -448
- package/build/lib/helpers/webview.js.map +0 -1
- package/lib/commands/actions.js +0 -244
- package/lib/commands/alert.js +0 -34
- package/lib/commands/context.js +0 -507
- package/lib/commands/emu-console.js +0 -31
- package/lib/commands/general.js +0 -343
- package/lib/commands/index.ts +0 -54
- package/lib/commands/mixins.ts +0 -976
- package/lib/helpers/android.ts +0 -1153
- package/lib/helpers/index.ts +0 -6
- package/lib/helpers/types.ts +0 -136
- package/lib/helpers/unlock.ts +0 -329
- package/lib/helpers/webview.ts +0 -610
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// @ts-check
|
|
3
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
4
|
};
|
|
6
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.mobileGetPermissions = exports.mobileChangePermissions = void 0;
|
|
7
7
|
const driver_1 = require("appium/driver");
|
|
8
8
|
const bluebird_1 = __importDefault(require("bluebird"));
|
|
9
9
|
const lodash_1 = __importDefault(require("lodash"));
|
|
10
10
|
const utils_1 = require("../utils");
|
|
11
|
-
const mixins_1 = require("./mixins");
|
|
12
11
|
const ALL_PERMISSIONS_MAGIC = 'all';
|
|
13
12
|
const PM_ACTION = Object.freeze({
|
|
14
13
|
GRANT: 'grant',
|
|
@@ -29,12 +28,66 @@ const PERMISSIONS_TYPE = Object.freeze({
|
|
|
29
28
|
GRANTED: 'granted',
|
|
30
29
|
REQUESTED: 'requested',
|
|
31
30
|
});
|
|
31
|
+
/**
|
|
32
|
+
* @this {import('../driver').AndroidDriver}
|
|
33
|
+
* @param {import('./types').ChangePermissionsOpts} opts
|
|
34
|
+
* @returns {Promise<void>}
|
|
35
|
+
*/
|
|
36
|
+
async function mobileChangePermissions(opts) {
|
|
37
|
+
const { permissions, appPackage = this.opts.appPackage, action = lodash_1.default.toLower(opts.target) === PERMISSION_TARGET.APPOPS
|
|
38
|
+
? APPOPS_ACTION.ALLOW
|
|
39
|
+
: PM_ACTION.GRANT, target = PERMISSION_TARGET.PM, } = opts;
|
|
40
|
+
if (lodash_1.default.isNil(permissions)) {
|
|
41
|
+
throw new driver_1.errors.InvalidArgumentError(`'permissions' argument is required`);
|
|
42
|
+
}
|
|
43
|
+
if (lodash_1.default.isEmpty(permissions)) {
|
|
44
|
+
throw new driver_1.errors.InvalidArgumentError(`'permissions' argument must not be empty`);
|
|
45
|
+
}
|
|
46
|
+
switch (lodash_1.default.toLower(target)) {
|
|
47
|
+
case PERMISSION_TARGET.PM:
|
|
48
|
+
return await changePermissionsViaPm.bind(this)(permissions, appPackage, lodash_1.default.toLower(action));
|
|
49
|
+
case PERMISSION_TARGET.APPOPS:
|
|
50
|
+
this.ensureFeatureEnabled(utils_1.ADB_SHELL_FEATURE);
|
|
51
|
+
return await changePermissionsViaAppops.bind(this)(permissions, appPackage, lodash_1.default.toLower(action));
|
|
52
|
+
default:
|
|
53
|
+
throw new driver_1.errors.InvalidArgumentError(`'target' argument must be one of: ${lodash_1.default.values(PERMISSION_TARGET)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.mobileChangePermissions = mobileChangePermissions;
|
|
57
|
+
/**
|
|
58
|
+
* @this {import('../driver').AndroidDriver}
|
|
59
|
+
* @param {import('./types').GetPermissionsOpts} [opts={}]
|
|
60
|
+
* @returns {Promise<string[]>}
|
|
61
|
+
*/
|
|
62
|
+
async function mobileGetPermissions(opts = {}) {
|
|
63
|
+
const { type = PERMISSIONS_TYPE.REQUESTED, appPackage = this.opts.appPackage } = opts;
|
|
64
|
+
/**
|
|
65
|
+
* @type {(pkg: string) => Promise<string[]>}
|
|
66
|
+
*/
|
|
67
|
+
let actionFunc;
|
|
68
|
+
switch (lodash_1.default.toLower(type)) {
|
|
69
|
+
case PERMISSIONS_TYPE.REQUESTED:
|
|
70
|
+
actionFunc = (pkg) => this.adb.getReqPermissions(pkg);
|
|
71
|
+
break;
|
|
72
|
+
case PERMISSIONS_TYPE.GRANTED:
|
|
73
|
+
actionFunc = (pkg) => this.adb.getGrantedPermissions(pkg);
|
|
74
|
+
break;
|
|
75
|
+
case PERMISSIONS_TYPE.DENIED:
|
|
76
|
+
actionFunc = (pkg) => this.adb.getDeniedPermissions(pkg);
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
throw new driver_1.errors.InvalidArgumentError(`Unknown permissions type '${type}'. ` +
|
|
80
|
+
`Only ${JSON.stringify(lodash_1.default.values(PERMISSIONS_TYPE))} types are supported`);
|
|
81
|
+
}
|
|
82
|
+
return await actionFunc(/** @type {string} */ (appPackage));
|
|
83
|
+
}
|
|
84
|
+
exports.mobileGetPermissions = mobileGetPermissions;
|
|
85
|
+
// #region Internal helpers
|
|
32
86
|
/**
|
|
33
87
|
* @this {AndroidDriver}
|
|
34
|
-
* @param {
|
|
35
|
-
* @param {
|
|
36
|
-
* @param {
|
|
37
|
-
* @todo FIXME: type this
|
|
88
|
+
* @param {string|string[]} permissions
|
|
89
|
+
* @param {string} appPackage
|
|
90
|
+
* @param {import('type-fest').ValueOf<PM_ACTION>} action
|
|
38
91
|
*/
|
|
39
92
|
async function changePermissionsViaPm(permissions, appPackage, action) {
|
|
40
93
|
if (!lodash_1.default.values(PM_ACTION).includes(action)) {
|
|
@@ -42,7 +95,7 @@ async function changePermissionsViaPm(permissions, appPackage, action) {
|
|
|
42
95
|
`Only ${JSON.stringify(lodash_1.default.values(PM_ACTION))} actions are supported`);
|
|
43
96
|
}
|
|
44
97
|
let affectedPermissions = lodash_1.default.isArray(permissions) ? permissions : [permissions];
|
|
45
|
-
if (lodash_1.default.toLower(permissions) === ALL_PERMISSIONS_MAGIC) {
|
|
98
|
+
if (lodash_1.default.isString(permissions) && lodash_1.default.toLower(permissions) === ALL_PERMISSIONS_MAGIC) {
|
|
46
99
|
const dumpsys = await this.adb.shell(['dumpsys', 'package', appPackage]);
|
|
47
100
|
const grantedPermissions = await this.adb.getGrantedPermissions(appPackage, dumpsys);
|
|
48
101
|
if (action === PM_ACTION.GRANT) {
|
|
@@ -66,17 +119,16 @@ async function changePermissionsViaPm(permissions, appPackage, action) {
|
|
|
66
119
|
}
|
|
67
120
|
/**
|
|
68
121
|
* @this {AndroidDriver}
|
|
69
|
-
* @param {
|
|
70
|
-
* @param {
|
|
71
|
-
* @param {
|
|
72
|
-
* @todo FIXME: type this
|
|
122
|
+
* @param {string|string[]} permissions
|
|
123
|
+
* @param {string} appPackage
|
|
124
|
+
* @param {import('type-fest').ValueOf<APPOPS_ACTION>} action
|
|
73
125
|
*/
|
|
74
126
|
async function changePermissionsViaAppops(permissions, appPackage, action) {
|
|
75
127
|
if (!lodash_1.default.values(APPOPS_ACTION).includes(action)) {
|
|
76
128
|
throw new driver_1.errors.InvalidArgumentError(`Unknown action '${action}'. ` +
|
|
77
129
|
`Only ${JSON.stringify(lodash_1.default.values(APPOPS_ACTION))} actions are supported`);
|
|
78
130
|
}
|
|
79
|
-
if (lodash_1.default.toLower(permissions) === ALL_PERMISSIONS_MAGIC) {
|
|
131
|
+
if (lodash_1.default.isString(permissions) && lodash_1.default.toLower(permissions) === ALL_PERMISSIONS_MAGIC) {
|
|
80
132
|
throw new driver_1.errors.InvalidArgumentError(`'${ALL_PERMISSIONS_MAGIC}' permission is only supported for ` +
|
|
81
133
|
`'${PERMISSION_TARGET.PM}' target. ` +
|
|
82
134
|
`Check AppOpsManager.java from Android platform sources to get the full list of supported AppOps permissions`);
|
|
@@ -84,56 +136,7 @@ async function changePermissionsViaAppops(permissions, appPackage, action) {
|
|
|
84
136
|
const promises = (lodash_1.default.isArray(permissions) ? permissions : [permissions]).map((permission) => this.adb.shell(['appops', 'set', appPackage, permission, action]));
|
|
85
137
|
await bluebird_1.default.all(promises);
|
|
86
138
|
}
|
|
87
|
-
|
|
88
|
-
* @type {import('./mixins').PermissionsMixin & ThisType<import('../driver').AndroidDriver>}
|
|
89
|
-
* @satisfies {import('@appium/types').ExternalDriver}
|
|
90
|
-
*/
|
|
91
|
-
const PermissionsMixin = {
|
|
92
|
-
async mobileChangePermissions(opts) {
|
|
93
|
-
const { permissions, appPackage = this.opts.appPackage, action = lodash_1.default.toLower(opts.target) === PERMISSION_TARGET.APPOPS
|
|
94
|
-
? APPOPS_ACTION.ALLOW
|
|
95
|
-
: PM_ACTION.GRANT, target = PERMISSION_TARGET.PM, } = opts;
|
|
96
|
-
if (lodash_1.default.isNil(permissions)) {
|
|
97
|
-
throw new driver_1.errors.InvalidArgumentError(`'permissions' argument is required`);
|
|
98
|
-
}
|
|
99
|
-
if (lodash_1.default.isEmpty(permissions)) {
|
|
100
|
-
throw new driver_1.errors.InvalidArgumentError(`'permissions' argument must not be empty`);
|
|
101
|
-
}
|
|
102
|
-
switch (lodash_1.default.toLower(target)) {
|
|
103
|
-
case PERMISSION_TARGET.PM:
|
|
104
|
-
return await changePermissionsViaPm.bind(this)(permissions, appPackage, lodash_1.default.toLower(action));
|
|
105
|
-
case PERMISSION_TARGET.APPOPS:
|
|
106
|
-
this.ensureFeatureEnabled(utils_1.ADB_SHELL_FEATURE);
|
|
107
|
-
return await changePermissionsViaAppops.bind(this)(permissions, appPackage, lodash_1.default.toLower(action));
|
|
108
|
-
default:
|
|
109
|
-
throw new driver_1.errors.InvalidArgumentError(`'target' argument must be one of: ${lodash_1.default.values(PERMISSION_TARGET)}`);
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
async mobileGetPermissions(opts = {}) {
|
|
113
|
-
const { type = PERMISSIONS_TYPE.REQUESTED, appPackage = this.opts.appPackage } = opts;
|
|
114
|
-
/**
|
|
115
|
-
* @type {(pkg: string) => Promise<string[]>}
|
|
116
|
-
*/
|
|
117
|
-
let actionFunc;
|
|
118
|
-
switch (lodash_1.default.toLower(type)) {
|
|
119
|
-
case PERMISSIONS_TYPE.REQUESTED:
|
|
120
|
-
actionFunc = (pkg) => this.adb.getReqPermissions(pkg);
|
|
121
|
-
break;
|
|
122
|
-
case PERMISSIONS_TYPE.GRANTED:
|
|
123
|
-
actionFunc = (pkg) => this.adb.getGrantedPermissions(pkg);
|
|
124
|
-
break;
|
|
125
|
-
case PERMISSIONS_TYPE.DENIED:
|
|
126
|
-
actionFunc = (pkg) => this.adb.getDeniedPermissions(pkg);
|
|
127
|
-
break;
|
|
128
|
-
default:
|
|
129
|
-
throw new driver_1.errors.InvalidArgumentError(`Unknown permissions type '${type}'. ` +
|
|
130
|
-
`Only ${JSON.stringify(lodash_1.default.values(PERMISSIONS_TYPE))} types are supported`);
|
|
131
|
-
}
|
|
132
|
-
return await actionFunc(/** @type {string} */ (appPackage));
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
(0, mixins_1.mixin)(PermissionsMixin);
|
|
136
|
-
exports.default = PermissionsMixin;
|
|
139
|
+
// #endregion
|
|
137
140
|
/**
|
|
138
141
|
* @typedef {import('appium-adb').ADB} ADB
|
|
139
142
|
* @typedef {import('../driver').AndroidDriver} AndroidDriver
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../lib/commands/permissions.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../lib/commands/permissions.js"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,47 @@
|
|
|
1
|
-
export default RecordScreenMixin;
|
|
2
|
-
export type ADB = import('appium-adb').ADB;
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
5
|
-
* @
|
|
2
|
+
*
|
|
3
|
+
* @this {import('../driver').AndroidDriver}
|
|
4
|
+
* @param {import('./types').StartScreenRecordingOpts} [options={}]
|
|
5
|
+
* @returns {Promise<string>}
|
|
6
|
+
*/
|
|
7
|
+
export function startRecordingScreen(this: import("../driver").AndroidDriver, options?: import("./types").StartScreenRecordingOpts | undefined): Promise<string>;
|
|
8
|
+
export class startRecordingScreen {
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @this {import('../driver').AndroidDriver}
|
|
12
|
+
* @param {import('./types').StartScreenRecordingOpts} [options={}]
|
|
13
|
+
* @returns {Promise<string>}
|
|
14
|
+
*/
|
|
15
|
+
constructor(this: import("../driver").AndroidDriver, options?: import("./types").StartScreenRecordingOpts | undefined);
|
|
16
|
+
_screenRecordingProperties: {
|
|
17
|
+
timer: timing.Timer;
|
|
18
|
+
videoSize: string | undefined;
|
|
19
|
+
timeLimit: string | number;
|
|
20
|
+
currentTimeLimit: string | number;
|
|
21
|
+
bitRate: string | number | undefined;
|
|
22
|
+
bugReport: boolean | undefined;
|
|
23
|
+
records: never[];
|
|
24
|
+
recordingProcess: null;
|
|
25
|
+
stopped: boolean;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @this {import('../driver').AndroidDriver}
|
|
31
|
+
* @param {import('./types').StopScreenRecordingOpts} [options={}]
|
|
32
|
+
* @returns {Promise<string>}
|
|
6
33
|
*/
|
|
7
|
-
|
|
34
|
+
export function stopRecordingScreen(this: import("../driver").AndroidDriver, options?: import("./types").StopScreenRecordingOpts | undefined): Promise<string>;
|
|
35
|
+
export class stopRecordingScreen {
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @this {import('../driver').AndroidDriver}
|
|
39
|
+
* @param {import('./types').StopScreenRecordingOpts} [options={}]
|
|
40
|
+
* @returns {Promise<string>}
|
|
41
|
+
*/
|
|
42
|
+
constructor(this: import("../driver").AndroidDriver, options?: import("./types").StopScreenRecordingOpts | undefined);
|
|
43
|
+
_screenRecordingProperties: any;
|
|
44
|
+
}
|
|
45
|
+
export type ADB = import('appium-adb').ADB;
|
|
46
|
+
import { timing } from '@appium/support';
|
|
8
47
|
//# sourceMappingURL=recordscreen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recordscreen.d.ts","sourceRoot":"","sources":["../../../lib/commands/recordscreen.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"recordscreen.d.ts","sourceRoot":"","sources":["../../../lib/commands/recordscreen.js"],"names":[],"mappings":"AAiBA;;;;;GAKG;AACH,iJAFa,QAAQ,MAAM,CAAC,CAsD3B;;IA1DD;;;;;OAKG;IACH,uHAoDC;IAxBG;;;;;;;;;;MAA2C;;AA0B/C;;;;;GAKG;AACH,+IAFa,QAAQ,MAAM,CAAC,CAiF3B;;IArFD;;;;;OAKG;IACH,sHA+EC;IAFG,gCAA2C;;kBA4LlC,OAAO,YAAY,EAAE,GAAG;uBA5VgB,iBAAiB"}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// @ts-check
|
|
3
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
4
|
};
|
|
6
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.stopRecordingScreen = exports.startRecordingScreen = void 0;
|
|
7
7
|
const support_1 = require("@appium/support");
|
|
8
8
|
const asyncbox_1 = require("asyncbox");
|
|
9
9
|
const lodash_1 = __importDefault(require("lodash"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const teen_process_1 = require("teen_process");
|
|
12
|
-
const mixins_1 = require("./mixins");
|
|
13
12
|
const RETRY_PAUSE = 300;
|
|
14
13
|
const RETRY_TIMEOUT = 5000;
|
|
15
14
|
const MAX_RECORDING_TIME_SEC = 60 * 3;
|
|
@@ -20,6 +19,122 @@ const SCREENRECORD_BINARY = 'screenrecord';
|
|
|
20
19
|
const DEFAULT_EXT = '.mp4';
|
|
21
20
|
const MIN_EMULATOR_API_LEVEL = 27;
|
|
22
21
|
const FFMPEG_BINARY = `ffmpeg${support_1.system.isWindows() ? '.exe' : ''}`;
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @this {import('../driver').AndroidDriver}
|
|
25
|
+
* @param {import('./types').StartScreenRecordingOpts} [options={}]
|
|
26
|
+
* @returns {Promise<string>}
|
|
27
|
+
*/
|
|
28
|
+
async function startRecordingScreen(options = {}) {
|
|
29
|
+
await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
|
|
30
|
+
let result = '';
|
|
31
|
+
const { videoSize, timeLimit = DEFAULT_RECORDING_TIME_SEC, bugReport, bitRate, forceRestart, } = options;
|
|
32
|
+
if (!forceRestart) {
|
|
33
|
+
result = await this.stopRecordingScreen(options);
|
|
34
|
+
}
|
|
35
|
+
if (await terminateBackgroundScreenRecording(this.adb, true)) {
|
|
36
|
+
this.log.warn(`There were some ${SCREENRECORD_BINARY} process leftovers running ` +
|
|
37
|
+
`in the background. Make sure you stop screen recording each time after it is started, ` +
|
|
38
|
+
`otherwise the recorded media might quickly exceed all the free space on the device under test.`);
|
|
39
|
+
}
|
|
40
|
+
if (!lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
41
|
+
// XXX: this doesn't need to be done in serial, does it?
|
|
42
|
+
for (const record of this._screenRecordingProperties.records || []) {
|
|
43
|
+
await this.adb.rimraf(record);
|
|
44
|
+
}
|
|
45
|
+
this._screenRecordingProperties = undefined;
|
|
46
|
+
}
|
|
47
|
+
const timeout = parseFloat(String(timeLimit));
|
|
48
|
+
if (isNaN(timeout) || timeout > MAX_TIME_SEC || timeout <= 0) {
|
|
49
|
+
throw new Error(`The timeLimit value must be in range [1, ${MAX_TIME_SEC}] seconds. ` +
|
|
50
|
+
`The value of '${timeLimit}' has been passed instead.`);
|
|
51
|
+
}
|
|
52
|
+
this._screenRecordingProperties = {
|
|
53
|
+
timer: new support_1.timing.Timer().start(),
|
|
54
|
+
videoSize,
|
|
55
|
+
timeLimit,
|
|
56
|
+
currentTimeLimit: timeLimit,
|
|
57
|
+
bitRate,
|
|
58
|
+
bugReport,
|
|
59
|
+
records: [],
|
|
60
|
+
recordingProcess: null,
|
|
61
|
+
stopped: false,
|
|
62
|
+
};
|
|
63
|
+
await scheduleScreenRecord.bind(this)(this._screenRecordingProperties);
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
exports.startRecordingScreen = startRecordingScreen;
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
* @this {import('../driver').AndroidDriver}
|
|
70
|
+
* @param {import('./types').StopScreenRecordingOpts} [options={}]
|
|
71
|
+
* @returns {Promise<string>}
|
|
72
|
+
*/
|
|
73
|
+
async function stopRecordingScreen(options = {}) {
|
|
74
|
+
await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
|
|
75
|
+
if (!lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
76
|
+
this._screenRecordingProperties.stopped = true;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await terminateBackgroundScreenRecording(this.adb, false);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
this.log.warn(/** @type {Error} */ (err).message);
|
|
83
|
+
if (!lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
84
|
+
this.log.warn('The resulting video might be corrupted');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
88
|
+
this.log.info(`Screen recording has not been previously started by Appium. There is nothing to stop`);
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
if (this._screenRecordingProperties.recordingProcess &&
|
|
92
|
+
this._screenRecordingProperties.recordingProcess.isRunning) {
|
|
93
|
+
try {
|
|
94
|
+
await this._screenRecordingProperties.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
this.log.errorAndThrow(`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`);
|
|
98
|
+
}
|
|
99
|
+
this._screenRecordingProperties.recordingProcess = null;
|
|
100
|
+
}
|
|
101
|
+
if (lodash_1.default.isEmpty(this._screenRecordingProperties.records)) {
|
|
102
|
+
this.log.errorAndThrow(`No screen recordings have been stored on the device so far. ` +
|
|
103
|
+
`Are you sure the ${SCREENRECORD_BINARY} utility works as expected?`);
|
|
104
|
+
}
|
|
105
|
+
const tmpRoot = await support_1.tempDir.openDir();
|
|
106
|
+
try {
|
|
107
|
+
const localRecords = [];
|
|
108
|
+
for (const pathOnDevice of this._screenRecordingProperties.records) {
|
|
109
|
+
const relativePath = path_1.default.resolve(tmpRoot, path_1.default.posix.basename(pathOnDevice));
|
|
110
|
+
localRecords.push(relativePath);
|
|
111
|
+
await this.adb.pull(pathOnDevice, relativePath);
|
|
112
|
+
await this.adb.rimraf(pathOnDevice);
|
|
113
|
+
}
|
|
114
|
+
let resultFilePath = /** @type {string} */ (lodash_1.default.last(localRecords));
|
|
115
|
+
if (localRecords.length > 1) {
|
|
116
|
+
this.log.info(`Got ${localRecords.length} screen recordings. Trying to merge them`);
|
|
117
|
+
try {
|
|
118
|
+
resultFilePath = await mergeScreenRecords.bind(this)(localRecords);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
this.log.warn(`Cannot merge the recorded files. The most recent screen recording is going to be returned as the result. ` +
|
|
122
|
+
`Original error: ${ /** @type {Error} */(e).message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (lodash_1.default.isEmpty(options.remotePath)) {
|
|
126
|
+
const { size } = await support_1.fs.stat(resultFilePath);
|
|
127
|
+
this.log.debug(`The size of the resulting screen recording is ${support_1.util.toReadableSizeString(size)}`);
|
|
128
|
+
}
|
|
129
|
+
return await uploadRecordedMedia(resultFilePath, options.remotePath, options);
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
await support_1.fs.rimraf(tmpRoot);
|
|
133
|
+
this._screenRecordingProperties = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.stopRecordingScreen = stopRecordingScreen;
|
|
137
|
+
// #region Internal helpers
|
|
23
138
|
/**
|
|
24
139
|
*
|
|
25
140
|
* @param {string} localFile
|
|
@@ -62,13 +177,11 @@ async function verifyScreenRecordIsSupported(adb, isEmulator) {
|
|
|
62
177
|
}
|
|
63
178
|
}
|
|
64
179
|
/**
|
|
65
|
-
*
|
|
66
|
-
* @param {ADB} adb
|
|
180
|
+
* @this {import('../driver').AndroidDriver}
|
|
67
181
|
* @param {import('@appium/types').StringRecord} recordingProperties
|
|
68
|
-
* @param {import('@appium/types').AppiumLogger} [log]
|
|
69
182
|
* @returns {Promise<void>}
|
|
70
183
|
*/
|
|
71
|
-
async function scheduleScreenRecord(
|
|
184
|
+
async function scheduleScreenRecord(recordingProperties) {
|
|
72
185
|
if (recordingProperties.stopped) {
|
|
73
186
|
return;
|
|
74
187
|
}
|
|
@@ -81,7 +194,7 @@ async function scheduleScreenRecord(adb, recordingProperties, log) {
|
|
|
81
194
|
}
|
|
82
195
|
}
|
|
83
196
|
const pathOnDevice = `/sdcard/${support_1.util.uuidV4().substring(0, 8)}${DEFAULT_EXT}`;
|
|
84
|
-
const recordingProc = adb.screenrecord(pathOnDevice, {
|
|
197
|
+
const recordingProc = this.adb.screenrecord(pathOnDevice, {
|
|
85
198
|
videoSize,
|
|
86
199
|
bitRate,
|
|
87
200
|
timeLimit: currentTimeLimit,
|
|
@@ -92,31 +205,31 @@ async function scheduleScreenRecord(adb, recordingProperties, log) {
|
|
|
92
205
|
return;
|
|
93
206
|
}
|
|
94
207
|
const currentDuration = timer.getDuration().asSeconds.toFixed(0);
|
|
95
|
-
log
|
|
208
|
+
this.log.debug(`The overall screen recording duration is ${currentDuration}s so far`);
|
|
96
209
|
const timeLimitInt = parseInt(timeLimit, 10);
|
|
97
210
|
if (isNaN(timeLimitInt) || currentDuration >= timeLimitInt) {
|
|
98
|
-
log
|
|
211
|
+
this.log.debug('There is no need to start the next recording chunk');
|
|
99
212
|
return;
|
|
100
213
|
}
|
|
101
214
|
recordingProperties.currentTimeLimit = timeLimitInt - currentDuration;
|
|
102
215
|
const chunkDuration = recordingProperties.currentTimeLimit < MAX_RECORDING_TIME_SEC
|
|
103
216
|
? recordingProperties.currentTimeLimit
|
|
104
217
|
: MAX_RECORDING_TIME_SEC;
|
|
105
|
-
log
|
|
218
|
+
this.log.debug(`Starting the next ${chunkDuration}s-chunk ` +
|
|
106
219
|
`of screen recording in order to achieve ${timeLimitInt}s total duration`);
|
|
107
220
|
(async () => {
|
|
108
221
|
try {
|
|
109
|
-
await scheduleScreenRecord(
|
|
222
|
+
await scheduleScreenRecord.bind(this)(recordingProperties);
|
|
110
223
|
}
|
|
111
224
|
catch (e) {
|
|
112
|
-
log
|
|
225
|
+
this.log.error(/** @type {Error} */ (e).stack);
|
|
113
226
|
recordingProperties.stopped = true;
|
|
114
227
|
}
|
|
115
228
|
})();
|
|
116
229
|
});
|
|
117
230
|
await recordingProc.start(0);
|
|
118
231
|
try {
|
|
119
|
-
await (0, asyncbox_1.waitForCondition)(async () => await adb.fileExists(pathOnDevice), {
|
|
232
|
+
await (0, asyncbox_1.waitForCondition)(async () => await this.adb.fileExists(pathOnDevice), {
|
|
120
233
|
waitMs: RETRY_TIMEOUT,
|
|
121
234
|
intervalMs: RETRY_PAUSE,
|
|
122
235
|
});
|
|
@@ -130,11 +243,11 @@ async function scheduleScreenRecord(adb, recordingProperties, log) {
|
|
|
130
243
|
}
|
|
131
244
|
/**
|
|
132
245
|
*
|
|
246
|
+
* @this {import('../driver').AndroidDriver}
|
|
133
247
|
* @param {string[]} mediaFiles
|
|
134
|
-
* @param {import('@appium/types').AppiumLogger} [log]
|
|
135
248
|
* @returns {Promise<string>}
|
|
136
249
|
*/
|
|
137
|
-
async function mergeScreenRecords(mediaFiles
|
|
250
|
+
async function mergeScreenRecords(mediaFiles) {
|
|
138
251
|
try {
|
|
139
252
|
await support_1.fs.which(FFMPEG_BINARY);
|
|
140
253
|
}
|
|
@@ -144,10 +257,10 @@ async function mergeScreenRecords(mediaFiles, log) {
|
|
|
144
257
|
const configContent = mediaFiles.map((x) => `file '${x}'`).join('\n');
|
|
145
258
|
const configFile = path_1.default.resolve(path_1.default.dirname(mediaFiles[0]), 'config.txt');
|
|
146
259
|
await support_1.fs.writeFile(configFile, configContent, 'utf8');
|
|
147
|
-
log
|
|
260
|
+
this.log.debug(`Generated ffmpeg merging config '${configFile}' with items:\n${configContent}`);
|
|
148
261
|
const result = path_1.default.resolve(path_1.default.dirname(mediaFiles[0]), `merge_${Math.floor(+new Date())}${DEFAULT_EXT}`);
|
|
149
262
|
const args = ['-safe', '0', '-f', 'concat', '-i', configFile, '-c', 'copy', result];
|
|
150
|
-
log
|
|
263
|
+
this.log.info(`Initiating screen records merging using the command '${FFMPEG_BINARY} ${args.join(' ')}'`);
|
|
151
264
|
await (0, teen_process_1.exec)(FFMPEG_BINARY, args);
|
|
152
265
|
return result;
|
|
153
266
|
}
|
|
@@ -174,115 +287,7 @@ async function terminateBackgroundScreenRecording(adb, force = true) {
|
|
|
174
287
|
throw new Error(`Unable to stop the background screen recording: ${ /** @type {Error} */(err).message}`);
|
|
175
288
|
}
|
|
176
289
|
}
|
|
177
|
-
|
|
178
|
-
* @type {import('./mixins').RecordScreenMixin & ThisType<import('../driver').AndroidDriver>}
|
|
179
|
-
* @satisfies {import('@appium/types').ExternalDriver}
|
|
180
|
-
*/
|
|
181
|
-
const RecordScreenMixin = {
|
|
182
|
-
async startRecordingScreen(options = {}) {
|
|
183
|
-
await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
|
|
184
|
-
let result = '';
|
|
185
|
-
const { videoSize, timeLimit = DEFAULT_RECORDING_TIME_SEC, bugReport, bitRate, forceRestart, } = options;
|
|
186
|
-
if (!forceRestart) {
|
|
187
|
-
result = await this.stopRecordingScreen(options);
|
|
188
|
-
}
|
|
189
|
-
if (await terminateBackgroundScreenRecording(this.adb, true)) {
|
|
190
|
-
this.log.warn(`There were some ${SCREENRECORD_BINARY} process leftovers running ` +
|
|
191
|
-
`in the background. Make sure you stop screen recording each time after it is started, ` +
|
|
192
|
-
`otherwise the recorded media might quickly exceed all the free space on the device under test.`);
|
|
193
|
-
}
|
|
194
|
-
if (!lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
195
|
-
// XXX: this doesn't need to be done in serial, does it?
|
|
196
|
-
for (const record of this._screenRecordingProperties.records || []) {
|
|
197
|
-
await this.adb.rimraf(record);
|
|
198
|
-
}
|
|
199
|
-
this._screenRecordingProperties = undefined;
|
|
200
|
-
}
|
|
201
|
-
const timeout = parseFloat(String(timeLimit));
|
|
202
|
-
if (isNaN(timeout) || timeout > MAX_TIME_SEC || timeout <= 0) {
|
|
203
|
-
throw new Error(`The timeLimit value must be in range [1, ${MAX_TIME_SEC}] seconds. ` +
|
|
204
|
-
`The value of '${timeLimit}' has been passed instead.`);
|
|
205
|
-
}
|
|
206
|
-
this._screenRecordingProperties = {
|
|
207
|
-
timer: new support_1.timing.Timer().start(),
|
|
208
|
-
videoSize,
|
|
209
|
-
timeLimit,
|
|
210
|
-
currentTimeLimit: timeLimit,
|
|
211
|
-
bitRate,
|
|
212
|
-
bugReport,
|
|
213
|
-
records: [],
|
|
214
|
-
recordingProcess: null,
|
|
215
|
-
stopped: false,
|
|
216
|
-
};
|
|
217
|
-
await scheduleScreenRecord(this.adb, this._screenRecordingProperties, this.log);
|
|
218
|
-
return result;
|
|
219
|
-
},
|
|
220
|
-
async stopRecordingScreen(options = {}) {
|
|
221
|
-
await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
|
|
222
|
-
if (!lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
223
|
-
this._screenRecordingProperties.stopped = true;
|
|
224
|
-
}
|
|
225
|
-
try {
|
|
226
|
-
await terminateBackgroundScreenRecording(this.adb, false);
|
|
227
|
-
}
|
|
228
|
-
catch (err) {
|
|
229
|
-
this.log.warn(/** @type {Error} */ (err).message);
|
|
230
|
-
if (!lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
231
|
-
this.log.warn('The resulting video might be corrupted');
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (lodash_1.default.isEmpty(this._screenRecordingProperties)) {
|
|
235
|
-
this.log.info(`Screen recording has not been previously started by Appium. There is nothing to stop`);
|
|
236
|
-
return '';
|
|
237
|
-
}
|
|
238
|
-
if (this._screenRecordingProperties.recordingProcess &&
|
|
239
|
-
this._screenRecordingProperties.recordingProcess.isRunning) {
|
|
240
|
-
try {
|
|
241
|
-
await this._screenRecordingProperties.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);
|
|
242
|
-
}
|
|
243
|
-
catch (e) {
|
|
244
|
-
this.log.errorAndThrow(`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`);
|
|
245
|
-
}
|
|
246
|
-
this._screenRecordingProperties.recordingProcess = null;
|
|
247
|
-
}
|
|
248
|
-
if (lodash_1.default.isEmpty(this._screenRecordingProperties.records)) {
|
|
249
|
-
this.log.errorAndThrow(`No screen recordings have been stored on the device so far. ` +
|
|
250
|
-
`Are you sure the ${SCREENRECORD_BINARY} utility works as expected?`);
|
|
251
|
-
}
|
|
252
|
-
const tmpRoot = await support_1.tempDir.openDir();
|
|
253
|
-
try {
|
|
254
|
-
const localRecords = [];
|
|
255
|
-
for (const pathOnDevice of this._screenRecordingProperties.records) {
|
|
256
|
-
const relativePath = path_1.default.resolve(tmpRoot, path_1.default.posix.basename(pathOnDevice));
|
|
257
|
-
localRecords.push(relativePath);
|
|
258
|
-
await this.adb.pull(pathOnDevice, relativePath);
|
|
259
|
-
await this.adb.rimraf(pathOnDevice);
|
|
260
|
-
}
|
|
261
|
-
let resultFilePath = /** @type {string} */ (lodash_1.default.last(localRecords));
|
|
262
|
-
if (localRecords.length > 1) {
|
|
263
|
-
this.log.info(`Got ${localRecords.length} screen recordings. Trying to merge them`);
|
|
264
|
-
try {
|
|
265
|
-
resultFilePath = await mergeScreenRecords(localRecords, this.log);
|
|
266
|
-
}
|
|
267
|
-
catch (e) {
|
|
268
|
-
this.log.warn(`Cannot merge the recorded files. The most recent screen recording is going to be returned as the result. ` +
|
|
269
|
-
`Original error: ${ /** @type {Error} */(e).message}`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (lodash_1.default.isEmpty(options.remotePath)) {
|
|
273
|
-
const { size } = await support_1.fs.stat(resultFilePath);
|
|
274
|
-
this.log.debug(`The size of the resulting screen recording is ${support_1.util.toReadableSizeString(size)}`);
|
|
275
|
-
}
|
|
276
|
-
return await uploadRecordedMedia(resultFilePath, options.remotePath, options);
|
|
277
|
-
}
|
|
278
|
-
finally {
|
|
279
|
-
await support_1.fs.rimraf(tmpRoot);
|
|
280
|
-
this._screenRecordingProperties = undefined;
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
};
|
|
284
|
-
(0, mixins_1.mixin)(RecordScreenMixin);
|
|
285
|
-
exports.default = RecordScreenMixin;
|
|
290
|
+
// #endregion
|
|
286
291
|
/**
|
|
287
292
|
* @typedef {import('appium-adb').ADB} ADB
|
|
288
293
|
*/
|