appium-adb 14.0.6 → 14.0.7
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 +6 -0
- package/build/lib/tools/apk-signing.d.ts +34 -40
- package/build/lib/tools/apk-signing.d.ts.map +1 -1
- package/build/lib/tools/apk-signing.js +73 -71
- package/build/lib/tools/apk-signing.js.map +1 -1
- package/build/lib/tools/emulator-commands.d.ts +53 -69
- package/build/lib/tools/emulator-commands.d.ts.map +1 -1
- package/build/lib/tools/emulator-commands.js +48 -66
- package/build/lib/tools/emulator-commands.js.map +1 -1
- package/lib/tools/{apk-signing.js → apk-signing.ts} +96 -89
- package/lib/tools/{emulator-commands.js → emulator-commands.ts} +88 -92
- package/package.json +1 -1
|
@@ -5,16 +5,29 @@ import { util, fs } from '@appium/support';
|
|
|
5
5
|
import B from 'bluebird';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import * as ini from 'ini';
|
|
8
|
+
import type { ADB } from '../adb.js';
|
|
9
|
+
import type {
|
|
10
|
+
EmuInfo,
|
|
11
|
+
EmuVersionInfo,
|
|
12
|
+
StringRecord,
|
|
13
|
+
PowerAcStates,
|
|
14
|
+
Sensors,
|
|
15
|
+
GsmCallActions,
|
|
16
|
+
GsmSignalStrength,
|
|
17
|
+
GsmVoiceStates,
|
|
18
|
+
NetworkSpeed,
|
|
19
|
+
ExecTelnetOptions
|
|
20
|
+
} from './types.js';
|
|
8
21
|
|
|
9
22
|
/**
|
|
10
23
|
* Retrieves the list of available Android emulators
|
|
11
24
|
*
|
|
12
|
-
* @returns
|
|
25
|
+
* @returns
|
|
13
26
|
*/
|
|
14
|
-
async function listEmulators () {
|
|
27
|
+
async function listEmulators (): Promise<EmuInfo[]> {
|
|
15
28
|
let avdsRoot = process.env.ANDROID_AVD_HOME;
|
|
16
29
|
if (await dirExists(avdsRoot ?? '')) {
|
|
17
|
-
return await getAvdConfigPaths(
|
|
30
|
+
return await getAvdConfigPaths(avdsRoot as string);
|
|
18
31
|
}
|
|
19
32
|
|
|
20
33
|
if (avdsRoot) {
|
|
@@ -38,10 +51,10 @@ async function listEmulators () {
|
|
|
38
51
|
/**
|
|
39
52
|
* Get configuration paths of all virtual devices
|
|
40
53
|
*
|
|
41
|
-
* @param
|
|
42
|
-
* @returns
|
|
54
|
+
* @param avdsRoot Path to the directory that contains the AVD .ini files
|
|
55
|
+
* @returns
|
|
43
56
|
*/
|
|
44
|
-
async function getAvdConfigPaths (avdsRoot) {
|
|
57
|
+
async function getAvdConfigPaths (avdsRoot: string): Promise<EmuInfo[]> {
|
|
45
58
|
const configs = await fs.glob('*.ini', {
|
|
46
59
|
cwd: avdsRoot,
|
|
47
60
|
absolute: true,
|
|
@@ -55,21 +68,19 @@ async function getAvdConfigPaths (avdsRoot) {
|
|
|
55
68
|
/**
|
|
56
69
|
* Check the emulator state.
|
|
57
70
|
*
|
|
58
|
-
* @
|
|
59
|
-
* @return {Promise<boolean>} True if Emulator is visible to adb.
|
|
71
|
+
* @returns True if Emulator is visible to adb.
|
|
60
72
|
*/
|
|
61
|
-
export async function isEmulatorConnected () {
|
|
62
|
-
|
|
73
|
+
export async function isEmulatorConnected (this: ADB): Promise<boolean> {
|
|
74
|
+
const emulators = await this.getConnectedEmulators();
|
|
63
75
|
return !!_.find(emulators, (x) => x && x.udid === this.curDeviceId);
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
/**
|
|
67
79
|
* Verify the emulator is connected.
|
|
68
80
|
*
|
|
69
|
-
* @
|
|
70
|
-
* @throws {Error} If Emulator is not visible to adb.
|
|
81
|
+
* @throws If Emulator is not visible to adb.
|
|
71
82
|
*/
|
|
72
|
-
export async function verifyEmulatorConnected () {
|
|
83
|
+
export async function verifyEmulatorConnected (this: ADB): Promise<void> {
|
|
73
84
|
if (!(await this.isEmulatorConnected())) {
|
|
74
85
|
throw new Error(`The emulator "${this.curDeviceId}" was unexpectedly disconnected`);
|
|
75
86
|
}
|
|
@@ -78,15 +89,14 @@ export async function verifyEmulatorConnected () {
|
|
|
78
89
|
/**
|
|
79
90
|
* Emulate fingerprint touch event on the connected emulator.
|
|
80
91
|
*
|
|
81
|
-
* @
|
|
82
|
-
* @param {string} fingerprintId - The ID of the fingerprint.
|
|
92
|
+
* @param fingerprintId - The ID of the fingerprint.
|
|
83
93
|
*/
|
|
84
|
-
export async function fingerprint (fingerprintId) {
|
|
94
|
+
export async function fingerprint (this: ADB, fingerprintId: string): Promise<void> {
|
|
85
95
|
if (!fingerprintId) {
|
|
86
96
|
throw new Error('Fingerprint id parameter must be defined');
|
|
87
97
|
}
|
|
88
98
|
// the method used only works for API level 23 and above
|
|
89
|
-
|
|
99
|
+
const level = await this.getApiLevel();
|
|
90
100
|
if (level < 23) {
|
|
91
101
|
throw new Error(`Device API Level must be >= 23. Current Api level '${level}'`);
|
|
92
102
|
}
|
|
@@ -97,19 +107,17 @@ export async function fingerprint (fingerprintId) {
|
|
|
97
107
|
* Change the display orientation on the connected emulator.
|
|
98
108
|
* The orientation is changed (PI/2 is added) every time
|
|
99
109
|
* this method is called.
|
|
100
|
-
* @this {import('../adb.js').ADB}
|
|
101
110
|
*/
|
|
102
|
-
export async function rotate () {
|
|
111
|
+
export async function rotate (this: ADB): Promise<void> {
|
|
103
112
|
await this.adbExecEmu(['rotate']);
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
/**
|
|
107
116
|
* Emulate power state change on the connected emulator.
|
|
108
117
|
*
|
|
109
|
-
* @
|
|
110
|
-
* @param {import('./types').PowerAcStates} [state='on'] - Either 'on' or 'off'.
|
|
118
|
+
* @param state - Either 'on' or 'off'.
|
|
111
119
|
*/
|
|
112
|
-
export async function powerAC (state = 'on') {
|
|
120
|
+
export async function powerAC (this: ADB, state: PowerAcStates = 'on'): Promise<void> {
|
|
113
121
|
if (_.values(this.POWER_AC_STATES).indexOf(state) === -1) {
|
|
114
122
|
throw new TypeError(`Wrong power AC state sent '${state}'. `
|
|
115
123
|
+ `Supported values: ${_.values(this.POWER_AC_STATES)}]`);
|
|
@@ -120,12 +128,11 @@ export async function powerAC (state = 'on') {
|
|
|
120
128
|
/**
|
|
121
129
|
* Emulate sensors values on the connected emulator.
|
|
122
130
|
*
|
|
123
|
-
* @
|
|
124
|
-
* @param
|
|
125
|
-
* @
|
|
126
|
-
* @throws {TypeError} - If sensor type or sensor value is not defined
|
|
131
|
+
* @param sensor - Sensor type declared in SENSORS items.
|
|
132
|
+
* @param value - Number to set as the sensor value.
|
|
133
|
+
* @throws - If sensor type or sensor value is not defined
|
|
127
134
|
*/
|
|
128
|
-
export async function sensorSet (sensor, value) {
|
|
135
|
+
export async function sensorSet (this: ADB, sensor: string, value: Sensors): Promise<void> {
|
|
129
136
|
if (!_.includes(this.SENSORS, sensor)) {
|
|
130
137
|
throw new TypeError(`Unsupported sensor sent '${sensor}'. `
|
|
131
138
|
+ `Supported values: ${_.values(this.SENSORS)}]`);
|
|
@@ -141,22 +148,20 @@ export async function sensorSet (sensor, value) {
|
|
|
141
148
|
/**
|
|
142
149
|
* Emulate power capacity change on the connected emulator.
|
|
143
150
|
*
|
|
144
|
-
* @
|
|
145
|
-
* @param {string|number} [percent=100] - Percentage value in range [0, 100].
|
|
151
|
+
* @param percent - Percentage value in range [0, 100].
|
|
146
152
|
*/
|
|
147
|
-
export async function powerCapacity (percent = 100) {
|
|
148
|
-
|
|
149
|
-
if (isNaN(
|
|
153
|
+
export async function powerCapacity (this: ADB, percent: string | number = 100): Promise<void> {
|
|
154
|
+
const percentInt = parseInt(`${percent}`, 10);
|
|
155
|
+
if (isNaN(percentInt) || percentInt < 0 || percentInt > 100) {
|
|
150
156
|
throw new TypeError(`The percentage value should be valid integer between 0 and 100`);
|
|
151
157
|
}
|
|
152
|
-
await this.adbExecEmu(['power', 'capacity', `${
|
|
158
|
+
await this.adbExecEmu(['power', 'capacity', `${percentInt}`]);
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/**
|
|
156
162
|
* Emulate power off event on the connected emulator.
|
|
157
|
-
* @this {import('../adb.js').ADB}
|
|
158
163
|
*/
|
|
159
|
-
export async function powerOFF () {
|
|
164
|
+
export async function powerOFF (this: ADB): Promise<void> {
|
|
160
165
|
await this.powerAC(this.POWER_AC_STATES.POWER_AC_OFF);
|
|
161
166
|
await this.powerCapacity(0);
|
|
162
167
|
}
|
|
@@ -164,12 +169,11 @@ export async function powerOFF () {
|
|
|
164
169
|
/**
|
|
165
170
|
* Emulate send SMS event on the connected emulator.
|
|
166
171
|
*
|
|
167
|
-
* @
|
|
168
|
-
* @param
|
|
169
|
-
* @
|
|
170
|
-
* @throws {TypeError} If phone number has invalid format.
|
|
172
|
+
* @param phoneNumber - The phone number of message sender.
|
|
173
|
+
* @param message - The message content.
|
|
174
|
+
* @throws If phone number has invalid format.
|
|
171
175
|
*/
|
|
172
|
-
export async function sendSMS (phoneNumber, message = '') {
|
|
176
|
+
export async function sendSMS (this: ADB, phoneNumber: string | number, message = ''): Promise<void> {
|
|
173
177
|
if (_.isEmpty(message)) {
|
|
174
178
|
throw new TypeError('SMS message must not be empty');
|
|
175
179
|
}
|
|
@@ -182,13 +186,12 @@ export async function sendSMS (phoneNumber, message = '') {
|
|
|
182
186
|
/**
|
|
183
187
|
* Emulate GSM call event on the connected emulator.
|
|
184
188
|
*
|
|
185
|
-
* @
|
|
186
|
-
* @param
|
|
187
|
-
* @
|
|
188
|
-
* @throws
|
|
189
|
-
* @throws {TypeError} If _action_ value is invalid.
|
|
189
|
+
* @param phoneNumber - The phone number of the caller.
|
|
190
|
+
* @param action - One of available GSM call actions.
|
|
191
|
+
* @throws If phone number has invalid format.
|
|
192
|
+
* @throws If _action_ value is invalid.
|
|
190
193
|
*/
|
|
191
|
-
export async function gsmCall (phoneNumber, action) {
|
|
194
|
+
export async function gsmCall (this: ADB, phoneNumber: string | number, action: GsmCallActions): Promise<void> {
|
|
192
195
|
if (!_.values(this.GSM_CALL_ACTIONS).includes(action)) {
|
|
193
196
|
throw new TypeError(
|
|
194
197
|
`Invalid gsm action param ${action}. Supported values: ${_.values(this.GSM_CALL_ACTIONS)}`
|
|
@@ -203,11 +206,10 @@ export async function gsmCall (phoneNumber, action) {
|
|
|
203
206
|
/**
|
|
204
207
|
* Emulate GSM signal strength change event on the connected emulator.
|
|
205
208
|
*
|
|
206
|
-
* @
|
|
207
|
-
* @
|
|
208
|
-
* @throws {TypeError} If _strength_ value is invalid.
|
|
209
|
+
* @param strength - A number in range [0, 4];
|
|
210
|
+
* @throws If _strength_ value is invalid.
|
|
209
211
|
*/
|
|
210
|
-
export async function gsmSignal (strength = 4) {
|
|
212
|
+
export async function gsmSignal (this: ADB, strength: GsmSignalStrength = 4): Promise<void> {
|
|
211
213
|
const strengthInt = parseInt(`${strength}`, 10);
|
|
212
214
|
if (!_.includes(this.GSM_SIGNAL_STRENGTHS, strengthInt)) {
|
|
213
215
|
throw new TypeError(
|
|
@@ -221,11 +223,10 @@ export async function gsmSignal (strength = 4) {
|
|
|
221
223
|
/**
|
|
222
224
|
* Emulate GSM voice event on the connected emulator.
|
|
223
225
|
*
|
|
224
|
-
* @
|
|
225
|
-
* @
|
|
226
|
-
* @throws {TypeError} If _state_ value is invalid.
|
|
226
|
+
* @param state - Either 'on' or 'off'.
|
|
227
|
+
* @throws If _state_ value is invalid.
|
|
227
228
|
*/
|
|
228
|
-
export async function gsmVoice (state = 'on') {
|
|
229
|
+
export async function gsmVoice (this: ADB, state: GsmVoiceStates = 'on'): Promise<void> {
|
|
229
230
|
// gsm voice <state> allows you to change the state of your GPRS connection
|
|
230
231
|
if (!_.values(this.GSM_VOICE_STATES).includes(state)) {
|
|
231
232
|
throw new TypeError(
|
|
@@ -238,12 +239,11 @@ export async function gsmVoice (state = 'on') {
|
|
|
238
239
|
/**
|
|
239
240
|
* Emulate network speed change event on the connected emulator.
|
|
240
241
|
*
|
|
241
|
-
* @
|
|
242
|
-
* @param {import('./types').NetworkSpeed} [speed='full']
|
|
242
|
+
* @param speed
|
|
243
243
|
* One of possible NETWORK_SPEED values.
|
|
244
|
-
* @throws
|
|
244
|
+
* @throws If _speed_ value is invalid.
|
|
245
245
|
*/
|
|
246
|
-
export async function networkSpeed (speed = 'full') {
|
|
246
|
+
export async function networkSpeed (this: ADB, speed: NetworkSpeed = 'full'): Promise<void> {
|
|
247
247
|
// network speed <speed> allows you to set the network speed emulation.
|
|
248
248
|
if (!_.values(this.NETWORK_SPEED).includes(speed)) {
|
|
249
249
|
throw new Error(
|
|
@@ -256,19 +256,18 @@ export async function networkSpeed (speed = 'full') {
|
|
|
256
256
|
/**
|
|
257
257
|
* Executes a command through emulator telnet console interface and returns its output
|
|
258
258
|
*
|
|
259
|
-
* @
|
|
260
|
-
* @param {string[]|string} cmd - The actual command to execute. See
|
|
259
|
+
* @param cmd - The actual command to execute. See
|
|
261
260
|
* https://developer.android.com/studio/run/emulator-console for more details
|
|
262
261
|
* on available commands
|
|
263
|
-
* @param
|
|
264
|
-
* @returns
|
|
265
|
-
* @throws
|
|
262
|
+
* @param opts
|
|
263
|
+
* @returns The command output
|
|
264
|
+
* @throws If there was an error while connecting to the Telnet console
|
|
266
265
|
* or if the given command returned non-OK response
|
|
267
266
|
*/
|
|
268
|
-
export async function execEmuConsoleCommand (cmd, opts = {}) {
|
|
267
|
+
export async function execEmuConsoleCommand (this: ADB, cmd: string[] | string, opts: ExecTelnetOptions = {}): Promise<string> {
|
|
269
268
|
let port = parseInt(`${opts.port}`, 10);
|
|
270
269
|
if (!port) {
|
|
271
|
-
const portMatch = /emulator-(\d+)/i.exec(
|
|
270
|
+
const portMatch = /emulator-(\d+)/i.exec(this.curDeviceId as string);
|
|
272
271
|
if (!portMatch) {
|
|
273
272
|
throw new Error(`Cannot parse the console port number from the device identifier '${this.curDeviceId}'. ` +
|
|
274
273
|
`Is it an emulator?`);
|
|
@@ -295,10 +294,10 @@ export async function execEmuConsoleCommand (cmd, opts = {}) {
|
|
|
295
294
|
const connTimeoutObj = setTimeout(
|
|
296
295
|
() => reject(new Error(`Cannot connect to the Emulator console at ${host}:${port} ` +
|
|
297
296
|
`after ${connTimeout}ms`)), connTimeout);
|
|
298
|
-
let execTimeoutObj;
|
|
299
|
-
let initTimeoutObj;
|
|
297
|
+
let execTimeoutObj: NodeJS.Timeout;
|
|
298
|
+
let initTimeoutObj: NodeJS.Timeout;
|
|
300
299
|
let isCommandSent = false;
|
|
301
|
-
let serverResponse = [];
|
|
300
|
+
let serverResponse: Buffer[] = [];
|
|
302
301
|
|
|
303
302
|
client.once('error', (e) => {
|
|
304
303
|
clearTimeout(connTimeoutObj);
|
|
@@ -341,7 +340,7 @@ export async function execEmuConsoleCommand (cmd, opts = {}) {
|
|
|
341
340
|
clearTimeout(execTimeoutObj);
|
|
342
341
|
client.end();
|
|
343
342
|
const outputArr = output.split(eol);
|
|
344
|
-
return reject(_.trim(_.last(outputArr)));
|
|
343
|
+
return reject(_.trim(_.last(outputArr) || ''));
|
|
345
344
|
}
|
|
346
345
|
});
|
|
347
346
|
});
|
|
@@ -350,19 +349,18 @@ export async function execEmuConsoleCommand (cmd, opts = {}) {
|
|
|
350
349
|
/**
|
|
351
350
|
* Retrieves emulator version from the file system
|
|
352
351
|
*
|
|
353
|
-
* @
|
|
354
|
-
* @returns {Promise<import('./types').EmuVersionInfo>} If no version info could be parsed then an empty
|
|
352
|
+
* @returns If no version info could be parsed then an empty
|
|
355
353
|
* object is returned
|
|
356
354
|
*/
|
|
357
|
-
export async function getEmuVersionInfo () {
|
|
358
|
-
const propsPath = path.join(
|
|
355
|
+
export async function getEmuVersionInfo (this: ADB): Promise<EmuVersionInfo> {
|
|
356
|
+
const propsPath = path.join(this.sdkRoot as string, 'emulator', 'source.properties');
|
|
359
357
|
if (!await fs.exists(propsPath)) {
|
|
360
358
|
return {};
|
|
361
359
|
}
|
|
362
360
|
|
|
363
361
|
const content = await fs.readFile(propsPath, 'utf8');
|
|
364
362
|
const revisionMatch = /^Pkg\.Revision=([\d.]+)$/m.exec(content);
|
|
365
|
-
const result = {};
|
|
363
|
+
const result: EmuVersionInfo = {};
|
|
366
364
|
if (revisionMatch) {
|
|
367
365
|
result.revision = revisionMatch[1];
|
|
368
366
|
}
|
|
@@ -376,17 +374,16 @@ export async function getEmuVersionInfo () {
|
|
|
376
374
|
/**
|
|
377
375
|
* Retrieves emulator image properties from the local file system
|
|
378
376
|
*
|
|
379
|
-
* @
|
|
380
|
-
* @
|
|
381
|
-
* @
|
|
382
|
-
* @returns {Promise<import('./types').StringRecord>} The content of emulator image properties file.
|
|
377
|
+
* @param avdName Emulator name. Should NOT start with '@' character
|
|
378
|
+
* @throws if there was a failure while extracting the properties
|
|
379
|
+
* @returns The content of emulator image properties file.
|
|
383
380
|
* Usually this configuration .ini file has the following content:
|
|
384
381
|
* avd.ini.encoding=UTF-8
|
|
385
382
|
* path=/Users/username/.android/avd/Pixel_XL_API_30.avd
|
|
386
383
|
* path.rel=avd/Pixel_XL_API_30.avd
|
|
387
384
|
* target=android-30
|
|
388
385
|
*/
|
|
389
|
-
export async function getEmuImageProperties (avdName) {
|
|
386
|
+
export async function getEmuImageProperties (this: ADB, avdName: string): Promise<StringRecord> {
|
|
390
387
|
const avds = await listEmulators();
|
|
391
388
|
const avd = avds.find(({name}) => name === avdName);
|
|
392
389
|
if (!avd) {
|
|
@@ -404,12 +401,11 @@ export async function getEmuImageProperties (avdName) {
|
|
|
404
401
|
/**
|
|
405
402
|
* Check if given emulator exists in the list of available avds.
|
|
406
403
|
*
|
|
407
|
-
* @
|
|
408
|
-
* @param {string} avdName - The name of emulator to verify for existence.
|
|
404
|
+
* @param avdName - The name of emulator to verify for existence.
|
|
409
405
|
* Should NOT start with '@' character
|
|
410
|
-
* @throws
|
|
406
|
+
* @throws If the emulator with given name does not exist.
|
|
411
407
|
*/
|
|
412
|
-
export async function checkAvdExist (avdName) {
|
|
408
|
+
export async function checkAvdExist (this: ADB, avdName: string): Promise<boolean> {
|
|
413
409
|
const avds = await listEmulators();
|
|
414
410
|
if (!avds.some(({name}) => name === avdName)) {
|
|
415
411
|
let msg = `Avd '${avdName}' is not available. `;
|
|
@@ -426,11 +422,10 @@ export async function checkAvdExist (avdName) {
|
|
|
426
422
|
/**
|
|
427
423
|
* Send an arbitrary Telnet command to the device under test.
|
|
428
424
|
*
|
|
429
|
-
* @
|
|
430
|
-
* @
|
|
431
|
-
* @return {Promise<string>} The actual output of the given command.
|
|
425
|
+
* @param command - The command to be sent.
|
|
426
|
+
* @returns The actual output of the given command.
|
|
432
427
|
*/
|
|
433
|
-
export async function sendTelnetCommand (command) {
|
|
428
|
+
export async function sendTelnetCommand (this: ADB, command: string): Promise<string> {
|
|
434
429
|
return await this.execEmuConsoleCommand(command, {port: await this.getEmulatorPort()});
|
|
435
430
|
}
|
|
436
431
|
|
|
@@ -440,9 +435,9 @@ export async function sendTelnetCommand (command) {
|
|
|
440
435
|
/**
|
|
441
436
|
* Retrieves the full path to the Android preferences root
|
|
442
437
|
*
|
|
443
|
-
* @returns
|
|
438
|
+
* @returns The full path to the folder or `null` if the folder cannot be found
|
|
444
439
|
*/
|
|
445
|
-
async function getAndroidPrefsRoot () {
|
|
440
|
+
async function getAndroidPrefsRoot (): Promise<string | null> {
|
|
446
441
|
let location = process.env.ANDROID_EMULATOR_HOME;
|
|
447
442
|
if (await dirExists(location ?? '')) {
|
|
448
443
|
return location ?? null;
|
|
@@ -468,11 +463,12 @@ async function getAndroidPrefsRoot () {
|
|
|
468
463
|
/**
|
|
469
464
|
* Check if a path exists on the filesystem and is a directory
|
|
470
465
|
*
|
|
471
|
-
* @param
|
|
472
|
-
* @returns
|
|
466
|
+
* @param location The full path to the directory
|
|
467
|
+
* @returns
|
|
473
468
|
*/
|
|
474
|
-
async function dirExists (location) {
|
|
469
|
+
async function dirExists (location: string): Promise<boolean> {
|
|
475
470
|
return await fs.exists(location) && (await fs.stat(location)).isDirectory();
|
|
476
471
|
}
|
|
477
472
|
|
|
478
473
|
// #endregion
|
|
474
|
+
|