appium-adb 14.0.4 → 14.0.6

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.
@@ -40,7 +40,7 @@ const support_1 = require("@appium/support");
40
40
  const logger_js_1 = require("../logger.js");
41
41
  const asyncbox_1 = require("asyncbox");
42
42
  const node_path_1 = __importDefault(require("node:path"));
43
- /** @type {import('./types').StringRecord<import('./types').InstallState>} */
43
+ // Constants
44
44
  exports.APP_INSTALL_STATE = {
45
45
  UNKNOWN: 'unknown',
46
46
  NOT_INSTALLED: 'notInstalled',
@@ -57,13 +57,13 @@ const MIN_API_LEVEL_WITH_PERMS_SUPPORT = 23;
57
57
  const RESOLVER_ACTIVITY_NAME = 'android/com.android.internal.app.ResolverActivity';
58
58
  const MAIN_ACTION = 'android.intent.action.MAIN';
59
59
  const LAUNCHER_CATEGORY = 'android.intent.category.LAUNCHER';
60
+ // Public methods
60
61
  /**
61
62
  * Verify whether the given argument is a
62
63
  * valid class name.
63
64
  *
64
- * @this {import('../adb.js').ADB}
65
- * @param {string} classString - The actual class name to be verified.
66
- * @return {boolean} The result of Regexp.exec operation
65
+ * @param classString - The actual class name to be verified.
66
+ * @returns The result of Regexp.exec operation
67
67
  * or _null_ if no matches are found.
68
68
  */
69
69
  function isValidClass(classString) {
@@ -75,10 +75,9 @@ function isValidClass(classString) {
75
75
  * given package. It is expected the package is already installed on
76
76
  * the device under test.
77
77
  *
78
- * @this {import('../adb.js').ADB}
79
- * @param {string} pkg - The target package identifier
80
- * @param {import('./types').ResolveActivityOptions} opts
81
- * @return {Promise<string>} Fully qualified name of the launchable activity
78
+ * @param pkg - The target package identifier
79
+ * @param opts - Options for resolving the activity
80
+ * @returns Fully qualified name of the launchable activity
82
81
  * @throws {Error} If there was an error while resolving the activity name
83
82
  */
84
83
  async function resolveLaunchableActivity(pkg, opts = {}) {
@@ -97,10 +96,10 @@ async function resolveLaunchableActivity(pkg, opts = {}) {
97
96
  try {
98
97
  const tmpApp = await this.pullApk(pkg, tmpRoot);
99
98
  const { apkActivity } = await this.packageAndLaunchActivityFromManifest(tmpApp);
100
- return /** @type {string} */ (apkActivity);
99
+ return apkActivity;
101
100
  }
102
101
  catch (e) {
103
- const err = /** @type {Error} */ (e);
102
+ const err = e;
104
103
  logger_js_1.log.debug(err.stack);
105
104
  logger_js_1.log.warn(`Unable to resolve the launchable activity of '${pkg}'. ` +
106
105
  `The very first match of the dumpsys output is going to be used. ` +
@@ -123,30 +122,28 @@ async function resolveLaunchableActivity(pkg, opts = {}) {
123
122
  }
124
123
  /**
125
124
  * Forcefully stops the app and puts it in the "stopped" state.
126
- * Android treats a stopped app as if it was never launched since boot:
125
+ * Android treats a "stopped" app as if it was never launched since boot:
127
126
  * - It cannot receive broadcast intents (except for explicit ones).
128
127
  * - Scheduled jobs, alarms, and services are cancelled.
129
- * - The app wont restart until the user explicitly launches it again.
130
- * Its the same as when a user swipes an app away from Settings → Apps → Force Stop.
128
+ * - The app won't restart until the user explicitly launches it again.
129
+ * It's the same as when a user swipes an app away from Settings → Apps → Force Stop.
131
130
  *
132
- * @this {import('../adb.js').ADB}
133
- * @param {string} pkg - The package name to be stopped.
134
- * @return {Promise<string>} The output of the corresponding adb command.
131
+ * @param pkg - The package name to be stopped.
132
+ * @returns The output of the corresponding adb command.
135
133
  */
136
134
  async function forceStop(pkg) {
137
135
  return await this.shell(['am', 'force-stop', pkg]);
138
136
  }
139
137
  /**
140
- * Gracefully kills the apps process, similar to how Android would do it
138
+ * Gracefully kills the app's process, similar to how Android would do it
141
139
  * automatically when low on memory.
142
- * It only kills the process, without changing the apps stopped state.
140
+ * It only kills the process, without changing the app's "stopped" state.
143
141
  * Background services or broadcast receivers may restart soon after,
144
142
  * if they are still scheduled or registered.
145
143
  * No data or state (like alarms, jobs, etc.) are cleared.
146
144
  *
147
- * @this {import('../adb.js').ADB}
148
- * @param {string} pkg - The package name to be stopped.
149
- * @return {Promise<string>} The output of the corresponding adb command.
145
+ * @param pkg - The package name to be stopped.
146
+ * @returns The output of the corresponding adb command.
150
147
  */
151
148
  async function killPackage(pkg) {
152
149
  return await this.shell(['am', 'kill', pkg]);
@@ -155,9 +152,8 @@ async function killPackage(pkg) {
155
152
  * Clear the user data of the particular application on the device
156
153
  * under test.
157
154
  *
158
- * @this {import('../adb.js').ADB}
159
- * @param {string} pkg - The package name to be cleared.
160
- * @return {Promise<string>} The output of the corresponding adb command.
155
+ * @param pkg - The package name to be cleared.
156
+ * @returns The output of the corresponding adb command.
161
157
  */
162
158
  async function clear(pkg) {
163
159
  return await this.shell(['pm', 'clear', pkg]);
@@ -167,9 +163,8 @@ async function clear(pkg) {
167
163
  * This method is only useful on Android 6.0+ and for applications
168
164
  * that support components-based permissions setting.
169
165
  *
170
- * @this {import('../adb.js').ADB}
171
- * @param {string} pkg - The package name to be processed.
172
- * @param {string} [apk] - The path to the actual apk file.
166
+ * @param pkg - The package name to be processed.
167
+ * @param apk - The path to the actual apk file.
173
168
  * @throws {Error} If there was an error while granting permissions
174
169
  */
175
170
  async function grantAllPermissions(pkg, apk) {
@@ -225,9 +220,8 @@ async function grantAllPermissions(pkg, apk) {
225
220
  * This call is more performant than `grantPermission` one, since it combines
226
221
  * multiple `adb shell` calls into a single command.
227
222
  *
228
- * @this {import('../adb.js').ADB}
229
- * @param {string} pkg - The package name to be processed.
230
- * @param {Array<string>} permissions - The list of permissions to be granted.
223
+ * @param pkg - The package name to be processed.
224
+ * @param permissions - The list of permissions to be granted.
231
225
  * @throws {Error} If there was an error while changing permissions.
232
226
  */
233
227
  async function grantPermissions(pkg, permissions) {
@@ -240,7 +234,7 @@ async function grantPermissions(pkg, permissions) {
240
234
  await this.shellChunks((perm) => ['pm', 'grant', pkg, perm], permissions);
241
235
  }
242
236
  catch (e) {
243
- const err = /** @type {import('teen_process').ExecError} */ (e);
237
+ const err = e;
244
238
  if (!IGNORED_PERM_ERRORS.some((pattern) => pattern.test(err.stderr || err.message))) {
245
239
  throw err;
246
240
  }
@@ -249,9 +243,8 @@ async function grantPermissions(pkg, permissions) {
249
243
  /**
250
244
  * Grant single permission for the particular package.
251
245
  *
252
- * @this {import('../adb.js').ADB}
253
- * @param {string} pkg - The package name to be processed.
254
- * @param {string} permission - The full name of the permission to be granted.
246
+ * @param pkg - The package name to be processed.
247
+ * @param permission - The full name of the permission to be granted.
255
248
  * @throws {Error} If there was an error while changing permissions.
256
249
  */
257
250
  async function grantPermission(pkg, permission) {
@@ -259,7 +252,7 @@ async function grantPermission(pkg, permission) {
259
252
  await this.shell(['pm', 'grant', pkg, permission]);
260
253
  }
261
254
  catch (e) {
262
- const err = /** @type {import('teen_process').ExecError} */ (e);
255
+ const err = e;
263
256
  if (!NOT_CHANGEABLE_PERM_ERROR.test(err.stderr || err.message)) {
264
257
  throw err;
265
258
  }
@@ -268,9 +261,8 @@ async function grantPermission(pkg, permission) {
268
261
  /**
269
262
  * Revoke single permission from the particular package.
270
263
  *
271
- * @this {import('../adb.js').ADB}
272
- * @param {string} pkg - The package name to be processed.
273
- * @param {string} permission - The full name of the permission to be revoked.
264
+ * @param pkg - The package name to be processed.
265
+ * @param permission - The full name of the permission to be revoked.
274
266
  * @throws {Error} If there was an error while changing permissions.
275
267
  */
276
268
  async function revokePermission(pkg, permission) {
@@ -278,7 +270,7 @@ async function revokePermission(pkg, permission) {
278
270
  await this.shell(['pm', 'revoke', pkg, permission]);
279
271
  }
280
272
  catch (e) {
281
- const err = /** @type {import('teen_process').ExecError} */ (e);
273
+ const err = e;
282
274
  if (!NOT_CHANGEABLE_PERM_ERROR.test(err.stderr || err.message)) {
283
275
  throw err;
284
276
  }
@@ -287,11 +279,10 @@ async function revokePermission(pkg, permission) {
287
279
  /**
288
280
  * Retrieve the list of granted permissions for the particular package.
289
281
  *
290
- * @this {import('../adb.js').ADB}
291
- * @param {string} pkg - The package name to be processed.
292
- * @param {string?} [cmdOutput=null] - Optional parameter containing command output of
282
+ * @param pkg - The package name to be processed.
283
+ * @param cmdOutput - Optional parameter containing command output of
293
284
  * _dumpsys package_ command. It may speed up the method execution.
294
- * @return {Promise<string[]>} The list of granted permissions or an empty list.
285
+ * @returns The list of granted permissions or an empty list.
295
286
  * @throws {Error} If there was an error while changing permissions.
296
287
  */
297
288
  async function getGrantedPermissions(pkg, cmdOutput = null) {
@@ -302,11 +293,10 @@ async function getGrantedPermissions(pkg, cmdOutput = null) {
302
293
  /**
303
294
  * Retrieve the list of denied permissions for the particular package.
304
295
  *
305
- * @this {import('../adb.js').ADB}
306
- * @param {string} pkg - The package name to be processed.
307
- * @param {string?} [cmdOutput=null] - Optional parameter containing command output of
296
+ * @param pkg - The package name to be processed.
297
+ * @param cmdOutput - Optional parameter containing command output of
308
298
  * _dumpsys package_ command. It may speed up the method execution.
309
- * @return {Promise<string[]>} The list of denied permissions or an empty list.
299
+ * @returns The list of denied permissions or an empty list.
310
300
  */
311
301
  async function getDeniedPermissions(pkg, cmdOutput = null) {
312
302
  logger_js_1.log.debug('Retrieving denied permissions');
@@ -316,11 +306,10 @@ async function getDeniedPermissions(pkg, cmdOutput = null) {
316
306
  /**
317
307
  * Retrieve the list of requested permissions for the particular package.
318
308
  *
319
- * @this {import('../adb.js').ADB}
320
- * @param {string} pkg - The package name to be processed.
321
- * @param {string?} [cmdOutput=null] - Optional parameter containing command output of
309
+ * @param pkg - The package name to be processed.
310
+ * @param cmdOutput - Optional parameter containing command output of
322
311
  * _dumpsys package_ command. It may speed up the method execution.
323
- * @return {Promise<string[]>} The list of requested permissions or an empty list.
312
+ * @returns The list of requested permissions or an empty list.
324
313
  */
325
314
  async function getReqPermissions(pkg, cmdOutput = null) {
326
315
  logger_js_1.log.debug('Retrieving requested permissions');
@@ -330,8 +319,7 @@ async function getReqPermissions(pkg, cmdOutput = null) {
330
319
  /**
331
320
  * Stop the particular package if it is running and clears its application data.
332
321
  *
333
- * @this {import('../adb.js').ADB}
334
- * @param {string} pkg - The package name to be processed.
322
+ * @param pkg - The package name to be processed.
335
323
  */
336
324
  async function stopAndClear(pkg) {
337
325
  try {
@@ -339,16 +327,15 @@ async function stopAndClear(pkg) {
339
327
  await this.clear(pkg);
340
328
  }
341
329
  catch (e) {
342
- const err = /** @type {Error} */ (e);
330
+ const err = e;
343
331
  throw new Error(`Cannot stop and clear ${pkg}. Original error: ${err.message}`);
344
332
  }
345
333
  }
346
334
  /**
347
335
  * Get the package info from the installed application.
348
336
  *
349
- * @this {import('../adb.js').ADB}
350
- * @param {string} pkg - The name of the installed package.
351
- * @return {Promise<import('./types').AppInfo>} The parsed application information.
337
+ * @param pkg - The name of the installed package.
338
+ * @returns The parsed application information.
352
339
  */
353
340
  async function getPackageInfo(pkg) {
354
341
  logger_js_1.log.debug(`Getting package info for '${pkg}'`);
@@ -358,8 +345,9 @@ async function getPackageInfo(pkg) {
358
345
  stdout = await this.shell(['dumpsys', 'package', pkg]);
359
346
  }
360
347
  catch (err) {
361
- logger_js_1.log.debug(err.stack);
362
- logger_js_1.log.warn(`Got an unexpected error while dumping package info: ${err.message}`);
348
+ const error = err;
349
+ logger_js_1.log.debug(error.stack);
350
+ logger_js_1.log.warn(`Got an unexpected error while dumping package info: ${error.message}`);
363
351
  return result;
364
352
  }
365
353
  const installedPattern = new RegExp(`^\\s*Package\\s+\\[${lodash_1.default.escapeRegExp(pkg)}\\][^:]+:$`, 'm');
@@ -380,10 +368,9 @@ async function getPackageInfo(pkg) {
380
368
  /**
381
369
  * Fetches base.apk of the given package to the local file system
382
370
  *
383
- * @this {import('../adb.js').ADB}
384
- * @param {string} pkg The package identifier (must be already installed on the device)
385
- * @param {string} tmpDir The destination folder path
386
- * @returns {Promise<string>} Full path to the downloaded file
371
+ * @param pkg - The package identifier (must be already installed on the device)
372
+ * @param tmpDir - The destination folder path
373
+ * @returns Full path to the downloaded file
387
374
  * @throws {Error} If there was an error while fetching the .apk
388
375
  */
389
376
  async function pullApk(pkg, tmpDir) {
@@ -403,8 +390,7 @@ async function pullApk(pkg, tmpDir) {
403
390
  * The action literally simulates
404
391
  * clicking the corresponding application icon on the dashboard.
405
392
  *
406
- * @this {import('../adb.js').ADB}
407
- * @param {string} appId - Application package identifier
393
+ * @param appId - Application package identifier
408
394
  * @throws {Error} If the app cannot be activated
409
395
  */
410
396
  async function activateApp(appId) {
@@ -424,7 +410,8 @@ async function activateApp(appId) {
424
410
  logger_js_1.log.debug(`Command stdout: ${output}`);
425
411
  }
426
412
  catch (e) {
427
- throw logger_js_1.log.errorWithException(`Cannot activate '${appId}'. Original error: ${e.message}`);
413
+ const error = e;
414
+ throw logger_js_1.log.errorWithException(`Cannot activate '${appId}'. Original error: ${error.message}`);
428
415
  }
429
416
  if (output.includes('monkey aborted')) {
430
417
  throw logger_js_1.log.errorWithException(`Cannot activate '${appId}'. Are you sure it is installed?`);
@@ -456,15 +443,13 @@ async function activateApp(appId) {
456
443
  /**
457
444
  * Check whether the particular package is present on the device under test.
458
445
  *
459
- * @this {import('../adb.js').ADB}
460
- * @param {string} pkg - The name of the package to check.
461
- * @param {import('./types').IsAppInstalledOptions} [opts={}]
462
- * @return {Promise<boolean>} True if the package is installed.
446
+ * @param pkg - The name of the package to check.
447
+ * @param opts - Options for checking installation
448
+ * @returns True if the package is installed.
463
449
  */
464
450
  async function isAppInstalled(pkg, opts = {}) {
465
451
  const { user, } = opts;
466
452
  logger_js_1.log.debug(`Getting install status for ${pkg}`);
467
- /** @type {boolean} */
468
453
  let isInstalled;
469
454
  if (await this.getApiLevel() < 26) {
470
455
  try {
@@ -485,14 +470,14 @@ async function isAppInstalled(pkg, opts = {}) {
485
470
  if (support_1.util.hasValue(user)) {
486
471
  cmd.push('--user', user);
487
472
  }
488
- /** @type {string} */
489
473
  let stdout;
490
474
  try {
491
475
  stdout = await this.shell(cmd);
492
476
  }
493
477
  catch (e) {
478
+ const error = e;
494
479
  // https://github.com/appium/appium-uiautomator2-driver/issues/810
495
- if (lodash_1.default.includes(e.stderr || e.stdout || e.message, 'access user') && lodash_1.default.isEmpty(user)) {
480
+ if (lodash_1.default.includes(error.stderr || error.stdout || error.message, 'access user') && lodash_1.default.isEmpty(user)) {
496
481
  stdout = await this.shell([...cmd, '--user', '0']);
497
482
  }
498
483
  else {
@@ -507,10 +492,9 @@ async function isAppInstalled(pkg, opts = {}) {
507
492
  /**
508
493
  * Start the particular URI on the device under test.
509
494
  *
510
- * @this {import('../adb.js').ADB}
511
- * @param {string} uri - The name of URI to start.
512
- * @param {string?} [pkg=null] - The name of the package to start the URI with.
513
- * @param {import('./types').StartUriOptions} [opts={}]
495
+ * @param uri - The name of URI to start.
496
+ * @param pkg - The name of the package to start the URI with.
497
+ * @param opts - Options for starting the URI
514
498
  */
515
499
  async function startUri(uri, pkg = null, opts = {}) {
516
500
  const { waitForLaunch = true, } = opts;
@@ -538,51 +522,49 @@ async function startUri(uri, pkg = null, opts = {}) {
538
522
  /**
539
523
  * Start the particular package/activity on the device under test.
540
524
  *
541
- * @this {import('../adb.js').ADB}
542
- * @param {import('./types').StartAppOptions} startAppOptions - Startup options mapping.
543
- * @return {Promise<string>} The output of the corresponding adb command.
525
+ * @param startAppOptions - Startup options mapping.
526
+ * @returns The output of the corresponding adb command.
544
527
  * @throws {Error} If there is an error while executing the activity
545
528
  */
546
529
  async function startApp(startAppOptions) {
547
530
  if (!startAppOptions.pkg || !(startAppOptions.activity || startAppOptions.action)) {
548
531
  throw new Error('pkg, and activity or intent action, are required to start an application');
549
532
  }
550
- startAppOptions = lodash_1.default.clone(startAppOptions);
551
- if (startAppOptions.activity) {
552
- startAppOptions.activity = startAppOptions.activity.replace('$', '\\$');
533
+ const options = lodash_1.default.clone(startAppOptions);
534
+ if (options.activity) {
535
+ options.activity = options.activity.replace('$', '\\$');
553
536
  }
554
537
  // initializing defaults
555
- lodash_1.default.defaults(startAppOptions, {
556
- waitPkg: startAppOptions.pkg,
538
+ lodash_1.default.defaults(options, {
539
+ waitPkg: options.pkg,
557
540
  waitForLaunch: true,
558
541
  waitActivity: false,
559
542
  retry: true,
560
543
  stopApp: true
561
544
  });
562
545
  // preventing null waitpkg
563
- startAppOptions.waitPkg = startAppOptions.waitPkg || startAppOptions.pkg;
546
+ options.waitPkg = options.waitPkg || options.pkg;
564
547
  const apiLevel = await this.getApiLevel();
565
- const cmd = buildStartCmd(startAppOptions, apiLevel);
566
- const intentName = `${startAppOptions.action}${startAppOptions.optionalIntentArguments
567
- ? ' ' + startAppOptions.optionalIntentArguments
548
+ const cmd = buildStartCmd(options, apiLevel);
549
+ const intentName = `${options.action}${options.optionalIntentArguments
550
+ ? ' ' + options.optionalIntentArguments
568
551
  : ''}`;
569
552
  try {
570
553
  const shellOpts = {};
571
- if (lodash_1.default.isInteger(startAppOptions.waitDuration)
572
- // @ts-ignore waitDuration is an integer here
573
- && startAppOptions.waitDuration >= 0) {
574
- shellOpts.timeout = startAppOptions.waitDuration;
554
+ if (options.waitDuration !== undefined && lodash_1.default.isInteger(options.waitDuration)
555
+ && options.waitDuration >= 0) {
556
+ shellOpts.timeout = options.waitDuration;
575
557
  }
576
558
  const stdout = await this.shell(cmd, shellOpts);
577
559
  if (stdout.includes('Error: Activity class') && stdout.includes('does not exist')) {
578
- if (startAppOptions.retry && startAppOptions.activity && !startAppOptions.activity.startsWith('.')) {
560
+ if (options.retry && options.activity && !options.activity.startsWith('.')) {
579
561
  logger_js_1.log.debug(`We tried to start an activity that doesn't exist, ` +
580
- `retrying with '.${startAppOptions.activity}' activity name`);
581
- startAppOptions.activity = `.${startAppOptions.activity}`;
582
- startAppOptions.retry = false;
583
- return await this.startApp(startAppOptions);
562
+ `retrying with '.${options.activity}' activity name`);
563
+ options.activity = `.${options.activity}`;
564
+ options.retry = false;
565
+ return await this.startApp(options);
584
566
  }
585
- throw new Error(`Activity name '${startAppOptions.activity}' used to start the app doesn't ` +
567
+ throw new Error(`Activity name '${options.activity}' used to start the app doesn't ` +
586
568
  `exist or cannot be launched! Make sure it exists and is a launchable activity`);
587
569
  }
588
570
  else if (stdout.includes('Error: Intent does not match any activities')
@@ -592,25 +574,26 @@ async function startApp(startAppOptions) {
592
574
  }
593
575
  else if (stdout.includes('java.lang.SecurityException')) {
594
576
  // if the app is disabled on a real device it will throw a security exception
595
- throw new Error(`The permission to start '${startAppOptions.activity}' activity has been denied.` +
577
+ throw new Error(`The permission to start '${options.activity}' activity has been denied.` +
596
578
  `Make sure the activity/package names are correct.`);
597
579
  }
598
- if (startAppOptions.waitActivity) {
599
- await this.waitForActivity(startAppOptions.waitPkg, startAppOptions.waitActivity, startAppOptions.waitDuration);
580
+ if (options.waitActivity) {
581
+ await this.waitForActivity(options.waitPkg, options.waitActivity, options.waitDuration);
600
582
  }
601
583
  return stdout;
602
584
  }
603
585
  catch (e) {
604
- const appDescriptor = startAppOptions.pkg || intentName;
586
+ const error = e;
587
+ const appDescriptor = options.pkg || intentName;
605
588
  throw new Error(`Cannot start the '${appDescriptor}' application. ` +
606
589
  `Consider checking the driver's troubleshooting documentation. ` +
607
- `Original error: ${e.message}`);
590
+ `Original error: ${error.message}`);
608
591
  }
609
592
  }
610
593
  /**
611
594
  * Helper method to call `adb dumpsys window windows/displays`
612
- * @this {import('../adb.js').ADB}
613
- * @returns {Promise<string>}
595
+ *
596
+ * @returns The output of the dumpsys command
614
597
  */
615
598
  async function dumpWindows() {
616
599
  const apiLevel = await this.getApiLevel();
@@ -622,8 +605,7 @@ async function dumpWindows() {
622
605
  /**
623
606
  * Get the name of currently focused package and activity.
624
607
  *
625
- * @this {import('../adb.js').ADB}
626
- * @return {Promise<import('./types').PackageActivityInfo>}
608
+ * @returns The focused package and activity information
627
609
  * @throws {Error} If there is an error while parsing the data.
628
610
  */
629
611
  async function getFocusedPackageAndActivity() {
@@ -633,18 +615,16 @@ async function getFocusedPackageAndActivity() {
633
615
  stdout = await this.dumpWindows();
634
616
  }
635
617
  catch (e) {
636
- throw new Error(`Could not retrieve the currently focused package and activity. Original error: ${e.message}`);
618
+ const error = e;
619
+ throw new Error(`Could not retrieve the currently focused package and activity. Original error: ${error.message}`);
637
620
  }
638
621
  const nullFocusedAppRe = /^\s*mFocusedApp=null/m;
639
622
  // https://regex101.com/r/xZ8vF7/1
640
623
  const focusedAppRe = new RegExp('^\\s*mFocusedApp.+Record\\{.*\\s([^\\s\\/\\}]+)\\/([^\\s\\/\\}\\,]+)\\,?(\\s[^\\s\\/\\}]+)*\\}', 'mg');
641
624
  const nullCurrentFocusRe = /^\s*mCurrentFocus=null/m;
642
625
  const currentFocusAppRe = new RegExp('^\\s*mCurrentFocus.+\\{.+\\s([^\\s\\/]+)\\/([^\\s]+)\\b', 'mg');
643
- /** @type {import('./types').PackageActivityInfo[]} */
644
626
  const focusedAppCandidates = [];
645
- /** @type {import('./types').PackageActivityInfo[]} */
646
627
  const currentFocusAppCandidates = [];
647
- /** @type {[import('./types').PackageActivityInfo[], RegExp][]} */
648
628
  const pairs = [
649
629
  [focusedAppCandidates, focusedAppRe],
650
630
  [currentFocusAppCandidates, currentFocusAppRe]
@@ -688,24 +668,22 @@ async function getFocusedPackageAndActivity() {
688
668
  /**
689
669
  * Wait for the given activity to be focused/non-focused.
690
670
  *
691
- * @this {import('../adb.js').ADB}
692
- * @param {string} pkg - The name of the package to wait for.
693
- * @param {string} activity - The name of the activity, belonging to that package,
671
+ * @param pkg - The name of the package to wait for.
672
+ * @param activity - The name of the activity, belonging to that package,
694
673
  * to wait for.
695
- * @param {boolean} waitForStop - Whether to wait until the activity is focused (true)
674
+ * @param waitForStop - Whether to wait until the activity is focused (true)
696
675
  * or is not focused (false).
697
- * @param {number} [waitMs=20000] - Number of milliseconds to wait before timeout occurs.
698
- * @throws {error} If timeout happens.
676
+ * @param waitMs - Number of milliseconds to wait before timeout occurs.
677
+ * @throws {Error} If timeout happens.
699
678
  */
700
679
  async function waitForActivityOrNot(pkg, activity, waitForStop, waitMs = 20000) {
701
680
  if (!pkg || !activity) {
702
681
  throw new Error('Package and activity required.');
703
682
  }
704
- const splitNames = (/** @type {string} */ names) => names.split(',').map(lodash_1.default.trim);
683
+ const splitNames = (names) => names.split(',').map(lodash_1.default.trim);
705
684
  const allPackages = splitNames(pkg);
706
685
  const allActivities = splitNames(activity);
707
- const toFullyQualifiedActivityName = (/** @type {string} */ prefix, /** @type {string} */ suffix) => `${prefix}${suffix}`.replace(/\/\.?/g, '.').replace(/\.{2,}/g, '.');
708
- /** @type {Set<string>} */
686
+ const toFullyQualifiedActivityName = (prefix, suffix) => `${prefix}${suffix}`.replace(/\/\.?/g, '.').replace(/\.{2,}/g, '.');
709
687
  const possibleActivityNamesSet = new Set();
710
688
  for (const oneActivity of allActivities) {
711
689
  if (oneActivity.startsWith('.')) {
@@ -741,7 +719,8 @@ async function waitForActivityOrNot(pkg, activity, waitForStop, waitMs = 20000)
741
719
  ({ appPackage, appActivity } = await this.getFocusedPackageAndActivity());
742
720
  }
743
721
  catch (e) {
744
- logger_js_1.log.debug(e.message);
722
+ const error = e;
723
+ logger_js_1.log.debug(error.message);
745
724
  return false;
746
725
  }
747
726
  if (appActivity && appPackage) {
@@ -772,12 +751,11 @@ async function waitForActivityOrNot(pkg, activity, waitForStop, waitMs = 20000)
772
751
  /**
773
752
  * Wait for the given activity to be focused
774
753
  *
775
- * @this {import('../adb.js').ADB}
776
- * @param {string} pkg - The name of the package to wait for.
777
- * @param {string} act - The name of the activity, belonging to that package,
754
+ * @param pkg - The name of the package to wait for.
755
+ * @param act - The name of the activity, belonging to that package,
778
756
  * to wait for.
779
- * @param {number} [waitMs=20000] - Number of milliseconds to wait before timeout occurs.
780
- * @throws {error} If timeout happens.
757
+ * @param waitMs - Number of milliseconds to wait before timeout occurs.
758
+ * @throws {Error} If timeout happens.
781
759
  */
782
760
  async function waitForActivity(pkg, act, waitMs = 20000) {
783
761
  await this.waitForActivityOrNot(pkg, act, false, waitMs);
@@ -785,24 +763,22 @@ async function waitForActivity(pkg, act, waitMs = 20000) {
785
763
  /**
786
764
  * Wait for the given activity to be non-focused.
787
765
  *
788
- * @this {import('../adb.js').ADB}
789
- * @param {string} pkg - The name of the package to wait for.
790
- * @param {string} act - The name of the activity, belonging to that package,
766
+ * @param pkg - The name of the package to wait for.
767
+ * @param act - The name of the activity, belonging to that package,
791
768
  * to wait for.
792
- * @param {number} [waitMs=20000] - Number of milliseconds to wait before timeout occurs.
793
- * @throws {error} If timeout happens.
769
+ * @param waitMs - Number of milliseconds to wait before timeout occurs.
770
+ * @throws {Error} If timeout happens.
794
771
  */
795
772
  async function waitForNotActivity(pkg, act, waitMs = 20000) {
796
773
  await this.waitForActivityOrNot(pkg, act, true, waitMs);
797
774
  }
798
- // #region Private functions
799
775
  /**
800
776
  * Builds command line representation for the given
801
777
  * application startup options
802
778
  *
803
- * @param {StartCmdOptions} startAppOptions - Application options mapping
804
- * @param {number} apiLevel - The actual OS API level
805
- * @returns {string[]} The actual command line array
779
+ * @param startAppOptions - Application options mapping
780
+ * @param apiLevel - The actual OS API level
781
+ * @returns The actual command line array
806
782
  */
807
783
  function buildStartCmd(startAppOptions, apiLevel) {
808
784
  const { user, waitForLaunch, pkg, activity, action, category, stopApp, flags, optionalIntentArguments, } = startAppOptions;
@@ -833,66 +809,12 @@ function buildStartCmd(startAppOptions, apiLevel) {
833
809
  }
834
810
  return cmd;
835
811
  }
836
- /**
837
- *
838
- * @param {string} value expect optionalIntentArguments to be a single string of the form:
839
- * "-flag key"
840
- * "-flag key value"
841
- * or a combination of these (e.g., "-flag1 key1 -flag2 key2 value2")
842
- * @returns {string[]}
843
- */
844
- function parseOptionalIntentArguments(value) {
845
- // take a string and parse out the part before any spaces, and anything after
846
- // the first space
847
- /** @type {(str: string) => string[]} */
848
- const parseKeyValue = (str) => {
849
- str = str.trim();
850
- const spacePos = str.indexOf(' ');
851
- if (spacePos < 0) {
852
- return str.length ? [str] : [];
853
- }
854
- else {
855
- return [str.substring(0, spacePos).trim(), str.substring(spacePos + 1).trim()];
856
- }
857
- };
858
- // cycle through the optionalIntentArguments and pull out the arguments
859
- // add a space initially so flags can be distinguished from arguments that
860
- // have internal hyphens
861
- let optionalIntentArguments = ` ${value}`;
862
- const re = / (-[^\s]+) (.+)/;
863
- /** @type {string[]} */
864
- const result = [];
865
- while (true) {
866
- const args = re.exec(optionalIntentArguments);
867
- if (!args) {
868
- if (optionalIntentArguments.length) {
869
- // no more flags, so the remainder can be treated as 'key' or 'key value'
870
- result.push(...parseKeyValue(optionalIntentArguments));
871
- }
872
- // we are done
873
- return result;
874
- }
875
- // take the flag and see if it is at the beginning of the string
876
- // if it is not, then it means we have been through already, and
877
- // what is before the flag is the argument for the previous flag
878
- const flag = args[1];
879
- const flagPos = optionalIntentArguments.indexOf(flag);
880
- if (flagPos !== 0) {
881
- const prevArgs = optionalIntentArguments.substring(0, flagPos);
882
- result.push(...parseKeyValue(prevArgs));
883
- }
884
- // add the flag, as there are no more earlier arguments
885
- result.push(flag);
886
- // make optionalIntentArguments hold the remainder
887
- optionalIntentArguments = args[2];
888
- }
889
- }
890
812
  /**
891
813
  * Parses the name of launchable package activity
892
814
  * from dumpsys output.
893
815
  *
894
- * @param {string} dumpsys the actual dumpsys output
895
- * @returns {string[]} Either the fully qualified
816
+ * @param dumpsys - The actual dumpsys output
817
+ * @returns Either the fully qualified
896
818
  * activity name as a single list item or an empty list if nothing could be parsed.
897
819
  * In Android 6 and older there is no reliable way to determine
898
820
  * the category name for the given activity, so this API just
@@ -968,39 +890,22 @@ function parseLaunchableActivityNames(dumpsys) {
968
890
  /**
969
891
  * Check if the given string is a valid component name
970
892
  *
971
- * @param {string} classString The string to verify
972
- * @return {RegExpExecArray?} The result of Regexp.exec operation
893
+ * @param classString - The string to verify
894
+ * @returns The result of Regexp.exec operation
973
895
  * or _null_ if no matches are found
974
896
  */
975
897
  function matchComponentName(classString) {
976
898
  // some.package/some.package.Activity
977
899
  return /^[\p{L}0-9./_]+$/u.exec(classString);
978
900
  }
979
- /**
980
- * Escapes special characters in command line arguments.
981
- * This is needed to avoid possible issues with how system `spawn`
982
- * call handles them.
983
- * See https://discuss.appium.io/t/how-to-modify-wd-proxy-and-uiautomator2-source-code-to-support-unicode/33466
984
- * for more details.
985
- *
986
- * @param {string} arg Non-escaped argument string
987
- * @returns The escaped argument
988
- */
989
- function escapeShellArg(arg) {
990
- arg = `${arg}`;
991
- if (support_1.system.isWindows()) {
992
- return /[&|^\s]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg;
993
- }
994
- return arg.replace(/&/g, '\\&');
995
- }
996
901
  /**
997
902
  * Retrieves the list of permission names encoded in `dumpsys package` command output.
998
903
  *
999
- * @param {string} dumpsysOutput - The actual command output.
1000
- * @param {string[]} groupNames - The list of group names to list permissions for.
1001
- * @param {boolean?} [grantedState=null] - The expected state of `granted` attribute to filter with.
904
+ * @param dumpsysOutput - The actual command output.
905
+ * @param groupNames - The list of group names to list permissions for.
906
+ * @param grantedState - The expected state of `granted` attribute to filter with.
1002
907
  * No filtering is done if the parameter is not set.
1003
- * @returns {string[]} The list of matched permission names or an empty list if no matches were found.
908
+ * @returns The list of matched permission names or an empty list if no matches were found.
1004
909
  */
1005
910
  function extractMatchingPermissions(dumpsysOutput, groupNames, grantedState = null) {
1006
911
  const groupPatternByName = (groupName) => new RegExp(`^(\\s*${lodash_1.default.escapeRegExp(groupName)} permissions:[\\s\\S]+)`, 'm');
@@ -1047,9 +952,8 @@ function extractMatchingPermissions(dumpsysOutput, groupNames, grantedState = nu
1047
952
  /**
1048
953
  * Broadcast a message to the given intent.
1049
954
  *
1050
- * @this {import('../adb.js').ADB}
1051
- * @param {string} intent - The name of the intent to broadcast to.
1052
- * @throws {error} If intent name is not a valid class name.
955
+ * @param intent - The name of the intent to broadcast to.
956
+ * @throws {Error} If intent name is not a valid class name.
1053
957
  */
1054
958
  async function broadcast(intent) {
1055
959
  if (!this.isValidClass(intent)) {
@@ -1061,9 +965,8 @@ async function broadcast(intent) {
1061
965
  /**
1062
966
  * Get the list of process ids for the particular package on the device under test.
1063
967
  *
1064
- * @this {import('../adb.js').ADB}
1065
- * @param {string} pkg
1066
- * @returns {Promise<number[]>} The list of matched process IDs or an empty list.
968
+ * @param pkg - The package name
969
+ * @returns The list of matched process IDs or an empty list.
1067
970
  */
1068
971
  async function listAppProcessIds(pkg) {
1069
972
  logger_js_1.log.debug(`Getting IDs of all '${pkg}' package`);
@@ -1079,24 +982,81 @@ async function listAppProcessIds(pkg) {
1079
982
  * Check whether the process with the particular name is running on the device
1080
983
  * under test.
1081
984
  *
1082
- * @this {import('../adb.js').ADB}
1083
- * @param {string} pkg - The id of the package to be checked.
985
+ * @param pkg - The id of the package to be checked.
1084
986
  * @returns True if the given package is running.
1085
987
  */
1086
988
  async function isAppRunning(pkg) {
1087
989
  return !lodash_1.default.isEmpty(await this.listAppProcessIds(pkg));
1088
990
  }
991
+ // Private methods
1089
992
  /**
1090
- * @typedef {Object} StartCmdOptions
1091
- * @property {number|string} [user]
1092
- * @property {boolean} [waitForLaunch]
1093
- * @property {string} [pkg]
1094
- * @property {string} [activity]
1095
- * @property {string} [action]
1096
- * @property {string} [category]
1097
- * @property {boolean} [stopApp]
1098
- * @property {string} [flags]
1099
- * @property {string} [optionalIntentArguments]
993
+ * Parses optional intent arguments from a string.
994
+ *
995
+ * @param value - Expect optionalIntentArguments to be a single string of the form:
996
+ * "-flag key"
997
+ * "-flag key value"
998
+ * or a combination of these (e.g., "-flag1 key1 -flag2 key2 value2")
999
+ * @returns Parsed arguments array
1100
1000
  */
1101
- // #endregion
1001
+ function parseOptionalIntentArguments(value) {
1002
+ // take a string and parse out the part before any spaces, and anything after
1003
+ // the first space
1004
+ const parseKeyValue = (str) => {
1005
+ str = str.trim();
1006
+ const spacePos = str.indexOf(' ');
1007
+ if (spacePos < 0) {
1008
+ return str.length ? [str] : [];
1009
+ }
1010
+ else {
1011
+ return [str.substring(0, spacePos).trim(), str.substring(spacePos + 1).trim()];
1012
+ }
1013
+ };
1014
+ // cycle through the optionalIntentArguments and pull out the arguments
1015
+ // add a space initially so flags can be distinguished from arguments that
1016
+ // have internal hyphens
1017
+ let optionalIntentArguments = ` ${value}`;
1018
+ const re = / (-[^\s]+) (.+)/;
1019
+ const result = [];
1020
+ while (true) {
1021
+ const args = re.exec(optionalIntentArguments);
1022
+ if (!args) {
1023
+ if (optionalIntentArguments.length) {
1024
+ // no more flags, so the remainder can be treated as 'key' or 'key value'
1025
+ result.push(...parseKeyValue(optionalIntentArguments));
1026
+ }
1027
+ // we are done
1028
+ return result;
1029
+ }
1030
+ // take the flag and see if it is at the beginning of the string
1031
+ // if it is not, then it means we have been through already, and
1032
+ // what is before the flag is the argument for the previous flag
1033
+ const flag = args[1];
1034
+ const flagPos = optionalIntentArguments.indexOf(flag);
1035
+ if (flagPos !== 0) {
1036
+ const prevArgs = optionalIntentArguments.substring(0, flagPos);
1037
+ result.push(...parseKeyValue(prevArgs));
1038
+ }
1039
+ // add the flag, as there are no more earlier arguments
1040
+ result.push(flag);
1041
+ // make optionalIntentArguments hold the remainder
1042
+ optionalIntentArguments = args[2];
1043
+ }
1044
+ }
1045
+ /**
1046
+ * Escapes special characters in command line arguments.
1047
+ * This is needed to avoid possible issues with how system `spawn`
1048
+ * call handles them.
1049
+ * See https://discuss.appium.io/t/how-to-modify-wd-proxy-and-uiautomator2-source-code-to-support-unicode/33466
1050
+ * for more details.
1051
+ *
1052
+ * @param arg - Non-escaped argument string
1053
+ * @returns The escaped argument
1054
+ */
1055
+ function escapeShellArg(arg) {
1056
+ arg = `${arg}`;
1057
+ if (support_1.system.isWindows()) {
1058
+ return /[&|^\s]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg;
1059
+ }
1060
+ return arg.replace(/&/g, '\\&');
1061
+ }
1102
1062
  //# sourceMappingURL=app-commands.js.map