appium-android-driver 5.14.7 → 6.0.0

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 (192) hide show
  1. package/build/index.d.ts +282 -0
  2. package/build/index.d.ts.map +1 -0
  3. package/build/index.js.map +1 -0
  4. package/build/lib/commands/actions.d.ts +6 -224
  5. package/build/lib/commands/actions.d.ts.map +1 -1
  6. package/build/lib/commands/actions.js +306 -405
  7. package/build/lib/commands/actions.js.map +1 -1
  8. package/build/lib/commands/alert.d.ts +7 -9
  9. package/build/lib/commands/alert.d.ts.map +1 -1
  10. package/build/lib/commands/alert.js +24 -18
  11. package/build/lib/commands/alert.js.map +1 -1
  12. package/build/lib/commands/app-management.d.ts +7 -313
  13. package/build/lib/commands/app-management.d.ts.map +1 -1
  14. package/build/lib/commands/app-management.js +135 -293
  15. package/build/lib/commands/app-management.js.map +1 -1
  16. package/build/lib/commands/context.d.ts +8 -92
  17. package/build/lib/commands/context.d.ts.map +1 -1
  18. package/build/lib/commands/context.js +381 -439
  19. package/build/lib/commands/context.js.map +1 -1
  20. package/build/lib/commands/element.d.ts +8 -35
  21. package/build/lib/commands/element.d.ts.map +1 -1
  22. package/build/lib/commands/element.js +153 -136
  23. package/build/lib/commands/element.js.map +1 -1
  24. package/build/lib/commands/emu-console.d.ts +6 -48
  25. package/build/lib/commands/emu-console.d.ts.map +1 -1
  26. package/build/lib/commands/emu-console.js +19 -34
  27. package/build/lib/commands/emu-console.js.map +1 -1
  28. package/build/lib/commands/execute.d.ts +6 -5
  29. package/build/lib/commands/execute.d.ts.map +1 -1
  30. package/build/lib/commands/execute.js +77 -66
  31. package/build/lib/commands/execute.js.map +1 -1
  32. package/build/lib/commands/file-actions.d.ts +7 -128
  33. package/build/lib/commands/file-actions.d.ts.map +1 -1
  34. package/build/lib/commands/file-actions.js +183 -219
  35. package/build/lib/commands/file-actions.js.map +1 -1
  36. package/build/lib/commands/find.d.ts +8 -12
  37. package/build/lib/commands/find.d.ts.map +1 -1
  38. package/build/lib/commands/find.js +19 -23
  39. package/build/lib/commands/find.js.map +1 -1
  40. package/build/lib/commands/general.d.ts +9 -132
  41. package/build/lib/commands/general.d.ts.map +1 -1
  42. package/build/lib/commands/general.js +281 -312
  43. package/build/lib/commands/general.js.map +1 -1
  44. package/build/lib/commands/ime.d.ts +7 -10
  45. package/build/lib/commands/ime.d.ts.map +1 -1
  46. package/build/lib/commands/ime.js +47 -35
  47. package/build/lib/commands/ime.js.map +1 -1
  48. package/build/lib/commands/index.d.ts +27 -2
  49. package/build/lib/commands/index.d.ts.map +1 -1
  50. package/build/lib/commands/index.js +41 -19
  51. package/build/lib/commands/index.js.map +1 -1
  52. package/build/lib/commands/intent.d.ts +7 -417
  53. package/build/lib/commands/intent.d.ts.map +1 -1
  54. package/build/lib/commands/intent.js +104 -216
  55. package/build/lib/commands/intent.js.map +1 -1
  56. package/build/lib/commands/keyboard.d.ts +6 -5
  57. package/build/lib/commands/keyboard.d.ts.map +1 -1
  58. package/build/lib/commands/keyboard.js +16 -8
  59. package/build/lib/commands/keyboard.js.map +1 -1
  60. package/build/lib/commands/log.d.ts +7 -44
  61. package/build/lib/commands/log.d.ts.map +1 -1
  62. package/build/lib/commands/log.js +146 -108
  63. package/build/lib/commands/log.js.map +1 -1
  64. package/build/lib/commands/media-projection.d.ts +7 -143
  65. package/build/lib/commands/media-projection.d.ts.map +1 -1
  66. package/build/lib/commands/media-projection.js +113 -140
  67. package/build/lib/commands/media-projection.js.map +1 -1
  68. package/build/lib/commands/mixins.d.ts +740 -0
  69. package/build/lib/commands/mixins.d.ts.map +1 -0
  70. package/build/lib/commands/mixins.js +19 -0
  71. package/build/lib/commands/mixins.js.map +1 -0
  72. package/build/lib/commands/network.d.ts +7 -138
  73. package/build/lib/commands/network.d.ts.map +1 -1
  74. package/build/lib/commands/network.js +212 -254
  75. package/build/lib/commands/network.js.map +1 -1
  76. package/build/lib/commands/performance.d.ts +24 -70
  77. package/build/lib/commands/performance.d.ts.map +1 -1
  78. package/build/lib/commands/performance.js +144 -100
  79. package/build/lib/commands/performance.js.map +1 -1
  80. package/build/lib/commands/permissions.d.ts +8 -92
  81. package/build/lib/commands/permissions.d.ts.map +1 -1
  82. package/build/lib/commands/permissions.js +75 -87
  83. package/build/lib/commands/permissions.js.map +1 -1
  84. package/build/lib/commands/recordscreen.d.ts +7 -193
  85. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  86. package/build/lib/commands/recordscreen.js +151 -182
  87. package/build/lib/commands/recordscreen.js.map +1 -1
  88. package/build/lib/commands/shell.d.ts +7 -7
  89. package/build/lib/commands/shell.d.ts.map +1 -1
  90. package/build/lib/commands/shell.js +40 -33
  91. package/build/lib/commands/shell.js.map +1 -1
  92. package/build/lib/commands/streamscreen.d.ts +9 -103
  93. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  94. package/build/lib/commands/streamscreen.js +261 -218
  95. package/build/lib/commands/streamscreen.js.map +1 -1
  96. package/build/lib/commands/system-bars.d.ts +22 -90
  97. package/build/lib/commands/system-bars.d.ts.map +1 -1
  98. package/build/lib/commands/system-bars.js +76 -74
  99. package/build/lib/commands/system-bars.js.map +1 -1
  100. package/build/lib/commands/touch.d.ts +10 -29
  101. package/build/lib/commands/touch.d.ts.map +1 -1
  102. package/build/lib/commands/touch.js +301 -285
  103. package/build/lib/commands/touch.js.map +1 -1
  104. package/build/lib/commands/types.d.ts +978 -0
  105. package/build/lib/commands/types.d.ts.map +1 -0
  106. package/build/lib/commands/types.js +3 -0
  107. package/build/lib/commands/types.js.map +1 -0
  108. package/build/lib/constraints.d.ts +291 -0
  109. package/build/lib/constraints.d.ts.map +1 -0
  110. package/build/lib/constraints.js +300 -0
  111. package/build/lib/constraints.js.map +1 -0
  112. package/build/lib/driver.d.ts +68 -37
  113. package/build/lib/driver.d.ts.map +1 -1
  114. package/build/lib/driver.js +123 -80
  115. package/build/lib/driver.js.map +1 -1
  116. package/build/lib/helpers/android.d.ts +164 -0
  117. package/build/lib/helpers/android.d.ts.map +1 -0
  118. package/build/lib/helpers/android.js +819 -0
  119. package/build/lib/helpers/android.js.map +1 -0
  120. package/build/lib/helpers/index.d.ts +7 -0
  121. package/build/lib/helpers/index.d.ts.map +1 -0
  122. package/build/lib/helpers/index.js +29 -0
  123. package/build/lib/helpers/index.js.map +1 -0
  124. package/build/lib/helpers/types.d.ts +121 -0
  125. package/build/lib/helpers/types.d.ts.map +1 -0
  126. package/build/lib/helpers/types.js +3 -0
  127. package/build/lib/helpers/types.js.map +1 -0
  128. package/build/lib/helpers/unlock.d.ts +32 -0
  129. package/build/lib/helpers/unlock.d.ts.map +1 -0
  130. package/build/lib/helpers/unlock.js +273 -0
  131. package/build/lib/helpers/unlock.js.map +1 -0
  132. package/build/lib/helpers/webview.d.ts +74 -0
  133. package/build/lib/helpers/webview.d.ts.map +1 -0
  134. package/build/lib/helpers/webview.js +421 -0
  135. package/build/lib/helpers/webview.js.map +1 -0
  136. package/build/lib/index.d.ts +9 -0
  137. package/build/lib/index.d.ts.map +1 -0
  138. package/build/lib/index.js +37 -0
  139. package/build/lib/index.js.map +1 -0
  140. package/build/lib/method-map.d.ts +0 -8
  141. package/build/lib/method-map.d.ts.map +1 -1
  142. package/build/lib/method-map.js +63 -74
  143. package/build/lib/method-map.js.map +1 -1
  144. package/build/lib/stubs.d.ts +0 -1
  145. package/build/lib/stubs.d.ts.map +1 -1
  146. package/build/lib/stubs.js +1 -0
  147. package/build/lib/stubs.js.map +1 -1
  148. package/build/lib/utils.d.ts +1 -1
  149. package/build/lib/utils.d.ts.map +1 -1
  150. package/lib/commands/actions.js +351 -464
  151. package/lib/commands/alert.js +27 -17
  152. package/lib/commands/app-management.js +156 -314
  153. package/lib/commands/context.js +457 -441
  154. package/lib/commands/element.js +201 -157
  155. package/lib/commands/emu-console.js +25 -45
  156. package/lib/commands/execute.js +106 -90
  157. package/lib/commands/file-actions.js +222 -240
  158. package/lib/commands/find.ts +103 -0
  159. package/lib/commands/general.js +327 -339
  160. package/lib/commands/ime.js +50 -34
  161. package/lib/commands/{index.js → index.ts} +20 -24
  162. package/lib/commands/intent.js +108 -249
  163. package/lib/commands/keyboard.js +20 -8
  164. package/lib/commands/log.js +172 -116
  165. package/lib/commands/media-projection.js +134 -161
  166. package/lib/commands/mixins.ts +966 -0
  167. package/lib/commands/network.js +252 -281
  168. package/lib/commands/performance.js +203 -132
  169. package/lib/commands/permissions.js +108 -109
  170. package/lib/commands/recordscreen.js +212 -209
  171. package/lib/commands/shell.js +51 -40
  172. package/lib/commands/streamscreen.js +355 -289
  173. package/lib/commands/system-bars.js +92 -83
  174. package/lib/commands/touch.js +357 -294
  175. package/lib/commands/types.ts +1097 -0
  176. package/lib/{desired-caps.js → constraints.ts} +106 -103
  177. package/lib/{driver.js → driver.ts} +278 -132
  178. package/lib/helpers/android.ts +1143 -0
  179. package/lib/helpers/index.ts +6 -0
  180. package/lib/helpers/types.ts +134 -0
  181. package/lib/helpers/unlock.ts +329 -0
  182. package/lib/helpers/webview.ts +582 -0
  183. package/lib/index.ts +18 -0
  184. package/lib/method-map.js +87 -98
  185. package/lib/stubs.ts +0 -1
  186. package/package.json +27 -20
  187. package/index.js +0 -24
  188. package/lib/android-helpers.js +0 -983
  189. package/lib/commands/coverage.js +0 -18
  190. package/lib/commands/find.js +0 -82
  191. package/lib/unlock-helpers.js +0 -278
  192. package/lib/webview-helpers.js +0 -602
@@ -1,361 +1,349 @@
1
+ // @ts-check
2
+ import {util} from '@appium/support';
3
+ import {longSleep} from 'asyncbox';
1
4
  import _ from 'lodash';
2
- import androidHelpers from '../android-helpers';
3
- import { util } from '@appium/support';
4
5
  import moment from 'moment';
5
- import { longSleep } from 'asyncbox';
6
- import { errors } from 'appium/driver';
6
+ import androidHelpers from '../helpers/android';
7
+ import {requireArgs} from '../utils';
8
+ import {mixin} from './mixins';
7
9
 
8
10
  const MOMENT_FORMAT_ISO8601 = 'YYYY-MM-DDTHH:mm:ssZ';
9
11
 
10
- let commands = {}, helpers = {}, extensions = {};
11
-
12
- commands.keys = async function keys (keys) {
13
- // Protocol sends an array; rethink approach
14
- keys = _.isArray(keys) ? keys.join('') : keys;
15
- let params = {
16
- text: keys,
17
- replace: false
18
- };
19
- if (this.opts.unicodeKeyboard) {
20
- params.unicodeKeyboard = true;
21
- }
22
- await this.doSendKeys(params);
23
- };
24
-
25
- commands.doSendKeys = async function doSendKeys (params) {
26
- return await this.bootstrap.sendAction('setText', params);
27
- };
28
-
29
- /**
30
- * Retrieves the current device's timestamp.
31
- *
32
- * @param {string} format - The set of format specifiers. Read
33
- * https://momentjs.com/docs/ to get the full list of supported
34
- * datetime format specifiers. The default format is
35
- * `YYYY-MM-DDTHH:mm:ssZ`, which complies to ISO-8601
36
- * @return {string} Formatted datetime string or the raw command output if formatting fails
37
- */
38
- commands.getDeviceTime = async function getDeviceTime (format = MOMENT_FORMAT_ISO8601) {
39
- this.log.debug('Attempting to capture android device date and time. ' +
40
- `The format specifier is '${format}'`);
41
- const deviceTimestamp = (await this.adb.shell(['date', '+%Y-%m-%dT%T%z'])).trim();
42
- this.log.debug(`Got device timestamp: ${deviceTimestamp}`);
43
- const parsedTimestamp = moment.utc(deviceTimestamp, 'YYYY-MM-DDTHH:mm:ssZZ');
44
- if (!parsedTimestamp.isValid()) {
45
- this.log.warn('Cannot parse the returned timestamp. Returning as is');
46
- return deviceTimestamp;
47
- }
48
- return parsedTimestamp.utcOffset(parsedTimestamp._tzm || 0).format(format);
49
- };
50
-
51
- /**
52
- * @typedef {Object} DeviceTimeOptions
53
- * @property {string} format [YYYY-MM-DDTHH:mm:ssZ] - See getDeviceTime#format
54
- */
55
-
56
12
  /**
57
- * Retrieves the current device time
58
- *
59
- * @param {DeviceTimeOptions} opts
60
- * @return {string} Formatted datetime string or the raw command output if formatting fails
13
+ * @type {import('./mixins').GeneralMixin & ThisType<import('../driver').AndroidDriver>}
14
+ * @satisfies {import('@appium/types').ExternalDriver}
61
15
  */
62
- commands.mobileGetDeviceTime = async function mobileGetDeviceTime (opts = {}) {
63
- return await this.getDeviceTime(opts.format);
64
- };
65
-
66
- commands.getPageSource = async function getPageSource () {
67
- return await this.bootstrap.sendAction('source');
68
- };
69
-
70
- commands.back = async function back () {
71
- return await this.bootstrap.sendAction('pressBack');
72
- };
73
-
74
- commands.openSettingsActivity = async function openSettingsActivity (setting) {
75
- let {appPackage, appActivity} = await this.adb.getFocusedPackageAndActivity();
76
- await this.adb.shell(['am', 'start', '-a', `android.settings.${setting}`]);
77
- await this.adb.waitForNotActivity(appPackage, appActivity, 5000);
78
- };
79
-
80
- commands.getWindowSize = async function getWindowSize () {
81
- return await this.bootstrap.sendAction('getDeviceSize');
82
- };
83
-
84
- // For W3C
85
- commands.getWindowRect = async function getWindowRect () {
86
- const { width, height } = await this.getWindowSize();
87
- return {
88
- width,
89
- height,
90
- x: 0,
91
- y: 0
92
- };
93
- };
94
-
95
- commands.getCurrentActivity = async function getCurrentActivity () {
96
- return (await this.adb.getFocusedPackageAndActivity()).appActivity;
97
- };
98
-
99
- commands.getCurrentPackage = async function getCurrentPackage () {
100
- return (await this.adb.getFocusedPackageAndActivity()).appPackage;
101
- };
102
-
103
- commands.background = async function background (seconds) {
104
- if (seconds < 0) {
105
- // if user passes in a negative seconds value, interpret that as the instruction
106
- // to not bring the app back at all
107
- await this.adb.goToHome();
108
- return true;
109
- }
110
- let {appPackage, appActivity} = await this.adb.getFocusedPackageAndActivity();
111
- await this.adb.goToHome();
112
-
113
- // people can wait for a long time, so to be safe let's use the longSleep function and log
114
- // progress periodically.
115
- const sleepMs = seconds * 1000;
116
- const thresholdMs = 30 * 1000; // use the spin-wait for anything over this threshold
117
- // for our spin interval, use 1% of the total wait time, but nothing bigger than 30s
118
- const intervalMs = _.min([30 * 1000, parseInt(sleepMs / 100, 10)]);
119
- const progressCb = ({elapsedMs, progress}) => {
120
- const waitSecs = (elapsedMs / 1000).toFixed(0);
121
- const progressPct = (progress * 100).toFixed(2);
122
- this.log.debug(`Waited ${waitSecs}s so far (${progressPct}%)`);
123
- };
124
- await longSleep(sleepMs, {thresholdMs, intervalMs, progressCb});
125
-
126
- let args;
127
- if (this._cachedActivityArgs && this._cachedActivityArgs[`${appPackage}/${appActivity}`]) {
128
- // the activity was started with `startActivity`, so use those args to restart
129
- args = this._cachedActivityArgs[`${appPackage}/${appActivity}`];
130
- } else {
131
- try {
132
- this.log.debug(`Activating app '${appPackage}' in order to restore it`);
133
- await this.activateApp(appPackage);
16
+ const GeneralMixin = {
17
+ _cachedActivityArgs: {},
18
+ async keys(keys) {
19
+ // Protocol sends an array; rethink approach
20
+ keys = _.isArray(keys) ? keys.join('') : keys;
21
+ /**
22
+ * @type {import('./types').SendKeysOpts}
23
+ */
24
+ const params = {
25
+ text: keys,
26
+ replace: false,
27
+ };
28
+ if (this.opts.unicodeKeyboard) {
29
+ params.unicodeKeyboard = true;
30
+ }
31
+ await this.doSendKeys(params);
32
+ },
33
+
34
+ async doSendKeys(params) {
35
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('setText', params);
36
+ },
37
+
38
+ async getDeviceTime(format = MOMENT_FORMAT_ISO8601) {
39
+ this.log.debug(
40
+ 'Attempting to capture android device date and time. ' + `The format specifier is '${format}'`
41
+ );
42
+ const deviceTimestamp = (
43
+ await /** @type {ADB} */ (this.adb).shell(['date', '+%Y-%m-%dT%T%z'])
44
+ ).trim();
45
+ this.log.debug(`Got device timestamp: ${deviceTimestamp}`);
46
+ const parsedTimestamp = moment.utc(deviceTimestamp, 'YYYY-MM-DDTHH:mm:ssZZ');
47
+ if (!parsedTimestamp.isValid()) {
48
+ this.log.warn('Cannot parse the returned timestamp. Returning as is');
49
+ return deviceTimestamp;
50
+ }
51
+ // @ts-expect-error private API
52
+ return parsedTimestamp.utcOffset(parsedTimestamp._tzm || 0).format(format);
53
+ },
54
+
55
+ async mobileGetDeviceTime(opts = {}) {
56
+ return await this.getDeviceTime(opts.format);
57
+ },
58
+
59
+ async getPageSource() {
60
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('source');
61
+ },
62
+
63
+ async back() {
64
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('pressBack');
65
+ },
66
+
67
+ async openSettingsActivity(setting) {
68
+ const adb = /** @type {ADB} */ (this.adb);
69
+ let {appPackage, appActivity} = await adb.getFocusedPackageAndActivity();
70
+ await adb.shell(['am', 'start', '-a', `android.settings.${setting}`]);
71
+ await adb.waitForNotActivity(/** @type {string} */ (appPackage), appActivity, 5000);
72
+ },
73
+
74
+ async getWindowSize() {
75
+ return await /** @type {AndroidBootstrap} */ (this.bootstrap).sendAction('getDeviceSize');
76
+ },
77
+
78
+ // For W3C
79
+ async getWindowRect() {
80
+ const {width, height} = await this.getWindowSize();
81
+ return {
82
+ width,
83
+ height,
84
+ x: 0,
85
+ y: 0,
86
+ };
87
+ },
88
+
89
+ async getCurrentActivity() {
90
+ return (await /** @type {ADB} */ (this.adb).getFocusedPackageAndActivity()).appActivity;
91
+ },
92
+
93
+ async getCurrentPackage() {
94
+ return (await /** @type {ADB} */ (this.adb).getFocusedPackageAndActivity()).appPackage;
95
+ },
96
+
97
+ async background(seconds) {
98
+ const adb = /** @type {ADB} */ (this.adb);
99
+ if (seconds < 0) {
100
+ // if user passes in a negative seconds value, interpret that as the instruction
101
+ // to not bring the app back at all
102
+ await adb.goToHome();
134
103
  return true;
135
- } catch (ign) {}
136
- args = ((appPackage === this.opts.appPackage && appActivity === this.opts.appActivity) ||
137
- (appPackage === this.opts.appWaitPackage && (this.opts.appWaitActivity || '').split(',').includes(appActivity)))
138
- ? {// the activity is the original session activity, so use the original args
139
- pkg: this.opts.appPackage,
140
- activity: this.opts.appActivity,
141
- action: this.opts.intentAction,
142
- category: this.opts.intentCategory,
143
- flags: this.opts.intentFlags,
144
- waitPkg: this.opts.appWaitPackage,
145
- waitActivity: this.opts.appWaitActivity,
146
- waitForLaunch: this.opts.appWaitForLaunch,
147
- waitDuration: this.opts.appWaitDuration,
148
- optionalIntentArguments: this.opts.optionalIntentArguments,
149
- stopApp: false,
150
- user: this.opts.userProfile}
151
- : {// the activity was started some other way, so use defaults
152
- pkg: appPackage,
153
- activity: appActivity,
154
- waitPkg: appPackage,
155
- waitActivity: appActivity,
156
- stopApp: false};
157
- }
158
- args = await util.filterObject(args);
159
- this.log.debug(`Bringing application back to foreground with arguments: ${JSON.stringify(args)}`);
160
- return await this.adb.startApp(args);
161
- };
162
-
163
- commands.getStrings = async function getStrings (language) {
164
- if (!language) {
165
- language = await this.adb.getDeviceLanguage();
166
- this.log.info(`No language specified, returning strings for: ${language}`);
167
- }
168
-
169
- // Clients require the resulting mapping to have both keys
170
- // and values of type string
171
- const preprocessStringsMap = (mapping) => {
172
- const result = {};
173
- for (const [key, value] of _.toPairs(mapping)) {
174
- result[key] = _.isString(value) ? value : JSON.stringify(value);
175
104
  }
176
- return result;
177
- };
178
-
179
- if (this.apkStrings[language]) {
180
- // Return cached strings
181
- return preprocessStringsMap(this.apkStrings[language]);
182
- }
183
-
184
- this.apkStrings[language] = await androidHelpers.pushStrings(language, this.adb, this.opts);
185
- if (this.bootstrap) {
186
- // TODO: This is mutating the current language, but it's how appium currently works
187
- await this.bootstrap.sendAction('updateStrings');
188
- }
105
+ let {appPackage, appActivity} = await adb.getFocusedPackageAndActivity();
106
+ await adb.goToHome();
107
+
108
+ // people can wait for a long time, so to be safe let's use the longSleep function and log
109
+ // progress periodically.
110
+ const sleepMs = seconds * 1000;
111
+ const thresholdMs = 30 * 1000; // use the spin-wait for anything over this threshold
112
+ // for our spin interval, use 1% of the total wait time, but nothing bigger than 30s
113
+ const intervalMs = _.min([30 * 1000, parseInt(String(sleepMs / 100), 10)]);
114
+ /**
115
+ *
116
+ * @param {{elapsedMs: number, progress: number}} param0
117
+ */
118
+ const progressCb = ({elapsedMs, progress}) => {
119
+ const waitSecs = (elapsedMs / 1000).toFixed(0);
120
+ const progressPct = (progress * 100).toFixed(2);
121
+ this.log.debug(`Waited ${waitSecs}s so far (${progressPct}%)`);
122
+ };
123
+ await longSleep(sleepMs, {thresholdMs, intervalMs, progressCb});
124
+
125
+ /** @type {import('appium-adb').StartAppOptions} */
126
+ let args;
127
+ if (this._cachedActivityArgs && this._cachedActivityArgs[`${appPackage}/${appActivity}`]) {
128
+ // the activity was started with `startActivity`, so use those args to restart
129
+ args = this._cachedActivityArgs[`${appPackage}/${appActivity}`];
130
+ } else {
131
+ try {
132
+ this.log.debug(`Activating app '${appPackage}' in order to restore it`);
133
+ await this.activateApp(/** @type {string} */ (appPackage));
134
+ return true;
135
+ } catch (ign) {}
136
+ args =
137
+ (appPackage === this.opts.appPackage && appActivity === this.opts.appActivity) ||
138
+ (appPackage === this.opts.appWaitPackage &&
139
+ (this.opts.appWaitActivity || '').split(',').includes(String(appActivity)))
140
+ ? {
141
+ // the activity is the original session activity, so use the original args
142
+ pkg: /** @type {string} */ (this.opts.appPackage),
143
+ activity: this.opts.appActivity,
144
+ action: this.opts.intentAction,
145
+ category: this.opts.intentCategory,
146
+ flags: this.opts.intentFlags,
147
+ waitPkg: this.opts.appWaitPackage,
148
+ waitActivity: this.opts.appWaitActivity,
149
+ waitForLaunch: this.opts.appWaitForLaunch,
150
+ waitDuration: this.opts.appWaitDuration,
151
+ optionalIntentArguments: this.opts.optionalIntentArguments,
152
+ stopApp: false,
153
+ user: this.opts.userProfile,
154
+ }
155
+ : {
156
+ // the activity was started some other way, so use defaults
157
+ pkg: /** @type {string} */ (appPackage),
158
+ activity: appActivity,
159
+ waitPkg: appPackage,
160
+ waitActivity: appActivity,
161
+ stopApp: false,
162
+ };
163
+ }
164
+ args = /** @type {import('appium-adb').StartAppOptions} */ (
165
+ _.pickBy(args, (value) => !_.isUndefined(value))
166
+ );
167
+ this.log.debug(
168
+ `Bringing application back to foreground with arguments: ${JSON.stringify(args)}`
169
+ );
170
+ return await adb.startApp(args);
171
+ },
172
+
173
+ async getStrings(language) {
174
+ const adb = /** @type {ADB} */ (this.adb);
175
+ if (!language) {
176
+ language = await adb.getDeviceLanguage();
177
+ this.log.info(`No language specified, returning strings for: ${language}`);
178
+ }
189
179
 
190
- return preprocessStringsMap(this.apkStrings[language]);
191
- };
180
+ // Clients require the resulting mapping to have both keys
181
+ // and values of type string
182
+ /** @param {StringRecord} mapping */
183
+ const preprocessStringsMap = (mapping) => {
184
+ /** @type {StringRecord} */
185
+ const result = {};
186
+ for (const [key, value] of _.toPairs(mapping)) {
187
+ result[key] = _.isString(value) ? value : JSON.stringify(value);
188
+ }
189
+ return result;
190
+ };
191
+
192
+ if (this.apkStrings[language]) {
193
+ // Return cached strings
194
+ return preprocessStringsMap(this.apkStrings[language]);
195
+ }
192
196
 
193
- commands.launchApp = async function launchApp () {
194
- await this.initAUT();
195
- await this.startAUT();
196
- };
197
+ this.apkStrings[language] = await androidHelpers.pushStrings(language, adb, this.opts);
198
+ if (this.bootstrap) {
199
+ // TODO: This is mutating the current language, but it's how appium currently works
200
+ await this.bootstrap.sendAction('updateStrings');
201
+ }
197
202
 
198
- commands.startActivity = async function startActivity (appPackage, appActivity,
199
- appWaitPackage, appWaitActivity, intentAction, intentCategory, intentFlags,
200
- optionalIntentArguments, dontStopAppOnReset) {
201
- this.log.debug(`Starting package '${appPackage}' and activity '${appActivity}'`);
202
-
203
- // dontStopAppOnReset is both an argument here, and a desired capability
204
- // if the argument is set, use it, otherwise use the cap
205
- if (!util.hasValue(dontStopAppOnReset)) {
206
- dontStopAppOnReset = !!this.opts.dontStopAppOnReset;
207
- }
208
-
209
- let args = {
210
- pkg: appPackage,
211
- activity: appActivity,
212
- waitPkg: appWaitPackage || appPackage,
213
- waitActivity: appWaitActivity || appActivity,
214
- action: intentAction,
215
- category: intentCategory,
216
- flags: intentFlags,
203
+ return preprocessStringsMap(this.apkStrings[language]);
204
+ },
205
+
206
+ async launchApp() {
207
+ await this.initAUT();
208
+ await this.startAUT();
209
+ },
210
+
211
+ async startActivity(
212
+ appPackage,
213
+ appActivity,
214
+ appWaitPackage,
215
+ appWaitActivity,
216
+ intentAction,
217
+ intentCategory,
218
+ intentFlags,
217
219
  optionalIntentArguments,
218
- stopApp: !dontStopAppOnReset
219
- };
220
- this._cachedActivityArgs = this._cachedActivityArgs || {};
221
- this._cachedActivityArgs[`${args.waitPkg}/${args.waitActivity}`] = args;
222
- await this.adb.startApp(args);
223
- };
224
-
225
- commands.reset = async function reset () {
226
- await androidHelpers.resetApp(this.adb, Object.assign({}, this.opts, {fastReset: true}));
227
- // reset context since we don't know what kind on context we will end up after app launch.
228
- await this.setContext();
229
- return await this.isChromeSession ? this.startChromeSession() : this.startAUT();
230
- };
231
-
232
- commands.startAUT = async function startAUT () {
233
- await this.adb.startApp({
234
- pkg: this.opts.appPackage,
235
- activity: this.opts.appActivity,
236
- action: this.opts.intentAction,
237
- category: this.opts.intentCategory,
238
- flags: this.opts.intentFlags,
239
- waitPkg: this.opts.appWaitPackage,
240
- waitActivity: this.opts.appWaitActivity,
241
- waitForLaunch: this.opts.appWaitForLaunch,
242
- waitDuration: this.opts.appWaitDuration,
243
- optionalIntentArguments: this.opts.optionalIntentArguments,
244
- stopApp: !this.opts.dontStopAppOnReset,
245
- user: this.opts.userProfile,
246
- });
247
- };
248
-
249
- // we override setUrl to take an android URI which can be used for deep-linking
250
- // inside an app, similar to starting an intent
251
- commands.setUrl = async function setUrl (uri) {
252
- await this.adb.startUri(uri, this.opts.appPackage);
253
- };
254
-
255
- // closing app using force stop
256
- commands.closeApp = async function closeApp () {
257
- await this.adb.forceStop(this.opts.appPackage);
258
- // reset context since we don't know what kind on context we will end up after app launch.
259
- await this.setContext();
260
- };
220
+ dontStopAppOnReset
221
+ ) {
222
+ this.log.debug(`Starting package '${appPackage}' and activity '${appActivity}'`);
223
+
224
+ // dontStopAppOnReset is both an argument here, and a desired capability
225
+ // if the argument is set, use it, otherwise use the cap
226
+ if (!util.hasValue(dontStopAppOnReset)) {
227
+ dontStopAppOnReset = !!this.opts.dontStopAppOnReset;
228
+ }
261
229
 
262
- commands.getDisplayDensity = async function getDisplayDensity () {
263
- // first try the property for devices
264
- let out = await this.adb.shell(['getprop', 'ro.sf.lcd_density']);
265
- if (out) {
266
- let val = parseInt(out, 10);
267
- // if the value is NaN, try getting the emulator property
268
- if (!isNaN(val)) {
269
- return val;
230
+ /** @type {import('appium-adb').StartAppOptions} */
231
+ let args = {
232
+ pkg: appPackage,
233
+ activity: appActivity,
234
+ waitPkg: appWaitPackage || appPackage,
235
+ waitActivity: appWaitActivity || appActivity,
236
+ action: intentAction,
237
+ category: intentCategory,
238
+ flags: intentFlags,
239
+ optionalIntentArguments,
240
+ stopApp: !dontStopAppOnReset,
241
+ };
242
+ this._cachedActivityArgs = this._cachedActivityArgs || {};
243
+ this._cachedActivityArgs[`${args.waitPkg}/${args.waitActivity}`] = args;
244
+ await /** @type {ADB} */ (this.adb).startApp(args);
245
+ },
246
+
247
+ async reset() {
248
+ await androidHelpers.resetApp(
249
+ /** @type {ADB} */ (this.adb),
250
+ Object.assign({}, this.opts, {fastReset: true})
251
+ );
252
+ // reset context since we don't know what kind on context we will end up after app launch.
253
+ await this.setContext();
254
+ return this.isChromeSession ? this.startChromeSession() : this.startAUT();
255
+ },
256
+
257
+ async startAUT() {
258
+ await /** @type {ADB} */ (this.adb).startApp({
259
+ pkg: /** @type {string} */ (this.opts.appPackage),
260
+ activity: this.opts.appActivity,
261
+ action: this.opts.intentAction,
262
+ category: this.opts.intentCategory,
263
+ flags: this.opts.intentFlags,
264
+ waitPkg: this.opts.appWaitPackage,
265
+ waitActivity: this.opts.appWaitActivity,
266
+ waitForLaunch: this.opts.appWaitForLaunch,
267
+ waitDuration: this.opts.appWaitDuration,
268
+ optionalIntentArguments: this.opts.optionalIntentArguments,
269
+ stopApp: !this.opts.dontStopAppOnReset,
270
+ user: this.opts.userProfile,
271
+ });
272
+ },
273
+
274
+ // we override setUrl to take an android URI which can be used for deep-linking
275
+ // inside an app, similar to starting an intent
276
+ async setUrl(uri) {
277
+ await /** @type {ADB} */ (this.adb).startUri(uri, /** @type {string} */ (this.opts.appPackage));
278
+ },
279
+
280
+ // closing app using force stop
281
+ async closeApp() {
282
+ await /** @type {ADB} */ (this.adb).forceStop(/** @type {string} */ (this.opts.appPackage));
283
+ // reset context since we don't know what kind on context we will end up after app launch.
284
+ await this.setContext();
285
+ },
286
+
287
+ async getDisplayDensity() {
288
+ // first try the property for devices
289
+ let out = await /** @type {ADB} */ (this.adb).shell(['getprop', 'ro.sf.lcd_density']);
290
+ if (out) {
291
+ let val = parseInt(out, 10);
292
+ // if the value is NaN, try getting the emulator property
293
+ if (!isNaN(val)) {
294
+ return val;
295
+ }
296
+ this.log.debug(`Parsed density value was NaN: "${out}"`);
270
297
  }
271
- this.log.debug(`Parsed density value was NaN: "${out}"`);
272
- }
273
- // fallback to trying property for emulators
274
- out = await this.adb.shell(['getprop', 'qemu.sf.lcd_density']);
275
- if (out) {
276
- let val = parseInt(out, 10);
277
- if (!isNaN(val)) {
278
- return val;
298
+ // fallback to trying property for emulators
299
+ out = await /** @type {ADB} */ (this.adb).shell(['getprop', 'qemu.sf.lcd_density']);
300
+ if (out) {
301
+ let val = parseInt(out, 10);
302
+ if (!isNaN(val)) {
303
+ return val;
304
+ }
305
+ this.log.debug(`Parsed density value was NaN: "${out}"`);
279
306
  }
280
- this.log.debug(`Parsed density value was NaN: "${out}"`);
281
- }
282
- // couldn't get anything, so error out
283
- this.log.errorAndThrow('Failed to get display density property.');
284
- };
285
-
286
- commands.mobilePerformEditorAction = async function mobilePerformEditorAction (opts = {}) {
287
- const {action} = opts;
288
- if (!util.hasValue(action)) {
289
- throw new errors.InvalidArgumentError(`'action' argument is required`);
290
- }
291
-
292
- await this.adb.performEditorAction(action);
307
+ // couldn't get anything, so error out
308
+ this.log.errorAndThrow('Failed to get display density property.');
309
+ throw new Error(); // unreachable
310
+ },
311
+
312
+ async mobilePerformEditorAction(opts) {
313
+ const {action} = requireArgs('action', opts);
314
+ await /** @type {ADB} */ (this.adb).performEditorAction(action);
315
+ },
316
+
317
+ async mobileGetNotifications() {
318
+ return await /** @type {ADB} */ (this.adb).getNotifications();
319
+ },
320
+
321
+ async mobileListSms(opts) {
322
+ return await /** @type {ADB} */ (this.adb).getSmsList(opts);
323
+ },
324
+
325
+ async mobileUnlock(opts = {}) {
326
+ const {key, type, strategy, timeoutMs} = opts;
327
+ if (!key && !type) {
328
+ await this.unlock();
329
+ } else {
330
+ // @ts-expect-error XXX: these caps should be defined in the constraints!!
331
+ await androidHelpers.unlock(this, /** @type {ADB} */ (this.adb), {
332
+ unlockKey: key,
333
+ unlockType: type,
334
+ unlockStrategy: strategy,
335
+ unlockSuccessTimeout: timeoutMs,
336
+ });
337
+ }
338
+ },
293
339
  };
294
340
 
295
- /**
296
- * Retrieves the list of recent system notifications.
297
- *
298
- * @returns {Object} See the documentation on `adb.getNotifications` for
299
- * more details
300
- */
301
- commands.mobileGetNotifications = async function mobileGetNotifications () {
302
- return await this.adb.getNotifications();
303
- };
341
+ mixin(GeneralMixin);
304
342
 
305
- /**
306
- * @typedef {Object} SmsListOptions
307
- * @property {number} max [100] - The maximum count of recent SMS messages
308
- * to retrieve
309
- */
343
+ export default GeneralMixin;
310
344
 
311
345
  /**
312
- * Retrieves the list of recent SMS messages with their properties.
313
- *
314
- * @param {SmsListOptions} opts
315
- * @returns {Object} See the documentation on `adb.getSmsList` for
316
- * more details
346
+ * @typedef {import('../bootstrap').AndroidBootstrap} AndroidBootstrap
347
+ * @typedef {import('appium-adb').ADB} ADB
348
+ * @typedef {import('@appium/types').StringRecord} StringRecord
317
349
  */
318
- commands.mobileListSms = async function mobileListSms (opts = {}) {
319
- return await this.adb.getSmsList(opts);
320
- };
321
-
322
- /**
323
- * @typedef {Object} UnlockOptions
324
- * @property {string?} key The unlock key. The value of this key depends
325
- * on the actual unlock type and could be a pin/password/pattern value or
326
- * a biometric finger id.
327
- * If not provided then the corresponding value from session capabilities is used.
328
- * @property {string?} type The unlock type. The following unlock types
329
- * are supported: `pin`, `pinWithKeyEvent`, `password`, `pattern` and `fingerprint`.
330
- * If not provided then the corresponding value from session capabilities is used.
331
- * @property {string?} strategy Either 'locksettings' (default) or 'uiautomator'.
332
- * Setting it to 'uiautomator' will enforce the driver to avoid using special
333
- * ADB shortcuts in order to speed up the unlock procedure.
334
- * @property {number?} timeoutMs [2000] The maximum time in milliseconds
335
- * to wait until the screen gets unlocked
336
- */
337
-
338
- /**
339
- * Unlocks the device if it is locked. Noop if the device's screen is not locked.
340
- *
341
- * @param {UnlockOptions} opts
342
- * @throws {Error} if unlock operation fails or the provided
343
- * arguments are not valid
344
- */
345
- commands.mobileUnlock = async function mobileUnlock (opts = {}) {
346
- const { key, type, strategy, timeoutMs } = opts;
347
- if (!key && !type) {
348
- await this.unlock();
349
- } else {
350
- await androidHelpers.unlock(this, this.adb, {
351
- unlockKey: key,
352
- unlockType: type,
353
- unlockStrategy: strategy,
354
- unlockSuccessTimeout: timeoutMs,
355
- });
356
- }
357
- };
358
-
359
- Object.assign(extensions, commands, helpers);
360
- export { commands, helpers };
361
- export default extensions;