appium-android-driver 12.4.7 → 12.4.9

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 (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/commands/file-actions.d.ts +37 -19
  3. package/build/lib/commands/file-actions.d.ts.map +1 -1
  4. package/build/lib/commands/file-actions.js +44 -58
  5. package/build/lib/commands/file-actions.js.map +1 -1
  6. package/build/lib/commands/geolocation.d.ts +44 -36
  7. package/build/lib/commands/geolocation.d.ts.map +1 -1
  8. package/build/lib/commands/geolocation.js +38 -32
  9. package/build/lib/commands/geolocation.js.map +1 -1
  10. package/build/lib/commands/intent.d.ts +103 -107
  11. package/build/lib/commands/intent.d.ts.map +1 -1
  12. package/build/lib/commands/intent.js +103 -97
  13. package/build/lib/commands/intent.js.map +1 -1
  14. package/build/lib/commands/log.d.ts +44 -48
  15. package/build/lib/commands/log.d.ts.map +1 -1
  16. package/build/lib/commands/log.js +30 -54
  17. package/build/lib/commands/log.js.map +1 -1
  18. package/build/lib/commands/network.d.ts +59 -39
  19. package/build/lib/commands/network.d.ts.map +1 -1
  20. package/build/lib/commands/network.js +65 -45
  21. package/build/lib/commands/network.js.map +1 -1
  22. package/build/lib/commands/recordscreen.d.ts +25 -40
  23. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  24. package/build/lib/commands/recordscreen.js +46 -63
  25. package/build/lib/commands/recordscreen.js.map +1 -1
  26. package/build/lib/commands/types.d.ts.map +1 -1
  27. package/build/lib/driver.d.ts +11 -10
  28. package/build/lib/driver.d.ts.map +1 -1
  29. package/build/lib/driver.js.map +1 -1
  30. package/lib/commands/{file-actions.js → file-actions.ts} +88 -74
  31. package/lib/commands/{geolocation.js → geolocation.ts} +85 -54
  32. package/lib/commands/intent.ts +422 -0
  33. package/lib/commands/{log.js → log.ts} +68 -73
  34. package/lib/commands/{network.js → network.ts} +106 -59
  35. package/lib/commands/{recordscreen.js → recordscreen.ts} +77 -73
  36. package/lib/commands/types.ts +17 -0
  37. package/lib/driver.ts +2 -1
  38. package/package.json +1 -1
  39. package/lib/commands/intent.js +0 -409
@@ -2,6 +2,8 @@ import _ from 'lodash';
2
2
  import {fs, util, zip, tempDir} from '@appium/support';
3
3
  import path from 'path';
4
4
  import {errors} from 'appium/driver';
5
+ import type {AndroidDriver} from '../driver';
6
+ import type {ADB} from 'appium-adb';
5
7
 
6
8
  const CONTAINER_PATH_MARKER = '@';
7
9
  // https://regex101.com/r/PLdB0G/2
@@ -9,21 +11,31 @@ const CONTAINER_PATH_PATTERN = new RegExp(`^${CONTAINER_PATH_MARKER}([^/]+)/(.+)
9
11
  const ANDROID_MEDIA_RESCAN_INTENT = 'android.intent.action.MEDIA_SCANNER_SCAN_FILE';
10
12
 
11
13
  /**
12
- * @this {import('../driver').AndroidDriver}
13
- * @param {string} remotePath The full path to the remote file or a specially formatted path, which
14
+ * Pulls a file from the remote device.
15
+ *
16
+ * The full path to the remote file or a specially formatted path, which
17
+ * points to an item inside an app bundle, for example `@my.app.id/my/path`.
18
+ * It is mandatory for the app bundle to have debugging enabled in order to
19
+ * use the latter `remotePath` format.
20
+ *
21
+ * @param remotePath The full path to the remote file or a specially formatted path, which
14
22
  * points to an item inside an app bundle, for example `@my.app.id/my/path`.
15
23
  * It is mandatory for the app bundle to have debugging enabled in order to
16
24
  * use the latter `remotePath` format.
17
- * @returns {Promise<string>}
25
+ * @returns Promise that resolves to the file content as a base64-encoded string.
26
+ * @throws {errors.InvalidArgumentError} If the remote path points to a folder instead of a file.
18
27
  */
19
- export async function pullFile(remotePath) {
28
+ export async function pullFile(
29
+ this: AndroidDriver,
30
+ remotePath: string,
31
+ ): Promise<string> {
20
32
  if (remotePath.endsWith('/')) {
21
33
  throw new errors.InvalidArgumentError(
22
34
  `It is expected that remote path points to a file and not to a folder. ` +
23
35
  `'${remotePath}' is given instead`,
24
36
  );
25
37
  }
26
- let tmpDestination = null;
38
+ let tmpDestination: string | null = null;
27
39
  if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
28
40
  const [packageId, pathInContainer] = parseContainerPath(remotePath);
29
41
  this.log.debug(
@@ -41,7 +53,7 @@ export async function pullFile(remotePath) {
41
53
  throw this.log.errorWithException(
42
54
  `Cannot access the container of '${packageId}' application. ` +
43
55
  `Is the application installed and has 'debuggable' build option set to true? ` +
44
- `Original error: ${/** @type {Error} */ (e).message}`,
56
+ `Original error: ${(e as Error).message}`,
45
57
  );
46
58
  }
47
59
  }
@@ -60,15 +72,27 @@ export async function pullFile(remotePath) {
60
72
  }
61
73
 
62
74
  /**
63
- * @this {import('../driver').AndroidDriver}
64
- * @param {string} remotePath The full path to the remote file or a specially formatted path, which
75
+ * Pushes a file to the remote device.
76
+ *
77
+ * The full path to the remote file or a specially formatted path, which
65
78
  * points to an item inside an app bundle, for example `@my.app.id/my/path`.
66
79
  * It is mandatory for the app bundle to have debugging enabled in order to
67
80
  * use the latter `remotePath` format.
68
- * @param {string} base64Data Base64-encoded content of the file to be pushed.
69
- * @returns {Promise<void>}
81
+ *
82
+ * @param remotePath The full path to the remote file or a specially formatted path, which
83
+ * points to an item inside an app bundle, for example `@my.app.id/my/path`.
84
+ * It is mandatory for the app bundle to have debugging enabled in order to
85
+ * use the latter `remotePath` format.
86
+ * @param base64Data Base64-encoded content of the file to be pushed.
87
+ * Can be a string or an array of numbers (for Java clients that send byte arrays).
88
+ * @returns Promise that resolves when the file is pushed.
89
+ * @throws {errors.InvalidArgumentError} If the remote path points to a folder instead of a file.
70
90
  */
71
- export async function pushFile(remotePath, base64Data) {
91
+ export async function pushFile(
92
+ this: AndroidDriver,
93
+ remotePath: string,
94
+ base64Data: string | number[],
95
+ ): Promise<void> {
72
96
  if (remotePath.endsWith('/')) {
73
97
  throw new errors.InvalidArgumentError(
74
98
  `It is expected that remote path points to a file and not to a folder. ` +
@@ -76,13 +100,16 @@ export async function pushFile(remotePath, base64Data) {
76
100
  );
77
101
  }
78
102
  const localFile = await tempDir.path({prefix: 'appium', suffix: '.tmp'});
103
+ let base64String: string;
79
104
  if (_.isArray(base64Data)) {
80
105
  // some clients (ahem) java, send a byte array encoding utf8 characters
81
106
  // instead of a string, which would be infinitely better!
82
- base64Data = Buffer.from(base64Data).toString('utf8');
107
+ base64String = Buffer.from(base64Data).toString('utf8');
108
+ } else {
109
+ base64String = base64Data;
83
110
  }
84
- const content = Buffer.from(base64Data, 'base64');
85
- let tmpDestination = null;
111
+ const content = Buffer.from(base64String, 'base64');
112
+ let tmpDestination: string | null = null;
86
113
  try {
87
114
  await fs.writeFile(localFile, content.toString('binary'), 'binary');
88
115
  if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
@@ -110,7 +137,7 @@ export async function pushFile(remotePath, base64Data) {
110
137
  throw this.log.errorWithException(
111
138
  `Cannot access the container of '${packageId}' application. ` +
112
139
  `Is the application installed and has 'debuggable' build option set to true? ` +
113
- `Original error: ${/** @type {Error} */ (e).message}`,
140
+ `Original error: ${(e as Error).message}`,
114
141
  );
115
142
  }
116
143
  } else {
@@ -132,11 +159,15 @@ export async function pushFile(remotePath, base64Data) {
132
159
  }
133
160
 
134
161
  /**
135
- * @this {import('../driver').AndroidDriver}
136
- * @param {string} remotePath The full path to the remote folder
137
- * @returns {Promise<string>}
162
+ * Pulls a folder from the remote device.
163
+ *
164
+ * @param remotePath The full path to the remote folder.
165
+ * @returns Promise that resolves to the folder content as a base64-encoded zip file string.
138
166
  */
139
- export async function pullFolder(remotePath) {
167
+ export async function pullFolder(
168
+ this: AndroidDriver,
169
+ remotePath: string,
170
+ ): Promise<string> {
140
171
  const tmpRoot = await tempDir.openDir();
141
172
  try {
142
173
  await this.adb.pull(remotePath, tmpRoot);
@@ -151,12 +182,17 @@ export async function pullFolder(remotePath) {
151
182
  }
152
183
 
153
184
  /**
154
- * @this {import('../driver').AndroidDriver}
155
- * @param {string} remotePath The full path to the remote file or a file inside an application bundle
156
- * (for example `@my.app.id/path/in/bundle`)
157
- * @returns {Promise<boolean>}
185
+ * Deletes a file from the remote device.
186
+ *
187
+ * @param remotePath The full path to the remote file or a file inside an application bundle
188
+ * (for example `@my.app.id/path/in/bundle`).
189
+ * @returns Promise that resolves to `true` if the file was successfully deleted, `false` if it doesn't exist.
190
+ * @throws {errors.InvalidArgumentError} If the remote path points to a folder instead of a file.
158
191
  */
159
- export async function mobileDeleteFile(remotePath) {
192
+ export async function mobileDeleteFile(
193
+ this: AndroidDriver,
194
+ remotePath: string,
195
+ ): Promise<boolean> {
160
196
  if (remotePath.endsWith('/')) {
161
197
  throw new errors.InvalidArgumentError(
162
198
  `It is expected that remote path points to a folder and not to a file. ` +
@@ -169,21 +205,20 @@ export async function mobileDeleteFile(remotePath) {
169
205
  /**
170
206
  * Deletes the given folder or file from the remote device
171
207
  *
172
- * @param {ADB} adb
173
- * @param {string} remotePath The full path to the remote folder
174
- * or file (folder names must end with a single slash)
175
208
  * @throws {Error} If the provided remote path is invalid or
176
209
  * the package content cannot be accessed
177
- * @returns {Promise<boolean>} `true` if the remote item has been successfully deleted.
210
+ * @returns `true` if the remote item has been successfully deleted.
178
211
  * If the remote path is valid, but the remote path does not exist
179
212
  * this function return `false`.
180
- * @this {import('../driver').AndroidDriver}
181
213
  */
182
- async function deleteFileOrFolder(adb, remotePath) {
214
+ async function deleteFileOrFolder(
215
+ this: AndroidDriver,
216
+ adb: ADB,
217
+ remotePath: string,
218
+ ): Promise<boolean> {
183
219
  const {isDir, isPresent, isFile} = createFSTests(adb);
184
220
  let dstPath = remotePath;
185
- /** @type {string|undefined} */
186
- let pkgId;
221
+ let pkgId: string | undefined;
187
222
  if (remotePath.startsWith(CONTAINER_PATH_MARKER)) {
188
223
  const [packageId, pathInContainer] = parseContainerPath(remotePath);
189
224
  this.log.debug(`Parsed package identifier '${packageId}' from '${remotePath}'`);
@@ -198,7 +233,7 @@ async function deleteFileOrFolder(adb, remotePath) {
198
233
  throw this.log.errorWithException(
199
234
  `Cannot access the container of '${pkgId}' application. ` +
200
235
  `Is the application installed and has 'debuggable' build option set to true? ` +
201
- `Original error: ${/** @type {Error} */ (e).message}`,
236
+ `Original error: ${(e as Error).message}`,
202
237
  );
203
238
  }
204
239
  }
@@ -233,13 +268,11 @@ async function deleteFileOrFolder(adb, remotePath) {
233
268
  /**
234
269
  * Parses the actual destination path from the given value
235
270
  *
236
- * @param {string} remotePath The preformatted remote path, which looks like
237
- * `@my.app.id/my/path`
238
- * @returns {Array<string>} An array, where the first item is the parsed package
271
+ * @returns An array, where the first item is the parsed package
239
272
  * identifier and the second one is the actual destination path inside the package.
240
273
  * @throws {Error} If the given string cannot be parsed
241
274
  */
242
- function parseContainerPath(remotePath) {
275
+ function parseContainerPath(remotePath: string): [string, string] {
243
276
  const match = CONTAINER_PATH_PATTERN.exec(remotePath);
244
277
  if (!match) {
245
278
  throw new Error(
@@ -254,11 +287,11 @@ function parseContainerPath(remotePath) {
254
287
  * Scans the given file/folder on the remote device
255
288
  * and adds matching items to the device's media library.
256
289
  * Exceptions are ignored and written into the log.
257
- *
258
- * @this {import('../driver').AndroidDriver}
259
- * @param {string} remotePath The file/folder path on the remote device
260
290
  */
261
- async function scanMedia(remotePath) {
291
+ async function scanMedia(
292
+ this: AndroidDriver,
293
+ remotePath: string,
294
+ ): Promise<void> {
262
295
  this.log.debug(`Performing media scan of '${remotePath}'`);
263
296
  try {
264
297
  // https://github.com/appium/appium/issues/16184
@@ -275,7 +308,7 @@ async function scanMedia(remotePath) {
275
308
  ]);
276
309
  }
277
310
  } catch (e) {
278
- const err = /** @type {any} */ (e);
311
+ const err = e as {stderr?: string; message?: string};
279
312
  // FIXME: what has a `stderr` prop?
280
313
  this.log.warn(
281
314
  `Ignoring an unexpected error upon media scanning of '${remotePath}': ${
@@ -288,27 +321,20 @@ async function scanMedia(remotePath) {
288
321
  /**
289
322
  * A small helper, which escapes single quotes in paths,
290
323
  * so they are safe to be passed as arguments of shell commands
291
- *
292
- * @param {string} p The initial remote path
293
- * @returns {string} The escaped path value
294
324
  */
295
- function escapePath(p) {
325
+ function escapePath(p: string): string {
296
326
  return p.replace(/'/g, `\\'`);
297
327
  }
298
328
 
299
329
  /**
300
330
  * Factory providing filesystem test functions using ADB
301
- * @param {ADB} adb
302
331
  */
303
- function createFSTests(adb) {
304
- /**
305
- *
306
- * @param {string} p
307
- * @param {'d'|'f'|'e'} op
308
- * @param {string} [runAs]
309
- * @returns
310
- */
311
- const performRemoteFsCheck = async (p, op, runAs) => {
332
+ function createFSTests(adb: ADB) {
333
+ const performRemoteFsCheck = async (
334
+ p: string,
335
+ op: 'd' | 'f' | 'e',
336
+ runAs?: string,
337
+ ): Promise<boolean> => {
312
338
  const passFlag = '__PASS__';
313
339
  const checkCmd = `[ -${op} '${escapePath(p)}' ] && echo ${passFlag}`;
314
340
  const fullCmd = runAs ? `run-as ${runAs} ${checkCmd}` : checkCmd;
@@ -319,27 +345,15 @@ function createFSTests(adb) {
319
345
  }
320
346
  };
321
347
 
322
- /**
323
- * @param {string} p
324
- * @param {string} [runAs]
325
- */
326
- const isFile = async (p, runAs) => await performRemoteFsCheck(p, 'f', runAs);
327
- /**
328
- * @param {string} p
329
- * @param {string} [runAs]
330
- */
331
- const isDir = async (p, runAs) => await performRemoteFsCheck(p, 'd', runAs);
332
- /**
333
- * @param {string} p
334
- * @param {string} [runAs]
335
- */
336
- const isPresent = async (p, runAs) => await performRemoteFsCheck(p, 'e', runAs);
348
+ const isFile = async (p: string, runAs?: string): Promise<boolean> =>
349
+ await performRemoteFsCheck(p, 'f', runAs);
350
+ const isDir = async (p: string, runAs?: string): Promise<boolean> =>
351
+ await performRemoteFsCheck(p, 'd', runAs);
352
+ const isPresent = async (p: string, runAs?: string): Promise<boolean> =>
353
+ await performRemoteFsCheck(p, 'e', runAs);
337
354
 
338
355
  return {isFile, isDir, isPresent};
339
356
  }
340
357
 
341
358
  // #endregion
342
359
 
343
- /**
344
- * @typedef {import('appium-adb').ADB} ADB
345
- */
@@ -2,8 +2,10 @@ import _ from 'lodash';
2
2
  import {fs, tempDir} from '@appium/support';
3
3
  import path from 'node:path';
4
4
  import B from 'bluebird';
5
+ import type {Location} from '@appium/types';
5
6
  import {SETTINGS_HELPER_ID} from 'io.appium.settings';
6
7
  import {getThirdPartyPackages} from './app-management';
8
+ import type {AndroidDriver} from '../driver';
7
9
 
8
10
  // The value close to zero, but not zero, is needed
9
11
  // to trick JSON generation and send a float value instead of an integer,
@@ -14,17 +16,21 @@ const GEO_EPSILON = Number.MIN_VALUE;
14
16
  const MOCK_APP_IDS_STORE = '/data/local/tmp/mock_apps.json';
15
17
 
16
18
  /**
17
- * @this {import('../driver').AndroidDriver}
18
- * @param {import('@appium/types').Location} location
19
- * @returns {Promise<import('@appium/types').Location>}
19
+ * Sets the device geolocation.
20
+ *
21
+ * @param location The geolocation object containing latitude, longitude, and altitude.
22
+ * @returns Promise that resolves to the current geolocation after setting it.
20
23
  */
21
- export async function setGeoLocation(location) {
24
+ export async function setGeoLocation(
25
+ this: AndroidDriver,
26
+ location: Location,
27
+ ): Promise<Location> {
22
28
  await this.settingsApp.setGeoLocation(location, this.isEmulator());
23
29
  try {
24
30
  return await this.getGeoLocation();
25
31
  } catch (e) {
26
32
  this.log.warn(
27
- `Could not get the current geolocation info: ${/** @type {Error} */ (e).message}`,
33
+ `Could not get the current geolocation info: ${(e as Error).message}`,
28
34
  );
29
35
  this.log.warn(`Returning the default zero'ed values`);
30
36
  return {
@@ -38,28 +44,28 @@ export async function setGeoLocation(location) {
38
44
  /**
39
45
  * Set the device geolocation.
40
46
  *
41
- * @this {import('../driver').AndroidDriver}
42
- * @param {number} latitude Valid latitude value.
43
- * @param {number} longitude Valid longitude value.
44
- * @param {number} [altitude] Valid altitude value.
45
- * @param {number} [satellites] Number of satellites being tracked (1-12). Available for emulators.
46
- * @param {number} [speed] Valid speed value.
47
+ * @param latitude Valid latitude value.
48
+ * @param longitude Valid longitude value.
49
+ * @param altitude Valid altitude value.
50
+ * @param satellites Number of satellites being tracked (1-12). Available for emulators.
51
+ * @param speed Valid speed value.
47
52
  * https://developer.android.com/reference/android/location/Location#setSpeed(float)
48
- * @param {number} [bearing] Valid bearing value. Available for real devices.
53
+ * @param bearing Valid bearing value. Available for real devices.
49
54
  * https://developer.android.com/reference/android/location/Location#setBearing(float)
50
- * @param {number} [accuracy] Valid accuracy value. Available for real devices.
55
+ * @param accuracy Valid accuracy value. Available for real devices.
51
56
  * https://developer.android.com/reference/android/location/Location#setAccuracy(float),
52
57
  * https://developer.android.com/reference/android/location/Criteria
53
58
  */
54
59
  export async function mobileSetGeolocation(
55
- latitude,
56
- longitude,
57
- altitude,
58
- satellites,
59
- speed,
60
- bearing,
61
- accuracy
62
- ) {
60
+ this: AndroidDriver,
61
+ latitude: number,
62
+ longitude: number,
63
+ altitude?: number,
64
+ satellites?: number,
65
+ speed?: number,
66
+ bearing?: number,
67
+ accuracy?: number,
68
+ ): Promise<void> {
63
69
  await this.settingsApp.setGeoLocation({
64
70
  latitude,
65
71
  longitude,
@@ -67,7 +73,7 @@ export async function mobileSetGeolocation(
67
73
  satellites,
68
74
  speed,
69
75
  bearing,
70
- accuracy
76
+ accuracy,
71
77
  }, this.isEmulator());
72
78
  }
73
79
 
@@ -78,22 +84,27 @@ export async function mobileSetGeolocation(
78
84
  * installed. In case the vanilla LocationManager is used the device API level
79
85
  * must be at version 30 (Android R) or higher.
80
86
  *
81
- * @this {import('../driver').AndroidDriver}
82
- * @param {number} [timeoutMs] The maximum number of milliseconds
87
+ * @param timeoutMs The maximum number of milliseconds
83
88
  * to block until GPS cache is refreshed. Providing zero or a negative
84
89
  * value to it skips waiting completely.
85
90
  * 20000ms by default.
86
- * @returns {Promise<void>}
91
+ * @returns Promise that resolves when the GPS cache refresh is initiated.
87
92
  */
88
- export async function mobileRefreshGpsCache(timeoutMs) {
93
+ export async function mobileRefreshGpsCache(
94
+ this: AndroidDriver,
95
+ timeoutMs?: number,
96
+ ): Promise<void> {
89
97
  await this.settingsApp.refreshGeoLocationCache(timeoutMs);
90
98
  }
91
99
 
92
100
  /**
93
- * @this {import('../driver').AndroidDriver}
94
- * @returns {Promise<import('@appium/types').Location>}
101
+ * Gets the current device geolocation.
102
+ *
103
+ * @returns Promise that resolves to the current geolocation object.
95
104
  */
96
- export async function getGeoLocation() {
105
+ export async function getGeoLocation(
106
+ this: AndroidDriver,
107
+ ): Promise<Location> {
97
108
  const {latitude, longitude, altitude} = await this.settingsApp.getGeoLocation();
98
109
  return {
99
110
  latitude: parseFloat(String(latitude)) || GEO_EPSILON,
@@ -103,26 +114,35 @@ export async function getGeoLocation() {
103
114
  }
104
115
 
105
116
  /**
106
- * @this {import('../driver').AndroidDriver}
107
- * @returns {Promise<import('@appium/types').Location>}
117
+ * Gets the current device geolocation.
118
+ *
119
+ * @returns Promise that resolves to the current geolocation object.
108
120
  */
109
- export async function mobileGetGeolocation() {
121
+ export async function mobileGetGeolocation(
122
+ this: AndroidDriver,
123
+ ): Promise<Location> {
110
124
  return await this.getGeoLocation();
111
125
  }
112
126
 
113
127
  /**
114
- * @this {import('../driver').AndroidDriver}
115
- * @returns {Promise<boolean>}
128
+ * Checks if location services are enabled.
129
+ *
130
+ * @returns Promise that resolves to `true` if location services are enabled, `false` otherwise.
116
131
  */
117
- export async function isLocationServicesEnabled() {
132
+ export async function isLocationServicesEnabled(
133
+ this: AndroidDriver,
134
+ ): Promise<boolean> {
118
135
  return (await this.adb.getLocationProviders()).includes('gps');
119
136
  }
120
137
 
121
138
  /**
122
- * @this {import('../driver').AndroidDriver}
123
- * @returns {Promise<void>}
139
+ * Toggles the location services state.
140
+ *
141
+ * @returns Promise that resolves when the location services state is toggled.
124
142
  */
125
- export async function toggleLocationServices() {
143
+ export async function toggleLocationServices(
144
+ this: AndroidDriver,
145
+ ): Promise<void> {
126
146
  this.log.info('Toggling location services');
127
147
  const isGpsEnabled = await this.isLocationServicesEnabled();
128
148
  this.log.debug(
@@ -133,10 +153,14 @@ export async function toggleLocationServices() {
133
153
  }
134
154
 
135
155
  /**
136
- * @this {import('../driver').AndroidDriver}
137
- * @returns {Promise<void>}
156
+ * Resets the geolocation to the default state.
157
+ *
158
+ * @returns Promise that resolves when the geolocation is reset.
159
+ * @throws {Error} If called on an emulator (geolocation reset does not work on emulators).
138
160
  */
139
- export async function mobileResetGeolocation() {
161
+ export async function mobileResetGeolocation(
162
+ this: AndroidDriver,
163
+ ): Promise<void> {
140
164
  if (this.isEmulator()) {
141
165
  throw new Error('Geolocation reset does not work on emulators');
142
166
  }
@@ -146,20 +170,23 @@ export async function mobileResetGeolocation() {
146
170
  // #region Internal helpers
147
171
 
148
172
  /**
149
- * @this {import('../driver').AndroidDriver}
150
- * @param {string} appId
151
- * @returns {Promise<void>}
173
+ * Sets the mock location permission for a specific app.
174
+ *
175
+ * @param appId The application package identifier.
176
+ * @returns Promise that resolves when the mock location permission is set.
152
177
  */
153
- export async function setMockLocationApp(appId) {
178
+ export async function setMockLocationApp(
179
+ this: AndroidDriver,
180
+ appId: string,
181
+ ): Promise<void> {
154
182
  try {
155
183
  await this.adb.shell(['appops', 'set', appId, 'android:mock_location', 'allow']);
156
184
  } catch (err) {
157
- this.log.warn(`Unable to set mock location for app '${appId}': ${err.message}`);
185
+ this.log.warn(`Unable to set mock location for app '${appId}': ${(err as Error).message}`);
158
186
  return;
159
187
  }
160
188
  try {
161
- /** @type {string[]} */
162
- let pkgIds = [];
189
+ let pkgIds: string[] = [];
163
190
  if (await this.adb.fileExists(MOCK_APP_IDS_STORE)) {
164
191
  try {
165
192
  pkgIds = JSON.parse(await this.adb.shell(['cat', MOCK_APP_IDS_STORE]));
@@ -178,18 +205,21 @@ export async function setMockLocationApp(appId) {
178
205
  await fs.rimraf(tmpRoot);
179
206
  }
180
207
  } catch (e) {
181
- this.log.warn(`Unable to persist mock location app id '${appId}': ${e.message}`);
208
+ this.log.warn(`Unable to persist mock location app id '${appId}': ${(e as Error).message}`);
182
209
  }
183
210
  }
184
211
 
185
212
  /**
186
- * @this {import('../driver').AndroidDriver}
187
- * @returns {Promise<void>}
213
+ * Resets the mock location permissions for all apps.
214
+ *
215
+ * @returns Promise that resolves when the mock location permissions are reset.
188
216
  */
189
- async function resetMockLocation() {
217
+ async function resetMockLocation(
218
+ this: AndroidDriver,
219
+ ): Promise<void> {
190
220
  try {
191
221
  const thirdPartyPkgIdsPromise = getThirdPartyPackages.bind(this)();
192
- let pkgIds = [];
222
+ let pkgIds: string[] = [];
193
223
  if (await this.adb.fileExists(MOCK_APP_IDS_STORE)) {
194
224
  try {
195
225
  pkgIds = JSON.parse(await this.adb.shell(['cat', MOCK_APP_IDS_STORE]));
@@ -220,8 +250,9 @@ async function resetMockLocation() {
220
250
  ),
221
251
  );
222
252
  } catch (err) {
223
- this.log.warn(`Unable to reset mock location: ${err.message}`);
253
+ this.log.warn(`Unable to reset mock location: ${(err as Error).message}`);
224
254
  }
225
255
  }
226
256
 
227
257
  // #endregion Internal helpers
258
+