appium-android-driver 14.0.2 → 14.0.3

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.
Files changed (178) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/lib/commands/app-management.d.ts +1 -1
  3. package/build/lib/commands/app-management.d.ts.map +1 -1
  4. package/build/lib/commands/app-management.js +2 -4
  5. package/build/lib/commands/app-management.js.map +1 -1
  6. package/build/lib/commands/appearance.d.ts.map +1 -1
  7. package/build/lib/commands/appearance.js.map +1 -1
  8. package/build/lib/commands/bidi/models.d.ts +1 -1
  9. package/build/lib/commands/bidi/models.d.ts.map +1 -1
  10. package/build/lib/commands/bidi/models.js +1 -1
  11. package/build/lib/commands/bidi/models.js.map +1 -1
  12. package/build/lib/commands/bluetooth.d.ts.map +1 -1
  13. package/build/lib/commands/bluetooth.js.map +1 -1
  14. package/build/lib/commands/context/cache.d.ts +1 -1
  15. package/build/lib/commands/context/cache.d.ts.map +1 -1
  16. package/build/lib/commands/context/cache.js.map +1 -1
  17. package/build/lib/commands/context/exports.d.ts.map +1 -1
  18. package/build/lib/commands/context/exports.js +3 -4
  19. package/build/lib/commands/context/exports.js.map +1 -1
  20. package/build/lib/commands/context/helpers.d.ts.map +1 -1
  21. package/build/lib/commands/context/helpers.js +21 -26
  22. package/build/lib/commands/context/helpers.js.map +1 -1
  23. package/build/lib/commands/device/common.d.ts +1 -1
  24. package/build/lib/commands/device/common.d.ts.map +1 -1
  25. package/build/lib/commands/device/common.js +8 -16
  26. package/build/lib/commands/device/common.js.map +1 -1
  27. package/build/lib/commands/device/emulator-actions.d.ts.map +1 -1
  28. package/build/lib/commands/device/emulator-actions.js +1 -1
  29. package/build/lib/commands/device/emulator-actions.js.map +1 -1
  30. package/build/lib/commands/device/emulator-console.d.ts.map +1 -1
  31. package/build/lib/commands/device/emulator-console.js.map +1 -1
  32. package/build/lib/commands/device/utils.d.ts.map +1 -1
  33. package/build/lib/commands/device/utils.js +5 -6
  34. package/build/lib/commands/device/utils.js.map +1 -1
  35. package/build/lib/commands/deviceidle.d.ts.map +1 -1
  36. package/build/lib/commands/deviceidle.js.map +1 -1
  37. package/build/lib/commands/element.d.ts.map +1 -1
  38. package/build/lib/commands/element.js.map +1 -1
  39. package/build/lib/commands/execute.d.ts.map +1 -1
  40. package/build/lib/commands/execute.js +2 -4
  41. package/build/lib/commands/execute.js.map +1 -1
  42. package/build/lib/commands/file-actions.d.ts.map +1 -1
  43. package/build/lib/commands/file-actions.js +6 -20
  44. package/build/lib/commands/file-actions.js.map +1 -1
  45. package/build/lib/commands/find.d.ts +1 -1
  46. package/build/lib/commands/find.d.ts.map +1 -1
  47. package/build/lib/commands/find.js +1 -1
  48. package/build/lib/commands/find.js.map +1 -1
  49. package/build/lib/commands/geolocation.d.ts.map +1 -1
  50. package/build/lib/commands/geolocation.js +5 -12
  51. package/build/lib/commands/geolocation.js.map +1 -1
  52. package/build/lib/commands/gestures.d.ts.map +1 -1
  53. package/build/lib/commands/gestures.js.map +1 -1
  54. package/build/lib/commands/image-injection.d.ts.map +1 -1
  55. package/build/lib/commands/image-injection.js +2 -2
  56. package/build/lib/commands/image-injection.js.map +1 -1
  57. package/build/lib/commands/ime.d.ts.map +1 -1
  58. package/build/lib/commands/ime.js +1 -7
  59. package/build/lib/commands/ime.js.map +1 -1
  60. package/build/lib/commands/intent.d.ts.map +1 -1
  61. package/build/lib/commands/intent.js +2 -3
  62. package/build/lib/commands/intent.js.map +1 -1
  63. package/build/lib/commands/keyboard.d.ts.map +1 -1
  64. package/build/lib/commands/keyboard.js.map +1 -1
  65. package/build/lib/commands/legacy.d.ts.map +1 -1
  66. package/build/lib/commands/legacy.js.map +1 -1
  67. package/build/lib/commands/lock/exports.d.ts.map +1 -1
  68. package/build/lib/commands/lock/exports.js.map +1 -1
  69. package/build/lib/commands/lock/helpers.d.ts.map +1 -1
  70. package/build/lib/commands/lock/helpers.js +2 -9
  71. package/build/lib/commands/lock/helpers.js.map +1 -1
  72. package/build/lib/commands/log.d.ts +1 -1
  73. package/build/lib/commands/log.d.ts.map +1 -1
  74. package/build/lib/commands/log.js +6 -8
  75. package/build/lib/commands/log.js.map +1 -1
  76. package/build/lib/commands/media-projection.d.ts.map +1 -1
  77. package/build/lib/commands/media-projection.js +2 -2
  78. package/build/lib/commands/media-projection.js.map +1 -1
  79. package/build/lib/commands/memory.d.ts.map +1 -1
  80. package/build/lib/commands/memory.js.map +1 -1
  81. package/build/lib/commands/misc.d.ts.map +1 -1
  82. package/build/lib/commands/misc.js.map +1 -1
  83. package/build/lib/commands/network.d.ts.map +1 -1
  84. package/build/lib/commands/network.js +4 -11
  85. package/build/lib/commands/network.js.map +1 -1
  86. package/build/lib/commands/nfc.d.ts.map +1 -1
  87. package/build/lib/commands/nfc.js.map +1 -1
  88. package/build/lib/commands/performance.d.ts.map +1 -1
  89. package/build/lib/commands/performance.js +4 -21
  90. package/build/lib/commands/performance.js.map +1 -1
  91. package/build/lib/commands/permissions.d.ts.map +1 -1
  92. package/build/lib/commands/permissions.js +4 -7
  93. package/build/lib/commands/permissions.js.map +1 -1
  94. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  95. package/build/lib/commands/recordscreen.js +2 -2
  96. package/build/lib/commands/recordscreen.js.map +1 -1
  97. package/build/lib/commands/resources.d.ts.map +1 -1
  98. package/build/lib/commands/resources.js.map +1 -1
  99. package/build/lib/commands/shell.d.ts.map +1 -1
  100. package/build/lib/commands/shell.js +1 -6
  101. package/build/lib/commands/shell.js.map +1 -1
  102. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  103. package/build/lib/commands/streamscreen.js +6 -9
  104. package/build/lib/commands/streamscreen.js.map +1 -1
  105. package/build/lib/commands/system-bars.d.ts.map +1 -1
  106. package/build/lib/commands/system-bars.js +1 -1
  107. package/build/lib/commands/system-bars.js.map +1 -1
  108. package/build/lib/commands/time.d.ts.map +1 -1
  109. package/build/lib/commands/time.js +1 -1
  110. package/build/lib/commands/time.js.map +1 -1
  111. package/build/lib/commands/types.d.ts +4 -4
  112. package/build/lib/commands/types.d.ts.map +1 -1
  113. package/build/lib/doctor/checks.d.ts.map +1 -1
  114. package/build/lib/doctor/checks.js +2 -2
  115. package/build/lib/doctor/checks.js.map +1 -1
  116. package/build/lib/driver.d.ts +8 -8
  117. package/build/lib/driver.d.ts.map +1 -1
  118. package/build/lib/driver.js +14 -20
  119. package/build/lib/driver.js.map +1 -1
  120. package/build/lib/execute-method-map.d.ts.map +1 -1
  121. package/build/lib/execute-method-map.js +1 -10
  122. package/build/lib/execute-method-map.js.map +1 -1
  123. package/build/lib/index.d.ts +1 -1
  124. package/build/lib/index.d.ts.map +1 -1
  125. package/build/lib/index.js +1 -1
  126. package/build/lib/index.js.map +1 -1
  127. package/build/lib/method-map.d.ts.map +1 -1
  128. package/build/lib/method-map.js.map +1 -1
  129. package/build/lib/utils.d.ts.map +1 -1
  130. package/build/lib/utils.js +1 -1
  131. package/build/lib/utils.js.map +1 -1
  132. package/lib/commands/app-management.ts +15 -43
  133. package/lib/commands/appearance.ts +1 -5
  134. package/lib/commands/bidi/models.ts +5 -12
  135. package/lib/commands/bluetooth.ts +1 -0
  136. package/lib/commands/context/cache.ts +2 -1
  137. package/lib/commands/context/exports.ts +17 -40
  138. package/lib/commands/context/helpers.ts +37 -88
  139. package/lib/commands/device/common.ts +16 -29
  140. package/lib/commands/device/emulator-actions.ts +12 -49
  141. package/lib/commands/device/emulator-console.ts +1 -0
  142. package/lib/commands/device/utils.ts +7 -16
  143. package/lib/commands/deviceidle.ts +1 -0
  144. package/lib/commands/element.ts +6 -20
  145. package/lib/commands/execute.ts +6 -13
  146. package/lib/commands/file-actions.ts +17 -50
  147. package/lib/commands/find.ts +4 -6
  148. package/lib/commands/geolocation.ts +9 -17
  149. package/lib/commands/gestures.ts +2 -1
  150. package/lib/commands/image-injection.ts +9 -19
  151. package/lib/commands/ime.ts +2 -7
  152. package/lib/commands/intent.ts +3 -3
  153. package/lib/commands/keyboard.ts +4 -14
  154. package/lib/commands/legacy.ts +1 -0
  155. package/lib/commands/lock/exports.ts +5 -10
  156. package/lib/commands/lock/helpers.ts +16 -51
  157. package/lib/commands/log.ts +12 -22
  158. package/lib/commands/media-projection.ts +9 -21
  159. package/lib/commands/memory.ts +2 -5
  160. package/lib/commands/misc.ts +3 -5
  161. package/lib/commands/network.ts +9 -27
  162. package/lib/commands/nfc.ts +1 -0
  163. package/lib/commands/performance.ts +12 -48
  164. package/lib/commands/permissions.ts +10 -22
  165. package/lib/commands/recordscreen.ts +16 -41
  166. package/lib/commands/resources.ts +3 -9
  167. package/lib/commands/shell.ts +3 -7
  168. package/lib/commands/streamscreen.ts +17 -37
  169. package/lib/commands/system-bars.ts +7 -13
  170. package/lib/commands/time.ts +4 -8
  171. package/lib/commands/types.ts +9 -10
  172. package/lib/doctor/checks.ts +11 -18
  173. package/lib/driver.ts +43 -65
  174. package/lib/execute-method-map.ts +1 -10
  175. package/lib/index.ts +1 -1
  176. package/lib/method-map.ts +1 -0
  177. package/lib/utils.ts +4 -6
  178. package/package.json +24 -34
@@ -1,15 +1,13 @@
1
+ import path from 'node:path';
2
+
1
3
  import {fs, net, system, tempDir, timing, util} from '@appium/support';
2
4
  import type {NetOptions, HttpUploadOptions} from '@appium/support';
5
+ import type {ADB} from 'appium-adb';
3
6
  import {waitForCondition} from 'asyncbox';
4
- import path from 'node:path';
5
7
  import {exec} from 'teen_process';
8
+
6
9
  import type {AndroidDriver} from '../driver.js';
7
- import type {ADB} from 'appium-adb';
8
- import type {
9
- StartScreenRecordingOpts,
10
- StopScreenRecordingOpts,
11
- ScreenRecordingProperties,
12
- } from './types.js';
10
+ import type {StartScreenRecordingOpts, StopScreenRecordingOpts, ScreenRecordingProperties} from './types.js';
13
11
 
14
12
  const RETRY_PAUSE = 300;
15
13
  const RETRY_TIMEOUT = 5000;
@@ -43,13 +41,7 @@ export async function startRecordingScreen(
43
41
  await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
44
42
 
45
43
  let result = '';
46
- const {
47
- videoSize,
48
- timeLimit = DEFAULT_RECORDING_TIME_SEC,
49
- bugReport,
50
- bitRate,
51
- forceRestart,
52
- } = options;
44
+ const {videoSize, timeLimit = DEFAULT_RECORDING_TIME_SEC, bugReport, bitRate, forceRestart} = options;
53
45
  if (!forceRestart) {
54
46
  result = await this.stopRecordingScreen(options);
55
47
  }
@@ -109,10 +101,7 @@ export async function startRecordingScreen(
109
101
  * @throws {Error} If screen recording is not supported, no recording was active,
110
102
  * or if the recording process cannot be stopped.
111
103
  */
112
- export async function stopRecordingScreen(
113
- this: AndroidDriver,
114
- options: StopScreenRecordingOpts = {},
115
- ): Promise<string> {
104
+ export async function stopRecordingScreen(this: AndroidDriver, options: StopScreenRecordingOpts = {}): Promise<string> {
116
105
  await verifyScreenRecordIsSupported(this.adb, this.isEmulator());
117
106
 
118
107
  const props = this._screenRecordingProperties;
@@ -130,9 +119,7 @@ export async function stopRecordingScreen(
130
119
  }
131
120
 
132
121
  if (!props) {
133
- this.log.info(
134
- `Screen recording has not been previously started by Appium. There is nothing to stop`,
135
- );
122
+ this.log.info(`Screen recording has not been previously started by Appium. There is nothing to stop`);
136
123
  return '';
137
124
  }
138
125
 
@@ -140,9 +127,7 @@ export async function stopRecordingScreen(
140
127
  try {
141
128
  await props.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);
142
129
  } catch {
143
- throw this.log.errorWithException(
144
- `Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`,
145
- );
130
+ throw this.log.errorWithException(`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`);
146
131
  }
147
132
  props.recordingProcess = null;
148
133
  }
@@ -177,9 +162,7 @@ export async function stopRecordingScreen(
177
162
  }
178
163
  if (util.isEmpty(options.remotePath)) {
179
164
  const {size} = await fs.stat(resultFilePath);
180
- this.log.debug(
181
- `The size of the resulting screen recording is ${util.toReadableSizeString(size)}`,
182
- );
165
+ this.log.debug(`The size of the resulting screen recording is ${util.toReadableSizeString(size)}`);
183
166
  }
184
167
  return await uploadRecordedMedia(resultFilePath, options.remotePath, options);
185
168
  } finally {
@@ -307,14 +290,9 @@ async function mergeScreenRecords(this: AndroidDriver, mediaFiles: string[]): Pr
307
290
  const configFile = path.resolve(path.dirname(mediaFiles[0]), 'config.txt');
308
291
  await fs.writeFile(configFile, configContent, 'utf8');
309
292
  this.log.debug(`Generated ffmpeg merging config '${configFile}' with items:\n${configContent}`);
310
- const result = path.resolve(
311
- path.dirname(mediaFiles[0]),
312
- `merge_${Math.floor(+new Date())}${DEFAULT_EXT}`,
313
- );
293
+ const result = path.resolve(path.dirname(mediaFiles[0]), `merge_${Math.floor(+new Date())}${DEFAULT_EXT}`);
314
294
  const args = ['-safe', '0', '-f', 'concat', '-i', configFile, '-c', 'copy', result];
315
- this.log.info(
316
- `Initiating screen records merging using the command '${FFMPEG_BINARY} ${args.join(' ')}'`,
317
- );
295
+ this.log.info(`Initiating screen records merging using the command '${FFMPEG_BINARY} ${args.join(' ')}'`);
318
296
  await exec(FFMPEG_BINARY, args);
319
297
  return result;
320
298
  }
@@ -327,13 +305,10 @@ async function terminateBackgroundScreenRecording(adb: ADB, force = true): Promi
327
305
 
328
306
  try {
329
307
  await adb.shell(['kill', force ? '-15' : '-2', ...screenrecordPids.map(String)]);
330
- await waitForCondition(
331
- async () => util.isEmpty(await adb.getProcessIdsByName(SCREENRECORD_BINARY)),
332
- {
333
- waitMs: PROCESS_SHUTDOWN_TIMEOUT,
334
- intervalMs: 500,
335
- },
336
- );
308
+ await waitForCondition(async () => util.isEmpty(await adb.getProcessIdsByName(SCREENRECORD_BINARY)), {
309
+ waitMs: PROCESS_SHUTDOWN_TIMEOUT,
310
+ intervalMs: 500,
311
+ });
337
312
  return true;
338
313
  } catch (err) {
339
314
  throw new Error(`Unable to stop the background screen recording: ${(err as Error).message}`, {
@@ -1,5 +1,6 @@
1
1
  import {fs, tempDir, util} from '@appium/support';
2
2
  import type {StringRecord} from '@appium/types';
3
+
3
4
  import type {AndroidDriver, AndroidDriverOpts} from '../driver.js';
4
5
  import type {Locale} from './types.js';
5
6
 
@@ -10,10 +11,7 @@ import type {Locale} from './types.js';
10
11
  * the device's current language will be used.
11
12
  * @returns Promise that resolves to a mapping of string keys to their localized values.
12
13
  */
13
- export async function getStrings(
14
- this: AndroidDriver,
15
- language: string | null = null,
16
- ): Promise<StringRecord> {
14
+ export async function getStrings(this: AndroidDriver, language: string | null = null): Promise<StringRecord> {
17
15
  if (!language) {
18
16
  language = await this.adb.getDeviceLanguage();
19
17
  this.log.info(`No language specified, returning strings for: ${language}`);
@@ -105,11 +103,7 @@ async function extractStringsFromResources(
105
103
  }
106
104
  }
107
105
 
108
- async function fetchLocaleSuggestions(
109
- this: AndroidDriver,
110
- language?: string,
111
- country?: string,
112
- ): Promise<Locale[]> {
106
+ async function fetchLocaleSuggestions(this: AndroidDriver, language?: string, country?: string): Promise<Locale[]> {
113
107
  const supportedLocales = await this.settingsApp.listSupportedLocales();
114
108
  const suggestedLocales = supportedLocales.filter(
115
109
  (locale) =>
@@ -2,8 +2,9 @@ import {util} from '@appium/support';
2
2
  import {errors} from 'appium/driver.js';
3
3
  import {exec} from 'teen_process';
4
4
  import type {ExecError} from 'teen_process';
5
- import {ADB_SHELL_FEATURE} from '../utils.js';
5
+
6
6
  import type {AndroidDriver} from '../driver.js';
7
+ import {ADB_SHELL_FEATURE} from '../utils.js';
7
8
 
8
9
  /**
9
10
  * Executes a shell command on the device via ADB.
@@ -39,12 +40,7 @@ export async function mobileShell<T extends boolean>(
39
40
  throw new errors.InvalidArgumentError(`The 'command' argument is mandatory`);
40
41
  }
41
42
 
42
- const adbArgs = [
43
- ...this.adb.executable.defaultArgs,
44
- 'shell',
45
- command,
46
- ...(Array.isArray(args) ? args : [args]),
47
- ];
43
+ const adbArgs = [...this.adb.executable.defaultArgs, 'shell', command, ...(Array.isArray(args) ? args : [args])];
48
44
  this.log.debug(`Running '${this.adb.executable.path} ${util.quote(adbArgs)}'`);
49
45
  try {
50
46
  const {stdout, stderr} = await exec(this.adb.executable.path, adbArgs, {timeout});
@@ -1,14 +1,16 @@
1
- import {fs, logger, system, util} from '@appium/support';
2
- import {waitForCondition} from 'asyncbox';
3
1
  import {spawn} from 'node:child_process';
4
2
  import http from 'node:http';
5
3
  import net from 'node:net';
6
4
  import url from 'node:url';
5
+
6
+ import {fs, logger, system, util} from '@appium/support';
7
+ import type {AppiumLogger} from '@appium/types';
8
+ import type {ADB} from 'appium-adb';
9
+ import {waitForCondition} from 'asyncbox';
7
10
  import {checkPortStatus} from 'portscanner';
8
11
  import {SubProcess, exec} from 'teen_process';
12
+
9
13
  import type {AndroidDriver} from '../driver.js';
10
- import type {ADB} from 'appium-adb';
11
- import type {AppiumLogger} from '@appium/types';
12
14
  import type {DeviceInfo, InitGStreamerPipelineOpts} from './types.js';
13
15
 
14
16
  const RECORDING_INTERVAL_SEC = 5;
@@ -91,22 +93,16 @@ export async function mobileStartScreenStreaming(
91
93
  if (this._screenStreamingProps === undefined) {
92
94
  await verifyStreamingRequirements(this.adb);
93
95
  } else {
94
- this.log.info(
95
- `The screen streaming session is already running. ` +
96
- `Stop it first in order to start a new one.`,
97
- );
96
+ this.log.info(`The screen streaming session is already running. Stop it first in order to start a new one.`);
98
97
  return;
99
98
  }
100
99
  if ((await checkPortStatus(port, host)) === 'open') {
101
- this.log.info(
102
- `The port #${port} at ${host} is busy. ` + `Assuming the screen streaming is already running`,
103
- );
100
+ this.log.info(`The port #${port} at ${host} is busy. Assuming the screen streaming is already running`);
104
101
  return;
105
102
  }
106
103
  if ((await checkPortStatus(tcpPort, TCP_HOST)) === 'open') {
107
104
  throw this.log.errorWithException(
108
- `The port #${tcpPort} at ${TCP_HOST} is busy. ` +
109
- `Make sure there are no leftovers from previous sessions.`,
105
+ `The port #${tcpPort} at ${TCP_HOST} is busy. Make sure there are no leftovers from previous sessions.`,
110
106
  );
111
107
  }
112
108
  this._screenStreamingProps = undefined;
@@ -139,12 +135,7 @@ export async function mobileStartScreenStreaming(
139
135
  let mjpegConnectTimeoutId: ReturnType<typeof setTimeout> | undefined;
140
136
  const mjpegConnectTimeoutPromise = new Promise<never>((_resolve, reject) => {
141
137
  mjpegConnectTimeoutId = setTimeout(
142
- () =>
143
- reject(
144
- new Error(
145
- `Cannot connect to the streaming server within ${STREAMING_STARTUP_TIMEOUT_MS}ms`,
146
- ),
147
- ),
138
+ () => reject(new Error(`Cannot connect to the streaming server within ${STREAMING_STARTUP_TIMEOUT_MS}ms`)),
148
139
  STREAMING_STARTUP_TIMEOUT_MS,
149
140
  );
150
141
  });
@@ -160,9 +151,7 @@ export async function mobileStartScreenStreaming(
160
151
  );
161
152
 
162
153
  if (pathname && currentPathname !== pathname) {
163
- this.log.info(
164
- 'Rejecting the broadcast request since it does not match the given pathname',
165
- );
154
+ this.log.info('Rejecting the broadcast request since it does not match the given pathname');
166
155
  res.writeHead(404, {
167
156
  Connection: 'close',
168
157
  'Content-Type': 'text/plain; charset=utf-8',
@@ -174,8 +163,7 @@ export async function mobileStartScreenStreaming(
174
163
 
175
164
  this.log.info('Starting MJPEG broadcast');
176
165
  res.writeHead(200, {
177
- 'Cache-Control':
178
- 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
166
+ 'Cache-Control': 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
179
167
  Pragma: 'no-cache',
180
168
  Connection: 'close',
181
169
  'Content-Type': `multipart/x-mixed-replace; boundary=${BOUNDARY_STRING}`,
@@ -253,8 +241,7 @@ export async function mobileStopScreenStreaming(this: AndroidDriver): Promise<vo
253
241
  return;
254
242
  }
255
243
 
256
- const {deviceStreamingProc, gstreamerPipeline, mjpegSocket, mjpegServer} =
257
- this._screenStreamingProps;
244
+ const {deviceStreamingProc, gstreamerPipeline, mjpegSocket, mjpegServer} = this._screenStreamingProps;
258
245
 
259
246
  try {
260
247
  mjpegSocket.end();
@@ -296,9 +283,7 @@ function createStreamingLogger(streamName: string, udid: string): AppiumLogger {
296
283
 
297
284
  async function verifyStreamingRequirements(adb: ADB): Promise<void> {
298
285
  if (!(await adb.shell(['which', SCREENRECORD_BINARY])).trim()) {
299
- throw new Error(
300
- `The required '${SCREENRECORD_BINARY}' binary is not available on the device under test`,
301
- );
286
+ throw new Error(`The required '${SCREENRECORD_BINARY}' binary is not available on the device under test`);
302
287
  }
303
288
 
304
289
  const gstreamerCheckPromises: Promise<void>[] = [];
@@ -349,8 +334,7 @@ async function getDeviceInfo(adb: ADB, log?: AppiumLogger): Promise<DeviceInfo>
349
334
  if (!match) {
350
335
  log?.debug(output);
351
336
  throw new Error(
352
- `Cannot parse the device ${key} from the adb command output. ` +
353
- `Check the server log for more details.`,
337
+ `Cannot parse the device ${key} from the adb command output. Check the server log for more details.`,
354
338
  );
355
339
  }
356
340
  result[key] = parseInt(match[1], 10);
@@ -416,9 +400,7 @@ async function initDeviceStreamingProc(
416
400
  intervalMs: 300,
417
401
  });
418
402
  } catch (e) {
419
- throw log.errorWithException(
420
- `Cannot start the screen streaming process. Original error: ${(e as Error).message}`,
421
- );
403
+ throw log.errorWithException(`Cannot start the screen streaming process. Original error: ${(e as Error).message}`);
422
404
  } finally {
423
405
  deviceStreaming.stderr.removeListener('data', errorsListener);
424
406
  deviceStreaming.stdout.removeListener('data', startupListener);
@@ -501,9 +483,7 @@ async function initGstreamerPipeline(
501
483
  );
502
484
  } catch (e) {
503
485
  didFail = true;
504
- throw log.errorWithException(
505
- `Cannot start the screen streaming pipeline. Original error: ${(e as Error).message}`,
506
- );
486
+ throw log.errorWithException(`Cannot start the screen streaming pipeline. Original error: ${(e as Error).message}`);
507
487
  } finally {
508
488
  if (!logPipelineDetails || didFail) {
509
489
  gstreamerPipeline.removeListener('output', gstOutputListener);
@@ -1,8 +1,9 @@
1
- import {errors} from 'appium/driver.js';
1
+ import {util} from '@appium/support';
2
2
  import type {StringRecord} from '@appium/types';
3
+ import {errors} from 'appium/driver.js';
4
+
3
5
  import type {AndroidDriver} from '../driver.js';
4
6
  import type {StatusBarCommand, WindowProperties} from './types.js';
5
- import {util} from '@appium/support';
6
7
 
7
8
  const WINDOW_TITLE_PATTERN = /^\s+Window\s#\d+\sWindow\{[0-9a-f]+\s\w+\s([\w-]+)\}:$/;
8
9
  const FRAME_PATTERN = /\bm?[Ff]rame=\[([0-9.-]+),([0-9.-]+)\]\[([0-9.-]+),([0-9.-]+)\]/;
@@ -38,12 +39,9 @@ export async function getSystemBars(this: AndroidDriver): Promise<StringRecord>
38
39
  try {
39
40
  stdout = await this.adb.shell(['dumpsys', 'window', 'windows']);
40
41
  } catch (e) {
41
- throw new Error(
42
- `Cannot retrieve system bars details. Original error: ${(e as Error).message}`,
43
- {
44
- cause: e,
45
- },
46
- );
42
+ throw new Error(`Cannot retrieve system bars details. Original error: ${(e as Error).message}`, {
43
+ cause: e,
44
+ });
47
45
  }
48
46
  return parseWindows.bind(this)(stdout);
49
47
  }
@@ -105,11 +103,7 @@ export async function mobilePerformStatusBarCommand(
105
103
  * @returns Parsed properties object
106
104
  * @throws {Error} If there was an issue while parsing the properties string
107
105
  */
108
- export function parseWindowProperties(
109
- this: AndroidDriver,
110
- name: string,
111
- props: string[],
112
- ): WindowProperties {
106
+ export function parseWindowProperties(this: AndroidDriver, name: string, props: string[]): WindowProperties {
113
107
  const result = structuredClone(DEFAULT_WINDOW_PROPERTIES);
114
108
  const propLines = props.join('\n');
115
109
  const frameMatch = FRAME_PATTERN.exec(propLines);
@@ -1,6 +1,7 @@
1
1
  import dayjs from 'dayjs';
2
- import utc from 'dayjs/plugin/utc.js';
3
2
  import customParseFormat from 'dayjs/plugin/customParseFormat.js';
3
+ import utc from 'dayjs/plugin/utc.js';
4
+
4
5
  import type {AndroidDriver} from '../driver.js';
5
6
 
6
7
  dayjs.extend(utc);
@@ -14,13 +15,8 @@ const DATETIME_FORMAT_ISO8601 = 'YYYY-MM-DDTHH:mm:ssZ';
14
15
  * @param format The format string for the time. Defaults to ISO8601 format.
15
16
  * @returns Promise that resolves to the formatted device time string.
16
17
  */
17
- export async function getDeviceTime(
18
- this: AndroidDriver,
19
- format: string = DATETIME_FORMAT_ISO8601,
20
- ): Promise<string> {
21
- this.log.debug(
22
- `Attempting to capture Android device date and time. The format specifier is '${format}'`,
23
- );
18
+ export async function getDeviceTime(this: AndroidDriver, format: string = DATETIME_FORMAT_ISO8601): Promise<string> {
19
+ this.log.debug(`Attempting to capture Android device date and time. The format specifier is '${format}'`);
24
20
  const deviceTimestamp = (await this.adb.shell(['date', '+%Y-%m-%dT%T%z'])).trim();
25
21
  this.log.debug(`Got device timestamp: ${deviceTimestamp}`);
26
22
  const parsedTimestamp = dayjs.utc(deviceTimestamp, 'YYYY-MM-DDTHH:mm:ssZZ');
@@ -1,10 +1,12 @@
1
- import type {HTTPMethod, StringRecord} from '@appium/types';
2
- import type {AndroidDriverCaps} from '../driver.js';
3
- import type {SubProcess} from 'teen_process';
4
- import type {timing} from '@appium/support';
5
1
  import type {ChildProcess} from 'node:child_process';
6
- import type {Socket} from 'node:net';
7
2
  import type {Server} from 'node:http';
3
+ import type {Socket} from 'node:net';
4
+
5
+ import type {timing} from '@appium/support';
6
+ import type {HTTPMethod, StringRecord} from '@appium/types';
7
+ import type {SubProcess} from 'teen_process';
8
+
9
+ import type {AndroidDriverCaps} from '../driver.js';
8
10
 
9
11
  /**
10
12
  * @privateRemarks probably better defined in `appium-adb`
@@ -21,8 +23,7 @@ export type GsmVoiceState = 'on' | 'off';
21
23
 
22
24
  export type PowerACState = 'on' | 'off';
23
25
 
24
- export type NetworkSpeed =
25
- 'gsm' | 'scsd' | 'gprs' | 'edge' | 'umts' | 'hsdpa' | 'lte' | 'evdo' | 'full';
26
+ export type NetworkSpeed = 'gsm' | 'scsd' | 'gprs' | 'edge' | 'umts' | 'hsdpa' | 'lte' | 'evdo' | 'full';
26
27
 
27
28
  /**
28
29
  * Returned by `queryAppState`
@@ -138,9 +139,7 @@ export interface WebviewsMapping {
138
139
  * [8000, [9000, 9100]]
139
140
  * ```
140
141
  */
141
- export type PortSpec = Array<
142
- number | string | [startPort: number | string, endPort: number | string]
143
- >;
142
+ export type PortSpec = Array<number | string | [startPort: number | string, endPort: number | string]>;
144
143
 
145
144
  export interface DoSetElementValueOpts {
146
145
  elementId: string;
@@ -1,19 +1,18 @@
1
- import {resolveExecutablePath} from './utils.js';
2
- import {system, fs, doctor, console} from '@appium/support';
3
1
  import path from 'node:path';
4
- import {getAndroidBinaryPath, getSdkRootFromEnv} from 'appium-adb';
2
+
3
+ import {system, fs, doctor, console} from '@appium/support';
5
4
  import type {IDoctorCheck, AppiumLogger, DoctorCheckResult} from '@appium/types';
5
+ import {getAndroidBinaryPath, getSdkRootFromEnv} from 'appium-adb';
6
+
7
+ import {resolveExecutablePath} from './utils.js';
6
8
 
7
9
  const JAVA_HOME_VAR_NAME = system.isWindows() ? '%JAVA_HOME%' : '$JAVA_HOME';
8
- const ENVIRONMENT_VARS_TUTORIAL_URL =
9
- 'https://github.com/appium/java-client/blob/master/docs/environment.md';
10
- const JAVA_HOME_TUTORIAL =
11
- 'https://docs.oracle.com/cd/E21454_01/html/821-2531/inst_jdk_javahome_t.html';
10
+ const ENVIRONMENT_VARS_TUTORIAL_URL = 'https://github.com/appium/java-client/blob/master/docs/environment.md';
11
+ const JAVA_HOME_TUTORIAL = 'https://docs.oracle.com/cd/E21454_01/html/821-2531/inst_jdk_javahome_t.html';
12
12
  const ANDROID_SDK_LINK1 = 'https://developer.android.com/studio#cmdline-tools';
13
13
  const ANDROID_SDK_LINK2 = 'https://developer.android.com/studio/intro/update#sdk-manager';
14
14
  const BUNDLETOOL_RELEASES_LINK = 'https://github.com/google/bundletool/releases/';
15
- const GSTREAMER_INSTALL_LINK =
16
- 'https://gstreamer.freedesktop.org/documentation/installing/index.html?gi-language=c';
15
+ const GSTREAMER_INSTALL_LINK = 'https://gstreamer.freedesktop.org/documentation/installing/index.html?gi-language=c';
17
16
  const FFMPEG_INSTALL_LINK = 'https://www.ffmpeg.org/download.html';
18
17
 
19
18
  export interface EnvVarCheckOptions {
@@ -47,14 +46,10 @@ class EnvVarAndPathCheck implements IDoctorCheck {
47
46
 
48
47
  const stat = await fs.stat(varValue);
49
48
  if (this.opts.expectDir && !stat.isDirectory()) {
50
- return doctor.nok(
51
- `${this.varName} is expected to be a valid folder, got a file path instead`,
52
- );
49
+ return doctor.nok(`${this.varName} is expected to be a valid folder, got a file path instead`);
53
50
  }
54
51
  if (this.opts.expectFile && stat.isDirectory()) {
55
- return doctor.nok(
56
- `${this.varName} is expected to be a valid file, got a folder path instead`,
57
- );
52
+ return doctor.nok(`${this.varName} is expected to be a valid file, got a folder path instead`);
58
53
  }
59
54
 
60
55
  return doctor.ok(`${this.varName} is set to: ${varValue}`);
@@ -203,9 +198,7 @@ export class OptionalGstreamerCheck implements IDoctorCheck {
203
198
  ? doctor.okOptional(
204
199
  `${this.GSTREAMER_BINARY} and ${this.GST_INSPECT_BINARY} are installed at: ${gstreamerPath} and ${gstInspectPath}`,
205
200
  )
206
- : doctor.nokOptional(
207
- `${this.GSTREAMER_BINARY} and/or ${this.GST_INSPECT_BINARY} cannot be found`,
208
- );
201
+ : doctor.nokOptional(`${this.GSTREAMER_BINARY} and/or ${this.GST_INSPECT_BINARY} cannot be found`);
209
202
  }
210
203
 
211
204
  async fix(): Promise<string> {
package/lib/driver.ts CHANGED
@@ -10,12 +10,34 @@ import type {
10
10
  import type {ADB, LogcatListener} from 'appium-adb';
11
11
  import type {Chromedriver as AppiumChromedriver} from 'appium-chromedriver';
12
12
  import {BaseDriver} from 'appium/driver.js';
13
- import {ANDROID_DRIVER_CONSTRAINTS} from './constraints.js';
14
- import type {AndroidDriverConstraints} from './constraints.js';
15
- import {newMethodMap} from './method-map.js';
16
13
  import {SettingsApp} from 'io.appium.settings';
17
- import {parseArray, removeAllSessionWebSocketHandlers} from './utils.js';
18
- import {CHROME_BROWSER_PACKAGE_ACTIVITY} from './commands/context/helpers.js';
14
+ import {LRUCache} from 'lru-cache';
15
+
16
+ import {
17
+ getThirdPartyPackages,
18
+ uninstallOtherPackages,
19
+ installOtherApks,
20
+ installAUT,
21
+ resetAUT,
22
+ background,
23
+ mobileBackgroundApp,
24
+ getCurrentActivity,
25
+ getCurrentPackage,
26
+ mobileClearApp,
27
+ mobileInstallApp,
28
+ installApp,
29
+ mobileIsAppInstalled,
30
+ mobileRemoveApp,
31
+ mobileTerminateApp,
32
+ mobileListApps,
33
+ terminateApp,
34
+ removeApp,
35
+ activateApp,
36
+ queryAppState,
37
+ isAppInstalled,
38
+ } from './commands/app-management.js';
39
+ import {mobileGetUiMode, mobileSetUiMode} from './commands/appearance.js';
40
+ import {mobileBluetooth} from './commands/bluetooth.js';
19
41
  import {
20
42
  getContexts,
21
43
  setContext,
@@ -38,12 +60,8 @@ import {
38
60
  setWindow,
39
61
  notifyBiDiContextChange,
40
62
  } from './commands/context/exports.js';
41
- import {
42
- getDeviceInfoFromCaps,
43
- createADB,
44
- getLaunchInfo,
45
- initDevice,
46
- } from './commands/device/common.js';
63
+ import {CHROME_BROWSER_PACKAGE_ACTIVITY} from './commands/context/helpers.js';
64
+ import {getDeviceInfoFromCaps, createADB, getLaunchInfo, initDevice} from './commands/device/common.js';
47
65
  import {
48
66
  fingerprint,
49
67
  mobileFingerprint,
@@ -64,32 +82,7 @@ import {
64
82
  sensorSet,
65
83
  } from './commands/device/emulator-actions.js';
66
84
  import {mobileExecEmuConsoleCommand} from './commands/device/emulator-console.js';
67
- import {
68
- getThirdPartyPackages,
69
- uninstallOtherPackages,
70
- installOtherApks,
71
- installAUT,
72
- resetAUT,
73
- background,
74
- mobileBackgroundApp,
75
- getCurrentActivity,
76
- getCurrentPackage,
77
- mobileClearApp,
78
- mobileInstallApp,
79
- installApp,
80
- mobileIsAppInstalled,
81
- mobileRemoveApp,
82
- mobileTerminateApp,
83
- mobileListApps,
84
- terminateApp,
85
- removeApp,
86
- activateApp,
87
- queryAppState,
88
- isAppInstalled,
89
- } from './commands/app-management.js';
90
- import {mobileGetUiMode, mobileSetUiMode} from './commands/appearance.js';
91
85
  import {mobileDeviceidle} from './commands/deviceidle.js';
92
- import {mobileBluetooth} from './commands/bluetooth.js';
93
86
  import {
94
87
  getAttribute,
95
88
  getName,
@@ -121,6 +114,7 @@ import {
121
114
  mobileResetGeolocation,
122
115
  } from './commands/geolocation.js';
123
116
  import {performActions} from './commands/gestures.js';
117
+ import {mobileInjectEmulatorCameraImage} from './commands/image-injection.js';
124
118
  import {
125
119
  isIMEActivated,
126
120
  availableIMEEngines,
@@ -145,6 +139,7 @@ import {
145
139
  longPressKeyCode,
146
140
  mobilePerformEditorAction,
147
141
  } from './commands/keyboard.js';
142
+ import {reset, closeApp, launchApp} from './commands/legacy.js';
148
143
  import {lock, unlock, mobileUnlock, isLocked} from './commands/lock/exports.js';
149
144
  import {
150
145
  supportedLogTypes,
@@ -160,8 +155,6 @@ import {
160
155
  mobileStopMediaProjectionRecording,
161
156
  } from './commands/media-projection.js';
162
157
  import {mobileSendTrimMemory} from './commands/memory.js';
163
- import {mobileNfc} from './commands/nfc.js';
164
- import {mobileInjectEmulatorCameraImage} from './commands/image-injection.js';
165
158
  import {
166
159
  getWindowRect,
167
160
  getWindowSize,
@@ -183,12 +176,8 @@ import {
183
176
  toggleFlightMode,
184
177
  toggleWiFi,
185
178
  } from './commands/network.js';
186
- import {
187
- getPerformanceData,
188
- getPerformanceDataTypes,
189
- mobileGetPerformanceData,
190
- } from './commands/performance.js';
191
- import {reset, closeApp, launchApp} from './commands/legacy.js';
179
+ import {mobileNfc} from './commands/nfc.js';
180
+ import {getPerformanceData, getPerformanceDataTypes, mobileGetPerformanceData} from './commands/performance.js';
192
181
  import {mobileChangePermissions, mobileGetPermissions} from './commands/permissions.js';
193
182
  import {startRecordingScreen, stopRecordingScreen} from './commands/recordscreen.js';
194
183
  import {getStrings, ensureDeviceLocale} from './commands/resources.js';
@@ -196,9 +185,12 @@ import {mobileShell} from './commands/shell.js';
196
185
  import {mobileStartScreenStreaming, mobileStopScreenStreaming} from './commands/streamscreen.js';
197
186
  import {getSystemBars, mobilePerformStatusBarCommand} from './commands/system-bars.js';
198
187
  import {getDeviceTime, mobileGetDeviceTime} from './commands/time.js';
199
- import {executeMethodMap} from './execute-method-map.js';
200
- import {LRUCache} from 'lru-cache';
201
188
  import type {ScreenRecordingProperties, ScreenStreamingProps} from './commands/types.js';
189
+ import {ANDROID_DRIVER_CONSTRAINTS} from './constraints.js';
190
+ import type {AndroidDriverConstraints} from './constraints.js';
191
+ import {executeMethodMap} from './execute-method-map.js';
192
+ import {newMethodMap} from './method-map.js';
193
+ import {parseArray, removeAllSessionWebSocketHandlers} from './utils.js';
202
194
 
203
195
  export type AndroidDriverCaps = DriverCaps<AndroidDriverConstraints>;
204
196
  export type W3CAndroidDriverCaps = W3CDriverCaps<AndroidDriverConstraints>;
@@ -454,13 +446,7 @@ class AndroidDriver
454
446
  constructor(opts: InitialOpts = {} as InitialOpts, shouldValidateCaps = true) {
455
447
  super(opts, shouldValidateCaps);
456
448
 
457
- this.locatorStrategies = [
458
- 'xpath',
459
- 'id',
460
- 'class name',
461
- 'accessibility id',
462
- '-android uiautomator',
463
- ];
449
+ this.locatorStrategies = ['xpath', 'id', 'class name', 'accessibility id', '-android uiautomator'];
464
450
  this.desiredCapConstraints = structuredClone(ANDROID_DRIVER_CONSTRAINTS);
465
451
  this.sessionChromedrivers = {};
466
452
  this.jwpProxyActive = false;
@@ -482,9 +468,7 @@ class AndroidDriver
482
468
  }
483
469
 
484
470
  get isChromeSession(): boolean {
485
- return Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY).includes(
486
- (this.opts.browserName || '').toLowerCase(),
487
- );
471
+ return Object.keys(CHROME_BROWSER_PACKAGE_ACTIVITY).includes((this.opts.browserName || '').toLowerCase());
488
472
  }
489
473
 
490
474
  isEmulator(): boolean {
@@ -500,14 +484,10 @@ class AndroidDriver
500
484
  if (caps.browserName) {
501
485
  if (caps.app) {
502
486
  // warn if the capabilities have both `app` and `browser, although this is common with selenium grid
503
- this.log.warn(
504
- `The desired capabilities should generally not include both an 'app' and a 'browserName'`,
505
- );
487
+ this.log.warn(`The desired capabilities should generally not include both an 'app' and a 'browserName'`);
506
488
  }
507
489
  if (caps.appPackage) {
508
- throw this.log.errorWithException(
509
- `The desired should not include both of an 'appPackage' and a 'browserName'`,
510
- );
490
+ throw this.log.errorWithException(`The desired should not include both of an 'appPackage' and a 'browserName'`);
511
491
  }
512
492
  }
513
493
 
@@ -531,9 +511,7 @@ class AndroidDriver
531
511
  this.adb?.logcat?.removeAllListeners();
532
512
  await this.adb?.stopLogcat();
533
513
  } catch (e) {
534
- this.log.warn(
535
- `Cannot stop the logcat process. Original error: ${e instanceof Error ? e.message : String(e)}`,
536
- );
514
+ this.log.warn(`Cannot stop the logcat process. Original error: ${e instanceof Error ? e.message : String(e)}`);
537
515
  }
538
516
 
539
517
  if (this._bidiServerLogListener) {