appium-android-driver 7.8.3 → 8.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 +32 -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 +2 -2
- 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
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {util} from '@appium/support';
|
|
3
|
+
import ADB from 'appium-adb';
|
|
4
|
+
import {retryInterval} from 'asyncbox';
|
|
5
|
+
import {
|
|
6
|
+
path as SETTINGS_APK_PATH,
|
|
7
|
+
SETTINGS_HELPER_ID,
|
|
8
|
+
UNICODE_IME,
|
|
9
|
+
EMPTY_IME,
|
|
10
|
+
} from 'io.appium.settings';
|
|
11
|
+
import B from 'bluebird';
|
|
12
|
+
|
|
13
|
+
const HELPER_APP_INSTALL_RETRIES = 3;
|
|
14
|
+
const HELPER_APP_INSTALL_RETRY_DELAY_MS = 5000;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @this {import('../../driver').AndroidDriver}
|
|
18
|
+
* @param {string} errMsg
|
|
19
|
+
*/
|
|
20
|
+
export function requireEmulator(errMsg) {
|
|
21
|
+
if (!this.isEmulator()) {
|
|
22
|
+
this.log.errorAndThrow(errMsg);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @this {import('../../driver').AndroidDriver}
|
|
28
|
+
* @returns {void}
|
|
29
|
+
*/
|
|
30
|
+
export function validatePackageActivityNames() {
|
|
31
|
+
for (const key of ['appPackage', 'appActivity', 'appWaitPackage', 'appWaitActivity']) {
|
|
32
|
+
const name = this.opts[key];
|
|
33
|
+
if (!name) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const match = /([^\w.*,])+/.exec(String(name));
|
|
38
|
+
if (!match) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.log.warn(
|
|
43
|
+
`Capability '${key}' is expected to only include latin letters, digits, underscore, dot, comma and asterisk characters.`,
|
|
44
|
+
);
|
|
45
|
+
this.log.warn(
|
|
46
|
+
`Current value '${name}' has non-matching character at index ${match.index}: '${String(
|
|
47
|
+
name,
|
|
48
|
+
).substring(0, match.index + 1)}'`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @this {import('../../driver').AndroidDriver}
|
|
55
|
+
* @param {string} networkSpeed
|
|
56
|
+
* @returns {string}
|
|
57
|
+
*/
|
|
58
|
+
export function ensureNetworkSpeed(networkSpeed) {
|
|
59
|
+
if (networkSpeed.toUpperCase() in this.adb.NETWORK_SPEED) {
|
|
60
|
+
return networkSpeed;
|
|
61
|
+
}
|
|
62
|
+
this.log.warn(
|
|
63
|
+
`Wrong network speed param '${networkSpeed}', using default: ${this.adb.NETWORK_SPEED.FULL}. ` +
|
|
64
|
+
`Supported values: ${_.values(this.adb.NETWORK_SPEED)}`,
|
|
65
|
+
);
|
|
66
|
+
return this.adb.NETWORK_SPEED.FULL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @this {import('../../driver').AndroidDriver}
|
|
71
|
+
* @returns {string[]}
|
|
72
|
+
*/
|
|
73
|
+
export function prepareAvdArgs() {
|
|
74
|
+
const {networkSpeed, isHeadless, avdArgs} = this.opts;
|
|
75
|
+
const result = [];
|
|
76
|
+
if (avdArgs) {
|
|
77
|
+
if (_.isArray(avdArgs)) {
|
|
78
|
+
result.push(...avdArgs);
|
|
79
|
+
} else {
|
|
80
|
+
result.push(...util.shellParse(`${avdArgs}`));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (networkSpeed) {
|
|
84
|
+
result.push('-netspeed', ensureNetworkSpeed.bind(this)(networkSpeed));
|
|
85
|
+
}
|
|
86
|
+
if (isHeadless) {
|
|
87
|
+
result.push('-no-window');
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @this {import('../../driver').AndroidDriver}
|
|
94
|
+
* @returns {Promise<void>}
|
|
95
|
+
*/
|
|
96
|
+
export async function prepareEmulator() {
|
|
97
|
+
const {
|
|
98
|
+
avd,
|
|
99
|
+
avdEnv: env,
|
|
100
|
+
language,
|
|
101
|
+
locale: country,
|
|
102
|
+
avdLaunchTimeout: launchTimeout,
|
|
103
|
+
avdReadyTimeout: readyTimeout,
|
|
104
|
+
} = this.opts;
|
|
105
|
+
if (!avd) {
|
|
106
|
+
throw new Error('Cannot launch AVD without AVD name');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const avdName = avd.replace('@', '');
|
|
110
|
+
let isEmulatorRunning = true;
|
|
111
|
+
try {
|
|
112
|
+
await this.adb.getRunningAVDWithRetry(avdName, 5000);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
this.log.debug(`Emulator '${avdName}' is not running: ${e.message}`);
|
|
115
|
+
isEmulatorRunning = false;
|
|
116
|
+
}
|
|
117
|
+
const args = prepareAvdArgs.bind(this)();
|
|
118
|
+
if (isEmulatorRunning) {
|
|
119
|
+
if (args.includes('-wipe-data')) {
|
|
120
|
+
this.log.debug(`Killing '${avdName}' because it needs to be wiped at start.`);
|
|
121
|
+
await this.adb.killEmulator(avdName);
|
|
122
|
+
} else {
|
|
123
|
+
this.log.debug('Not launching AVD because it is already running.');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
await this.adb.launchAVD(avd, {
|
|
128
|
+
args,
|
|
129
|
+
env,
|
|
130
|
+
language,
|
|
131
|
+
country,
|
|
132
|
+
launchTimeout,
|
|
133
|
+
readyTimeout,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {import('../../driver').AndroidDriverOpts?} [opts=null]
|
|
139
|
+
* @returns {Promise<ADB>}
|
|
140
|
+
*/
|
|
141
|
+
export async function createBaseADB(opts = null) {
|
|
142
|
+
// filter out any unwanted options sent in
|
|
143
|
+
// this list should be updated as ADB takes more arguments
|
|
144
|
+
const {
|
|
145
|
+
adbPort,
|
|
146
|
+
suppressKillServer,
|
|
147
|
+
remoteAdbHost,
|
|
148
|
+
clearDeviceLogsOnStart,
|
|
149
|
+
adbExecTimeout,
|
|
150
|
+
useKeystore,
|
|
151
|
+
keystorePath,
|
|
152
|
+
keystorePassword,
|
|
153
|
+
keyAlias,
|
|
154
|
+
keyPassword,
|
|
155
|
+
remoteAppsCacheLimit,
|
|
156
|
+
buildToolsVersion,
|
|
157
|
+
allowOfflineDevices,
|
|
158
|
+
allowDelayAdb,
|
|
159
|
+
} = opts ?? {};
|
|
160
|
+
return await ADB.createADB({
|
|
161
|
+
adbPort,
|
|
162
|
+
suppressKillServer,
|
|
163
|
+
remoteAdbHost,
|
|
164
|
+
clearDeviceLogsOnStart,
|
|
165
|
+
adbExecTimeout,
|
|
166
|
+
useKeystore,
|
|
167
|
+
keystorePath,
|
|
168
|
+
keystorePassword,
|
|
169
|
+
keyAlias,
|
|
170
|
+
keyPassword,
|
|
171
|
+
remoteAppsCacheLimit,
|
|
172
|
+
buildToolsVersion,
|
|
173
|
+
allowOfflineDevices,
|
|
174
|
+
allowDelayAdb,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @this {import('../../driver').AndroidDriver}
|
|
180
|
+
* @param {boolean} throwIfError
|
|
181
|
+
* @returns {Promise<void>}
|
|
182
|
+
*/
|
|
183
|
+
export async function pushSettingsApp(throwIfError) {
|
|
184
|
+
this.log.debug('Pushing settings apk to the device...');
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
// Sometimes adb push or adb instal take more time than expected to install an app
|
|
188
|
+
// e.g. https://github.com/appium/io.appium.settings/issues/40#issuecomment-476593174
|
|
189
|
+
await retryInterval(
|
|
190
|
+
HELPER_APP_INSTALL_RETRIES,
|
|
191
|
+
HELPER_APP_INSTALL_RETRY_DELAY_MS,
|
|
192
|
+
async () =>
|
|
193
|
+
await this.adb.installOrUpgrade(SETTINGS_APK_PATH, SETTINGS_HELPER_ID, {
|
|
194
|
+
grantPermissions: true,
|
|
195
|
+
}),
|
|
196
|
+
);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (throwIfError) {
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this.log.warn(
|
|
203
|
+
`Ignored error while installing '${SETTINGS_APK_PATH}': ` +
|
|
204
|
+
`'${err.message}'. Features that rely on this helper ` +
|
|
205
|
+
'require the apk such as toggle WiFi and getting location ' +
|
|
206
|
+
'will raise an error if you try to use them.',
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Reinstall would stop the settings helper process anyway, so
|
|
211
|
+
// there is no need to continue if the application is still running
|
|
212
|
+
if (await this.settingsApp.isRunningInForeground()) {
|
|
213
|
+
this.log.debug(
|
|
214
|
+
`${SETTINGS_HELPER_ID} is already running. ` + `There is no need to reset its permissions.`,
|
|
215
|
+
);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const fixSettingsAppPermissionsForLegacyApis = async () => {
|
|
220
|
+
if ((await this.adb.getApiLevel()) > 23) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Android 6- devices should have granted permissions
|
|
225
|
+
// https://github.com/appium/appium/pull/11640#issuecomment-438260477
|
|
226
|
+
const perms = ['SET_ANIMATION_SCALE', 'CHANGE_CONFIGURATION', 'ACCESS_FINE_LOCATION'];
|
|
227
|
+
this.log.info(`Granting permissions ${perms} to '${SETTINGS_HELPER_ID}'`);
|
|
228
|
+
await this.adb.grantPermissions(
|
|
229
|
+
SETTINGS_HELPER_ID,
|
|
230
|
+
perms.map((x) => `android.permission.${x}`),
|
|
231
|
+
);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
await B.all([
|
|
236
|
+
this.settingsApp.adjustNotificationsPermissions(),
|
|
237
|
+
this.settingsApp.adjustMediaProjectionServicePermissions(),
|
|
238
|
+
fixSettingsAppPermissionsForLegacyApis(),
|
|
239
|
+
]);
|
|
240
|
+
} catch (e) {
|
|
241
|
+
this.log.debug(e.stack);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// launch io.appium.settings app due to settings failing to be set
|
|
245
|
+
// if the app is not launched prior to start the session on android 7+
|
|
246
|
+
// see https://github.com/appium/appium/issues/8957
|
|
247
|
+
try {
|
|
248
|
+
await this.settingsApp.requireRunning({
|
|
249
|
+
timeout: this.isEmulator() ? 30000 : 5000,
|
|
250
|
+
});
|
|
251
|
+
} catch (err) {
|
|
252
|
+
this.log.debug(err.stack);
|
|
253
|
+
if (throwIfError) {
|
|
254
|
+
throw err;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @deprecated
|
|
261
|
+
* @this {import('../../driver').AndroidDriver}
|
|
262
|
+
* @returns {Promise<string?>}
|
|
263
|
+
*/
|
|
264
|
+
export async function initUnicodeKeyboard() {
|
|
265
|
+
this.log.debug('Enabling Unicode keyboard support');
|
|
266
|
+
|
|
267
|
+
// get the default IME so we can return back to it later if we want
|
|
268
|
+
const defaultIME = await this.adb.defaultIME();
|
|
269
|
+
|
|
270
|
+
this.log.debug(`Unsetting previous IME ${defaultIME}`);
|
|
271
|
+
this.log.debug(`Setting IME to '${UNICODE_IME}'`);
|
|
272
|
+
await this.adb.enableIME(UNICODE_IME);
|
|
273
|
+
await this.adb.setIME(UNICODE_IME);
|
|
274
|
+
return defaultIME;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @this {import('../../driver').AndroidDriver}
|
|
279
|
+
* @returns {Promise<void>}
|
|
280
|
+
*/
|
|
281
|
+
export async function hideKeyboardCompletely() {
|
|
282
|
+
this.log.debug(`Hiding the on-screen keyboard by setting IME to '${EMPTY_IME}'`);
|
|
283
|
+
await this.adb.enableIME(EMPTY_IME);
|
|
284
|
+
await this.adb.setIME(EMPTY_IME);
|
|
285
|
+
}
|
|
@@ -1,56 +1,43 @@
|
|
|
1
1
|
import {errors} from 'appium/driver';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import {mixin} from './mixins';
|
|
4
3
|
|
|
5
4
|
const SUPPORTED_ACTIONS = ['whitelistAdd', 'whitelistRemove'];
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* This is a wrapper to 'adb shell dumpsys deviceidle' interface.
|
|
8
|
+
* Read https://www.protechtraining.com/blog/post/diving-into-android-m-doze-875
|
|
9
|
+
* for more details.
|
|
10
|
+
*
|
|
11
|
+
* @param {import('./types').DeviceidleOpts} opts
|
|
12
|
+
* @returns {Promise<void>}
|
|
10
13
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* This is a wrapper to 'adb shell dumpsys deviceidle' interface.
|
|
14
|
-
* Read https://www.protechtraining.com/blog/post/diving-into-android-m-doze-875
|
|
15
|
-
* for more details.
|
|
16
|
-
*
|
|
17
|
-
* @param {import('./types').DeviceidleOpts} opts
|
|
18
|
-
*/
|
|
19
|
-
async mobileDeviceidle(opts) {
|
|
20
|
-
const {
|
|
21
|
-
action,
|
|
22
|
-
packages,
|
|
23
|
-
} = opts;
|
|
14
|
+
export async function mobileDeviceidle(opts) {
|
|
15
|
+
const {action, packages} = opts;
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
if (!(_.isString(packages) || _.isArray(packages))) {
|
|
18
|
+
throw new errors.InvalidArgumentError(`packages argument must be a string or an array`);
|
|
19
|
+
}
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
mixin(DeviceidleMixin);
|
|
52
|
-
|
|
53
|
-
export default DeviceidleMixin;
|
|
21
|
+
/** @type {string[]} */
|
|
22
|
+
const packagesArr = _.isArray(packages) ? packages : [packages];
|
|
23
|
+
/** @type {string[]} */
|
|
24
|
+
const commonArgs = ['dumpsys', 'deviceidle', 'whitelist'];
|
|
25
|
+
/** @type {(x: string) => string[]} */
|
|
26
|
+
let argsGenerator;
|
|
27
|
+
switch (action) {
|
|
28
|
+
case SUPPORTED_ACTIONS[0]:
|
|
29
|
+
argsGenerator = (pkg) => [...commonArgs, `+${pkg}`];
|
|
30
|
+
break;
|
|
31
|
+
case SUPPORTED_ACTIONS[1]:
|
|
32
|
+
argsGenerator = (pkg) => [...commonArgs, `-${pkg}`];
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
throw new errors.InvalidArgumentError(
|
|
36
|
+
`action must be one of ${JSON.stringify(SUPPORTED_ACTIONS)}. Got '${action}' instead`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
await this.adb.shellChunks(argsGenerator, packagesArr);
|
|
40
|
+
}
|
|
54
41
|
|
|
55
42
|
/**
|
|
56
43
|
* @typedef {import('appium-adb').ADB} ADB
|
package/lib/commands/element.js
CHANGED
|
@@ -1,151 +1,158 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
|
|
3
|
-
import {mixin} from './mixins';
|
|
4
|
-
import {retryInterval} from 'asyncbox';
|
|
5
3
|
import {errors} from 'appium/driver';
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
6
|
+
* @this {import('../driver').AndroidDriver}
|
|
7
|
+
* @param {string} attribute
|
|
8
|
+
* @param {string} elementId
|
|
9
|
+
* @returns {Promise<string?>}
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
async getName(elementId) {
|
|
17
|
-
return await this.getAttribute('className', elementId);
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
async elementDisplayed(elementId) {
|
|
21
|
-
return (await this.getAttribute('displayed', elementId)) === 'true';
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
async elementEnabled(elementId) {
|
|
25
|
-
return (await this.getAttribute('enabled', elementId)) === 'true';
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
async elementSelected(elementId) {
|
|
29
|
-
return (await this.getAttribute('selected', elementId)) === 'true';
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
async setElementValue(keys, elementId, replace = false) {
|
|
33
|
-
const text = keys instanceof Array ? keys.join('') : keys;
|
|
34
|
-
return await this.doSetElementValue({
|
|
35
|
-
elementId,
|
|
36
|
-
text: String(text),
|
|
37
|
-
replace,
|
|
38
|
-
});
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Reason for isolating doSetElementValue from setElementValue is for reusing setElementValue
|
|
43
|
-
* across android-drivers (like appium-uiautomator2-driver) and to avoid code duplication.
|
|
44
|
-
* Other android-drivers (like appium-uiautomator2-driver) need to override doSetElementValue
|
|
45
|
-
* to facilitate setElementValue.
|
|
46
|
-
*/
|
|
47
|
-
async doSetElementValue(params) {
|
|
48
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
async setValue(keys, elementId) {
|
|
52
|
-
return await this.setElementValue(keys, elementId, false);
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
async replaceValue(keys, elementId) {
|
|
56
|
-
return await this.setElementValue(keys, elementId, true);
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
async setValueImmediate(keys, elementId) {
|
|
60
|
-
let text = keys;
|
|
61
|
-
if (keys instanceof Array) {
|
|
62
|
-
text = keys.join('');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// first, make sure we are focused on the element
|
|
66
|
-
await this.click(elementId);
|
|
67
|
-
|
|
68
|
-
// then send through adb
|
|
69
|
-
await this.adb.inputText(/** @type {string} */ (text));
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
async getText(elementId) {
|
|
73
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
async clear(elementId) {
|
|
77
|
-
let text = (await this.getText(elementId)) || '';
|
|
78
|
-
let length = text.length;
|
|
79
|
-
if (length === 0) {
|
|
80
|
-
// if length is zero there are two possibilities:
|
|
81
|
-
// 1. there is nothing in the text field
|
|
82
|
-
// 2. it is a password field
|
|
83
|
-
// since there is little overhead to the adb call, delete 100 elements
|
|
84
|
-
// if we get zero, just in case it is #2
|
|
85
|
-
length = 100;
|
|
86
|
-
}
|
|
87
|
-
await this.click(elementId);
|
|
88
|
-
this.log.debug(`Sending up to ${length} clear characters to device`);
|
|
89
|
-
await retryInterval(5, 500, async () => {
|
|
90
|
-
let remainingLength = length;
|
|
91
|
-
while (remainingLength > 0) {
|
|
92
|
-
let lengthToSend = remainingLength < 50 ? remainingLength : 50;
|
|
93
|
-
this.log.debug(`Sending ${lengthToSend} clear characters to device`);
|
|
94
|
-
await this.adb.clearTextField(lengthToSend);
|
|
95
|
-
remainingLength -= lengthToSend;
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
async click(elementId) {
|
|
101
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
async getLocation(elementId) {
|
|
105
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
async getLocationInView(elementId) {
|
|
109
|
-
return await this.getLocation(elementId);
|
|
110
|
-
},
|
|
111
|
-
|
|
112
|
-
async getSize(elementId) {
|
|
113
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
async getElementRect(elementId) {
|
|
117
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
async touchLongClick(elementId, x, y, duration) {
|
|
121
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
async touchDown(elementId, x, y) {
|
|
125
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
async touchUp(elementId, x, y) {
|
|
129
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
async touchMove(elementId, x, y) {
|
|
133
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
async complexTap(tapCount, touchCount, duration, x, y) {
|
|
137
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
async tap(elementId = null, x = null, y = null, count = 1) {
|
|
141
|
-
throw new errors.NotImplementedError('Not implemented');
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
mixin(ElementMixin);
|
|
146
|
-
|
|
147
|
-
export default ElementMixin;
|
|
11
|
+
export async function getAttribute(attribute, elementId) {
|
|
12
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
13
|
+
}
|
|
148
14
|
|
|
149
15
|
/**
|
|
150
|
-
* @
|
|
16
|
+
* @this {import('../driver').AndroidDriver}
|
|
17
|
+
* @param {string} elementId
|
|
18
|
+
* @returns {Promise<void>}
|
|
151
19
|
*/
|
|
20
|
+
export async function click(elementId) {
|
|
21
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @this {import('../driver').AndroidDriver}
|
|
26
|
+
* @param {string} elementId
|
|
27
|
+
* @returns {Promise<string>}
|
|
28
|
+
*/
|
|
29
|
+
export async function getText(elementId) {
|
|
30
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @this {import('../driver').AndroidDriver}
|
|
35
|
+
* @param {string} elementId
|
|
36
|
+
* @returns {Promise<import('@appium/types').Position>}
|
|
37
|
+
*/
|
|
38
|
+
export async function getLocation(elementId) {
|
|
39
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @this {import('../driver').AndroidDriver}
|
|
44
|
+
* @param {string} elementId
|
|
45
|
+
* @returns {Promise<import('@appium/types').Size>}
|
|
46
|
+
*/
|
|
47
|
+
export async function getSize(elementId) {
|
|
48
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @this {import('../driver').AndroidDriver}
|
|
53
|
+
* @param {string} elementId
|
|
54
|
+
* @returns {Promise<string>}
|
|
55
|
+
*/
|
|
56
|
+
export async function getName(elementId) {
|
|
57
|
+
return /** @type {string} */ (await this.getAttribute('className', elementId));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @this {import('../driver').AndroidDriver}
|
|
62
|
+
* @param {string} elementId
|
|
63
|
+
* @returns {Promise<boolean>}
|
|
64
|
+
*/
|
|
65
|
+
export async function elementDisplayed(elementId) {
|
|
66
|
+
return (await this.getAttribute('displayed', elementId)) === 'true';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @this {import('../driver').AndroidDriver}
|
|
71
|
+
* @param {string} elementId
|
|
72
|
+
* @returns {Promise<boolean>}
|
|
73
|
+
*/
|
|
74
|
+
export async function elementEnabled(elementId) {
|
|
75
|
+
return (await this.getAttribute('enabled', elementId)) === 'true';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @this {import('../driver').AndroidDriver}
|
|
80
|
+
* @param {string} elementId
|
|
81
|
+
* @returns {Promise<boolean>}
|
|
82
|
+
*/
|
|
83
|
+
export async function elementSelected(elementId) {
|
|
84
|
+
return (await this.getAttribute('selected', elementId)) === 'true';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @this {import('../driver').AndroidDriver}
|
|
89
|
+
* @param {string|string[]} keys
|
|
90
|
+
* @param {string} elementId
|
|
91
|
+
* @param {boolean} [replace=false]
|
|
92
|
+
* @returns {Promise<void>}
|
|
93
|
+
*/
|
|
94
|
+
export async function setElementValue(keys, elementId, replace = false) {
|
|
95
|
+
const text = keys instanceof Array ? keys.join('') : keys;
|
|
96
|
+
return await this.doSetElementValue({
|
|
97
|
+
elementId,
|
|
98
|
+
text: String(text),
|
|
99
|
+
replace,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Reason for isolating doSetElementValue from setElementValue is for reusing setElementValue
|
|
105
|
+
* across android-drivers (like appium-uiautomator2-driver) and to avoid code duplication.
|
|
106
|
+
* Other android-drivers (like appium-uiautomator2-driver) need to override doSetElementValue
|
|
107
|
+
* to facilitate setElementValue.
|
|
108
|
+
*
|
|
109
|
+
* @this {import('../driver').AndroidDriver}
|
|
110
|
+
* @param {import('./types').DoSetElementValueOpts} params
|
|
111
|
+
* @returns {Promise<void>}
|
|
112
|
+
*/
|
|
113
|
+
export async function doSetElementValue(params) {
|
|
114
|
+
throw new errors.NotImplementedError('Not implemented');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @this {import('../driver').AndroidDriver}
|
|
119
|
+
* @param {string|string[]} keys
|
|
120
|
+
* @param {string} elementId
|
|
121
|
+
* @returns {Promise<void>}
|
|
122
|
+
*/
|
|
123
|
+
export async function setValue(keys, elementId) {
|
|
124
|
+
return await this.setElementValue(keys, elementId, false);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @this {import('../driver').AndroidDriver}
|
|
129
|
+
* @param {string|string[]} keys
|
|
130
|
+
* @param {string} elementId
|
|
131
|
+
* @returns {Promise<void>}
|
|
132
|
+
*/
|
|
133
|
+
export async function replaceValue(keys, elementId) {
|
|
134
|
+
return await this.setElementValue(keys, elementId, true);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @this {import('../driver').AndroidDriver}
|
|
139
|
+
* @param {string|string[]} keys
|
|
140
|
+
* @param {string} elementId
|
|
141
|
+
* @returns {Promise<void>}
|
|
142
|
+
*/
|
|
143
|
+
export async function setValueImmediate(keys, elementId) {
|
|
144
|
+
const text = Array.isArray(keys) ? keys.join('') : keys;
|
|
145
|
+
// first, make sure we are focused on the element
|
|
146
|
+
await this.click(elementId);
|
|
147
|
+
// then send through adb
|
|
148
|
+
await this.adb.inputText(/** @type {string} */ (text));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @this {import('../driver').AndroidDriver}
|
|
153
|
+
* @param {string} elementId
|
|
154
|
+
* @returns {Promise<import('@appium/types').Position>}
|
|
155
|
+
*/
|
|
156
|
+
export async function getLocationInView(elementId) {
|
|
157
|
+
return await this.getLocation(elementId);
|
|
158
|
+
}
|