appium-android-driver 7.8.3 → 8.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 (261) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/build/lib/commands/app-management.d.ts +129 -5
  3. package/build/lib/commands/app-management.d.ts.map +1 -1
  4. package/build/lib/commands/app-management.js +433 -128
  5. package/build/lib/commands/app-management.js.map +1 -1
  6. package/build/lib/commands/appearance.d.ts +17 -4
  7. package/build/lib/commands/appearance.d.ts.map +1 -1
  8. package/build/lib/commands/appearance.js +32 -33
  9. package/build/lib/commands/appearance.js.map +1 -1
  10. package/build/lib/commands/context/cache.d.ts +19 -0
  11. package/build/lib/commands/context/cache.d.ts.map +1 -0
  12. package/build/lib/commands/context/cache.js +32 -0
  13. package/build/lib/commands/context/cache.js.map +1 -0
  14. package/build/lib/commands/context/exports.d.ts +141 -0
  15. package/build/lib/commands/context/exports.d.ts.map +1 -0
  16. package/build/lib/commands/context/exports.js +351 -0
  17. package/build/lib/commands/context/exports.js.map +1 -0
  18. package/build/lib/commands/context/helpers.d.ts +98 -0
  19. package/build/lib/commands/context/helpers.d.ts.map +1 -0
  20. package/build/lib/commands/context/helpers.js +715 -0
  21. package/build/lib/commands/context/helpers.js.map +1 -0
  22. package/build/lib/commands/device/common.d.ts +23 -0
  23. package/build/lib/commands/device/common.d.ts.map +1 -0
  24. package/build/lib/commands/device/common.js +230 -0
  25. package/build/lib/commands/device/common.js.map +1 -0
  26. package/build/lib/commands/device/emulator-actions.d.ts +114 -0
  27. package/build/lib/commands/device/emulator-actions.d.ts.map +1 -0
  28. package/build/lib/commands/device/emulator-actions.js +197 -0
  29. package/build/lib/commands/device/emulator-actions.js.map +1 -0
  30. package/build/lib/commands/device/emulator-console.d.ts +7 -0
  31. package/build/lib/commands/device/emulator-console.d.ts.map +1 -0
  32. package/build/lib/commands/device/emulator-console.js +24 -0
  33. package/build/lib/commands/device/emulator-console.js.map +1 -0
  34. package/build/lib/commands/device/utils.d.ts +50 -0
  35. package/build/lib/commands/device/utils.d.ts.map +1 -0
  36. package/build/lib/commands/device/utils.js +238 -0
  37. package/build/lib/commands/device/utils.js.map +1 -0
  38. package/build/lib/commands/deviceidle.d.ts +8 -5
  39. package/build/lib/commands/deviceidle.d.ts.map +1 -1
  40. package/build/lib/commands/deviceidle.js +31 -37
  41. package/build/lib/commands/deviceidle.js.map +1 -1
  42. package/build/lib/commands/element.d.ts +99 -5
  43. package/build/lib/commands/element.d.ts.map +1 -1
  44. package/build/lib/commands/element.js +152 -116
  45. package/build/lib/commands/element.js.map +1 -1
  46. package/build/lib/commands/execute.d.ts +12 -4
  47. package/build/lib/commands/execute.d.ts.map +1 -1
  48. package/build/lib/commands/execute.js +83 -78
  49. package/build/lib/commands/execute.js.map +1 -1
  50. package/build/lib/commands/file-actions.d.ts +42 -5
  51. package/build/lib/commands/file-actions.d.ts.map +1 -1
  52. package/build/lib/commands/file-actions.js +230 -194
  53. package/build/lib/commands/file-actions.js.map +1 -1
  54. package/build/lib/commands/find.d.ts +5 -4
  55. package/build/lib/commands/find.d.ts.map +1 -1
  56. package/build/lib/commands/find.js +7 -10
  57. package/build/lib/commands/find.js.map +1 -1
  58. package/build/lib/commands/geolocation.d.ts +45 -0
  59. package/build/lib/commands/geolocation.d.ts.map +1 -0
  60. package/build/lib/commands/geolocation.js +182 -0
  61. package/build/lib/commands/geolocation.js.map +1 -0
  62. package/build/lib/commands/ime.d.ts +25 -5
  63. package/build/lib/commands/ime.d.ts.map +1 -1
  64. package/build/lib/commands/ime.js +59 -42
  65. package/build/lib/commands/ime.js.map +1 -1
  66. package/build/lib/commands/intent.d.ts +56 -5
  67. package/build/lib/commands/intent.d.ts.map +1 -1
  68. package/build/lib/commands/intent.js +135 -83
  69. package/build/lib/commands/intent.js.map +1 -1
  70. package/build/lib/commands/keyboard.d.ts +58 -4
  71. package/build/lib/commands/keyboard.d.ts.map +1 -1
  72. package/build/lib/commands/keyboard.js +119 -17
  73. package/build/lib/commands/keyboard.js.map +1 -1
  74. package/build/lib/commands/lock/exports.d.ts +301 -0
  75. package/build/lib/commands/lock/exports.d.ts.map +1 -0
  76. package/build/lib/commands/lock/exports.js +121 -0
  77. package/build/lib/commands/lock/exports.js.map +1 -0
  78. package/build/lib/commands/lock/helpers.d.ts +349 -0
  79. package/build/lib/commands/lock/helpers.d.ts.map +1 -0
  80. package/build/lib/commands/lock/helpers.js +375 -0
  81. package/build/lib/commands/lock/helpers.js.map +1 -0
  82. package/build/lib/commands/log.d.ts +59 -5
  83. package/build/lib/commands/log.d.ts.map +1 -1
  84. package/build/lib/commands/log.js +150 -140
  85. package/build/lib/commands/log.js.map +1 -1
  86. package/build/lib/commands/media-projection.d.ts +16 -5
  87. package/build/lib/commands/media-projection.d.ts.map +1 -1
  88. package/build/lib/commands/media-projection.js +69 -58
  89. package/build/lib/commands/media-projection.js.map +1 -1
  90. package/build/lib/commands/memory.d.ts +9 -5
  91. package/build/lib/commands/memory.d.ts.map +1 -1
  92. package/build/lib/commands/memory.js +19 -24
  93. package/build/lib/commands/memory.js.map +1 -1
  94. package/build/lib/commands/misc.d.ts +42 -0
  95. package/build/lib/commands/misc.d.ts.map +1 -0
  96. package/build/lib/commands/misc.js +100 -0
  97. package/build/lib/commands/misc.js.map +1 -0
  98. package/build/lib/commands/network.d.ts +61 -5
  99. package/build/lib/commands/network.d.ts.map +1 -1
  100. package/build/lib/commands/network.js +196 -189
  101. package/build/lib/commands/network.js.map +1 -1
  102. package/build/lib/commands/performance.d.ts +67 -27
  103. package/build/lib/commands/performance.d.ts.map +1 -1
  104. package/build/lib/commands/performance.js +105 -80
  105. package/build/lib/commands/performance.js.map +1 -1
  106. package/build/lib/commands/permissions.d.ts +12 -6
  107. package/build/lib/commands/permissions.d.ts.map +1 -1
  108. package/build/lib/commands/permissions.js +65 -62
  109. package/build/lib/commands/permissions.js.map +1 -1
  110. package/build/lib/commands/recordscreen.d.ts +44 -5
  111. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  112. package/build/lib/commands/recordscreen.js +131 -126
  113. package/build/lib/commands/recordscreen.js.map +1 -1
  114. package/build/lib/commands/resources.d.ts +16 -0
  115. package/build/lib/commands/resources.d.ts.map +1 -0
  116. package/build/lib/commands/resources.js +91 -0
  117. package/build/lib/commands/resources.js.map +1 -0
  118. package/build/lib/commands/shell.d.ts +8 -5
  119. package/build/lib/commands/shell.d.ts.map +1 -1
  120. package/build/lib/commands/shell.js +29 -33
  121. package/build/lib/commands/shell.js.map +1 -1
  122. package/build/lib/commands/streamscreen.d.ts +34 -6
  123. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  124. package/build/lib/commands/streamscreen.js +166 -162
  125. package/build/lib/commands/streamscreen.js.map +1 -1
  126. package/build/lib/commands/system-bars.d.ts +18 -13
  127. package/build/lib/commands/system-bars.d.ts.map +1 -1
  128. package/build/lib/commands/system-bars.js +68 -64
  129. package/build/lib/commands/system-bars.js.map +1 -1
  130. package/build/lib/commands/time.d.ts +14 -0
  131. package/build/lib/commands/time.d.ts.map +1 -0
  132. package/build/lib/commands/time.js +39 -0
  133. package/build/lib/commands/time.js.map +1 -0
  134. package/build/lib/commands/touch.d.ts +99 -6
  135. package/build/lib/commands/touch.d.ts.map +1 -1
  136. package/build/lib/commands/touch.js +399 -280
  137. package/build/lib/commands/touch.js.map +1 -1
  138. package/build/lib/commands/types.d.ts +110 -2
  139. package/build/lib/commands/types.d.ts.map +1 -1
  140. package/build/lib/doctor/checks.d.ts.map +1 -1
  141. package/build/lib/doctor/checks.js +4 -4
  142. package/build/lib/doctor/checks.js.map +1 -1
  143. package/build/lib/driver.d.ts +224 -27
  144. package/build/lib/driver.d.ts.map +1 -1
  145. package/build/lib/driver.js +232 -7
  146. package/build/lib/driver.js.map +1 -1
  147. package/build/lib/index.d.ts +1 -4
  148. package/build/lib/index.d.ts.map +1 -1
  149. package/build/lib/index.js +1 -13
  150. package/build/lib/index.js.map +1 -1
  151. package/build/lib/logger.js.map +1 -1
  152. package/build/lib/method-map.d.ts +0 -23
  153. package/build/lib/method-map.d.ts.map +1 -1
  154. package/build/lib/method-map.js +0 -11
  155. package/build/lib/method-map.js.map +1 -1
  156. package/build/lib/utils.d.ts +12 -0
  157. package/build/lib/utils.d.ts.map +1 -1
  158. package/build/lib/utils.js +38 -2
  159. package/build/lib/utils.js.map +1 -1
  160. package/lib/commands/app-management.js +470 -145
  161. package/lib/commands/appearance.js +29 -36
  162. package/lib/commands/context/cache.js +29 -0
  163. package/lib/commands/context/exports.js +379 -0
  164. package/lib/commands/context/helpers.js +802 -0
  165. package/lib/commands/device/common.js +264 -0
  166. package/lib/commands/device/emulator-actions.js +194 -0
  167. package/lib/commands/device/emulator-console.js +24 -0
  168. package/lib/commands/device/utils.js +285 -0
  169. package/lib/commands/deviceidle.js +31 -44
  170. package/lib/commands/element.js +149 -142
  171. package/lib/commands/execute.js +86 -87
  172. package/lib/commands/file-actions.js +249 -222
  173. package/lib/commands/find.ts +13 -19
  174. package/lib/commands/geolocation.js +179 -0
  175. package/lib/commands/ime.js +53 -45
  176. package/lib/commands/intent.js +149 -91
  177. package/lib/commands/keyboard.js +114 -17
  178. package/lib/commands/lock/exports.js +139 -0
  179. package/lib/commands/lock/helpers.js +379 -0
  180. package/lib/commands/log.js +170 -166
  181. package/lib/commands/media-projection.js +75 -70
  182. package/lib/commands/memory.js +17 -29
  183. package/lib/commands/misc.js +94 -0
  184. package/lib/commands/network.js +209 -223
  185. package/lib/commands/performance.js +88 -73
  186. package/lib/commands/permissions.js +83 -84
  187. package/lib/commands/recordscreen.js +171 -170
  188. package/lib/commands/resources.js +96 -0
  189. package/lib/commands/shell.js +28 -42
  190. package/lib/commands/streamscreen.js +207 -206
  191. package/lib/commands/system-bars.js +76 -77
  192. package/lib/commands/time.js +36 -0
  193. package/lib/commands/touch.js +442 -346
  194. package/lib/commands/types.ts +123 -2
  195. package/lib/doctor/checks.js +24 -16
  196. package/lib/driver.ts +454 -12
  197. package/lib/index.ts +1 -13
  198. package/lib/logger.js +1 -1
  199. package/lib/method-map.js +0 -11
  200. package/lib/utils.js +40 -3
  201. package/package.json +1 -1
  202. package/build/lib/commands/actions.d.ts +0 -8
  203. package/build/lib/commands/actions.d.ts.map +0 -1
  204. package/build/lib/commands/actions.js +0 -207
  205. package/build/lib/commands/actions.js.map +0 -1
  206. package/build/lib/commands/alert.d.ts +0 -8
  207. package/build/lib/commands/alert.d.ts.map +0 -1
  208. package/build/lib/commands/alert.js +0 -29
  209. package/build/lib/commands/alert.js.map +0 -1
  210. package/build/lib/commands/context.d.ts +0 -10
  211. package/build/lib/commands/context.d.ts.map +0 -1
  212. package/build/lib/commands/context.js +0 -431
  213. package/build/lib/commands/context.js.map +0 -1
  214. package/build/lib/commands/emu-console.d.ts +0 -7
  215. package/build/lib/commands/emu-console.d.ts.map +0 -1
  216. package/build/lib/commands/emu-console.js +0 -27
  217. package/build/lib/commands/emu-console.js.map +0 -1
  218. package/build/lib/commands/general.d.ts +0 -9
  219. package/build/lib/commands/general.d.ts.map +0 -1
  220. package/build/lib/commands/general.js +0 -293
  221. package/build/lib/commands/general.js.map +0 -1
  222. package/build/lib/commands/index.d.ts +0 -28
  223. package/build/lib/commands/index.d.ts.map +0 -1
  224. package/build/lib/commands/index.js +0 -57
  225. package/build/lib/commands/index.js.map +0 -1
  226. package/build/lib/commands/mixins.d.ts +0 -747
  227. package/build/lib/commands/mixins.d.ts.map +0 -1
  228. package/build/lib/commands/mixins.js +0 -19
  229. package/build/lib/commands/mixins.js.map +0 -1
  230. package/build/lib/helpers/android.d.ts +0 -163
  231. package/build/lib/helpers/android.d.ts.map +0 -1
  232. package/build/lib/helpers/android.js +0 -818
  233. package/build/lib/helpers/android.js.map +0 -1
  234. package/build/lib/helpers/index.d.ts +0 -7
  235. package/build/lib/helpers/index.d.ts.map +0 -1
  236. package/build/lib/helpers/index.js +0 -29
  237. package/build/lib/helpers/index.js.map +0 -1
  238. package/build/lib/helpers/types.d.ts +0 -122
  239. package/build/lib/helpers/types.d.ts.map +0 -1
  240. package/build/lib/helpers/types.js +0 -3
  241. package/build/lib/helpers/types.js.map +0 -1
  242. package/build/lib/helpers/unlock.d.ts +0 -32
  243. package/build/lib/helpers/unlock.d.ts.map +0 -1
  244. package/build/lib/helpers/unlock.js +0 -273
  245. package/build/lib/helpers/unlock.js.map +0 -1
  246. package/build/lib/helpers/webview.d.ts +0 -74
  247. package/build/lib/helpers/webview.d.ts.map +0 -1
  248. package/build/lib/helpers/webview.js +0 -448
  249. package/build/lib/helpers/webview.js.map +0 -1
  250. package/lib/commands/actions.js +0 -244
  251. package/lib/commands/alert.js +0 -34
  252. package/lib/commands/context.js +0 -507
  253. package/lib/commands/emu-console.js +0 -31
  254. package/lib/commands/general.js +0 -343
  255. package/lib/commands/index.ts +0 -54
  256. package/lib/commands/mixins.ts +0 -976
  257. package/lib/helpers/android.ts +0 -1153
  258. package/lib/helpers/index.ts +0 -6
  259. package/lib/helpers/types.ts +0 -136
  260. package/lib/helpers/unlock.ts +0 -329
  261. package/lib/helpers/webview.ts +0 -610
@@ -1,43 +1,36 @@
1
- import {mixin} from './mixins';
2
1
  import {requireArgs} from '../utils';
3
2
 
4
3
  const RESPONSE_PATTERN = /:\s+(\w+)/;
5
4
 
6
5
  /**
7
- * @type {import('./mixins').AppearanceMixin & ThisType<import('../driver').AndroidDriver>}
8
- * @satisfies {import('@appium/types').ExternalDriver}
6
+ * Set the Ui appearance.
7
+ *
8
+ * @since Android 10
9
+ * @this {import('../driver').AndroidDriver}
10
+ * @property {import('./types').SetUiModeOpts}
11
+ * @returns {Promise<void>}
9
12
  */
10
- const AppearanceMixin = {
11
- /**
12
- * Set the Ui appearance.
13
- *
14
- * @since Android 10
15
- */
16
- async mobileSetUiMode(opts) {
17
- const {mode, value} = requireArgs(['mode', 'value'], opts);
18
- await this.adb.shell(['cmd', 'uimode', mode, value]);
19
- },
13
+ export async function mobileSetUiMode(opts) {
14
+ const {mode, value} = requireArgs(['mode', 'value'], opts);
15
+ await this.adb.shell(['cmd', 'uimode', mode, value]);
16
+ }
20
17
 
21
- /**
22
- * Get the Ui appearance.
23
- *
24
- * @since Android 10
25
- * @returns {Promise<string>} The actual state for the queried UI mode,
26
- * for example 'yes' or 'no'
27
- */
28
- async mobileGetUiMode(opts) {
29
- const {mode} = requireArgs(['mode'], opts);
30
- const response = await this.adb.shell(['cmd', 'uimode', mode]);
31
- // response looks like 'Night mode: no'
32
- const match = RESPONSE_PATTERN.exec(response);
33
- if (!match) {
34
- throw new Error(`Cannot parse the command response: ${response}`);
35
- }
36
- return match[1];
37
- },
38
-
39
- };
40
-
41
- export default AppearanceMixin;
42
-
43
- mixin(AppearanceMixin);
18
+ /**
19
+ * Get the Ui appearance.
20
+ *
21
+ * @since Android 10
22
+ * @this {import('../driver').AndroidDriver}
23
+ * @property {import('./types').GetUiModeOpts}
24
+ * @returns {Promise<string>} The actual state for the queried UI mode,
25
+ * for example 'yes' or 'no'
26
+ */
27
+ export async function mobileGetUiMode(opts) {
28
+ const {mode} = requireArgs(['mode'], opts);
29
+ const response = await this.adb.shell(['cmd', 'uimode', mode]);
30
+ // response looks like 'Night mode: no'
31
+ const match = RESPONSE_PATTERN.exec(response);
32
+ if (!match) {
33
+ throw new Error(`Cannot parse the command response: ${response}`);
34
+ }
35
+ return match[1];
36
+ }
@@ -0,0 +1,29 @@
1
+ import {LRUCache} from 'lru-cache';
2
+
3
+ /** @type {LRUCache<string, import('../types').WebViewDetails>} */
4
+ export const WEBVIEWS_DETAILS_CACHE = new LRUCache({
5
+ max: 100,
6
+ updateAgeOnGet: true,
7
+ });
8
+
9
+ /**
10
+ *
11
+ * @param {import('appium-adb').ADB} adb
12
+ * @param {string} webview
13
+ * @returns {string}
14
+ */
15
+ export function toDetailsCacheKey(adb, webview) {
16
+ return `${adb?.curDeviceId}:${webview}`;
17
+ }
18
+
19
+ /**
20
+ * Retrieves web view details previously cached by `getWebviews` call
21
+ *
22
+ * @param {import('appium-adb').ADB} adb
23
+ * @param {string} webview
24
+ * @returns {import('../types').WebViewDetails | undefined}
25
+ */
26
+ export function getWebviewDetails(adb, webview) {
27
+ const key = toDetailsCacheKey(adb, webview);
28
+ return WEBVIEWS_DETAILS_CACHE.get(key);
29
+ }
@@ -0,0 +1,379 @@
1
+ /* eslint-disable require-await */
2
+ import {util} from '@appium/support';
3
+ import Chromedriver from 'appium-chromedriver';
4
+ import {errors} from 'appium/driver';
5
+ import _ from 'lodash';
6
+ import {
7
+ CHROMIUM_WIN,
8
+ KNOWN_CHROME_PACKAGE_NAMES,
9
+ NATIVE_WIN,
10
+ WEBVIEW_BASE,
11
+ WEBVIEW_WIN,
12
+ dismissChromeWelcome,
13
+ getWebViewsMapping,
14
+ parseWebviewNames,
15
+ setupExistingChromedriver,
16
+ setupNewChromedriver,
17
+ shouldDismissChromeWelcome,
18
+ } from './helpers';
19
+ import {APP_STATE} from '../app-management';
20
+
21
+ /**
22
+ * @this {import('../../driver').AndroidDriver}
23
+ * @returns {Promise<string>}
24
+ */
25
+ export async function getCurrentContext() {
26
+ // if the current context is `null`, indicating no context
27
+ // explicitly set, it is the default context
28
+ return this.curContext || this.defaultContextName();
29
+ }
30
+
31
+ /**
32
+ * @this {import('../../driver').AndroidDriver}
33
+ * @returns {Promise<string[]>}
34
+ */
35
+ export async function getContexts() {
36
+ const webviewsMapping = await getWebViewsMapping.bind(this)(this.opts);
37
+ return this.assignContexts(webviewsMapping);
38
+ }
39
+
40
+ /**
41
+ * @this {import('../../driver').AndroidDriver}
42
+ * @param {string?} name
43
+ * @returns {Promise<void>}
44
+ */
45
+ export async function setContext(name) {
46
+ if (!util.hasValue(name)) {
47
+ name = this.defaultContextName();
48
+ } else if (name === WEBVIEW_WIN) {
49
+ // handle setContext "WEBVIEW"
50
+ name = this.defaultWebviewName();
51
+ }
52
+ // if we're already in the context we want, do nothing
53
+ if (name === this.curContext) {
54
+ return;
55
+ }
56
+
57
+ const webviewsMapping = await getWebViewsMapping.bind(this)(this.opts);
58
+ const contexts = this.assignContexts(webviewsMapping);
59
+ // if the context we want doesn't exist, fail
60
+ if (!_.includes(contexts, name)) {
61
+ throw new errors.NoSuchContextError();
62
+ }
63
+
64
+ await this.switchContext(name, webviewsMapping);
65
+ this.curContext = name;
66
+ }
67
+
68
+ /**
69
+ * @this {import('../../driver').AndroidDriver}
70
+ * @param {any} [opts={}]
71
+ * @returns {Promise<import('../types').WebviewsMapping[]>}
72
+ */
73
+ export async function mobileGetContexts(opts = {}) {
74
+ const _opts = {
75
+ androidDeviceSocket: this.opts.androidDeviceSocket,
76
+ ensureWebviewsHavePages: true,
77
+ webviewDevtoolsPort: this.opts.webviewDevtoolsPort,
78
+ enableWebviewDetailsCollection: true,
79
+ waitForWebviewMs: opts.waitForWebviewMs || 0,
80
+ };
81
+ return await getWebViewsMapping.bind(this)(_opts);
82
+ }
83
+
84
+ /**
85
+ * @this {import('../../driver').AndroidDriver}
86
+ * @param {import('../types').WebviewsMapping[]} webviewsMapping
87
+ * @returns {string[]}
88
+ */
89
+ export function assignContexts(webviewsMapping) {
90
+ const opts = Object.assign({isChromeSession: this.isChromeSession}, this.opts);
91
+ const webviews = parseWebviewNames.bind(this)(webviewsMapping, opts);
92
+ this.contexts = [NATIVE_WIN, ...webviews];
93
+ this.log.debug(`Available contexts: ${JSON.stringify(this.contexts)}`);
94
+ return this.contexts;
95
+ }
96
+
97
+ /**
98
+ * @this {import('../../driver').AndroidDriver}
99
+ * @param {string} name
100
+ * @param {import('../types').WebviewsMapping[]} webviewsMapping
101
+ * @returns {Promise<void>}
102
+ */
103
+ export async function switchContext(name, webviewsMapping) {
104
+ // We have some options when it comes to webviews. If we want a
105
+ // Chromedriver webview, we can only control one at a time.
106
+ if (this.isChromedriverContext(name)) {
107
+ // start proxying commands directly to chromedriver
108
+ await this.startChromedriverProxy(name, webviewsMapping);
109
+ } else if (this.isChromedriverContext(this.curContext)) {
110
+ // if we're moving to a non-chromedriver webview, and our current context
111
+ // _is_ a chromedriver webview, if caps recreateChromeDriverSessions is set
112
+ // to true then kill chromedriver session using stopChromedriverProxies or
113
+ // else simply suspend proxying to the latter
114
+ if (this.opts.recreateChromeDriverSessions) {
115
+ this.log.debug('recreateChromeDriverSessions set to true; killing existing chromedrivers');
116
+ await this.stopChromedriverProxies();
117
+ } else {
118
+ this.suspendChromedriverProxy();
119
+ }
120
+ } else {
121
+ throw new Error(`Didn't know how to handle switching to context '${name}'`);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * @this {import('../../driver').AndroidDriver}
127
+ * @returns {string}
128
+ */
129
+ export function defaultContextName() {
130
+ return NATIVE_WIN;
131
+ }
132
+
133
+ /**
134
+ * @this {import('../../driver').AndroidDriver}
135
+ * @returns {string}
136
+ */
137
+ export function defaultWebviewName() {
138
+ return WEBVIEW_BASE + (this.opts.autoWebviewName || this.opts.appPackage);
139
+ }
140
+
141
+ /**
142
+ * @this {import('../../driver').AndroidDriver}
143
+ * @returns {boolean}
144
+ */
145
+ export function isWebContext() {
146
+ return this.curContext !== null && this.curContext !== NATIVE_WIN;
147
+ }
148
+
149
+ /**
150
+ * Turn on proxying to an existing Chromedriver session or a new one
151
+ *
152
+ * @this {import('../../driver').AndroidDriver}
153
+ * @param {string} context
154
+ * @param {import('../types').WebviewsMapping[]} webviewsMapping
155
+ * @returns {Promise<void>}
156
+ */
157
+ export async function startChromedriverProxy(context, webviewsMapping) {
158
+ this.log.debug(`Connecting to chrome-backed webview context '${context}'`);
159
+
160
+ let cd;
161
+ if (this.sessionChromedrivers[context]) {
162
+ // in the case where we've already set up a chromedriver for a context,
163
+ // we want to reconnect to it, not create a whole new one
164
+ this.log.debug(`Found existing Chromedriver for context '${context}'. Using it.`);
165
+ cd = this.sessionChromedrivers[context];
166
+ await setupExistingChromedriver.bind(this)(cd);
167
+ } else {
168
+ // XXX: this suppresses errors about putting arbitrary stuff on opts
169
+ const opts = /** @type {any} */ (_.cloneDeep(this.opts));
170
+ opts.chromeUseRunningApp = true;
171
+
172
+ // if requested, tell chromedriver to attach to the android package we have
173
+ // associated with the context name, rather than the package of the AUT.
174
+ // And turn this on by default for chrome--if chrome pops up with a webview
175
+ // and someone wants to switch to it, we should let chromedriver connect to
176
+ // chrome rather than staying stuck on the AUT
177
+ if (opts.extractChromeAndroidPackageFromContextName || context === `${WEBVIEW_BASE}chrome`) {
178
+ let androidPackage = context.match(`${WEBVIEW_BASE}(.+)`);
179
+ if (androidPackage && androidPackage.length > 0) {
180
+ opts.chromeAndroidPackage = androidPackage[1];
181
+ }
182
+ if (!opts.extractChromeAndroidPackageFromContextName) {
183
+ if (
184
+ _.has(this.opts, 'enableWebviewDetailsCollection') &&
185
+ !this.opts.enableWebviewDetailsCollection
186
+ ) {
187
+ // When enableWebviewDetailsCollection capability is explicitly disabled, try to identify
188
+ // chromeAndroidPackage based on contexts, known chrome variant packages and queryAppState result
189
+ // since webviewsMapping does not have info object
190
+ const contexts = webviewsMapping.map((wm) => wm.webviewName);
191
+ for (const knownPackage of KNOWN_CHROME_PACKAGE_NAMES) {
192
+ if (_.includes(contexts, `${WEBVIEW_BASE}${knownPackage}`)) {
193
+ continue;
194
+ }
195
+ const appState = await this.queryAppState(knownPackage);
196
+ if (
197
+ _.includes(
198
+ [APP_STATE.RUNNING_IN_BACKGROUND, APP_STATE.RUNNING_IN_FOREGROUND],
199
+ appState,
200
+ )
201
+ ) {
202
+ opts.chromeAndroidPackage = knownPackage;
203
+ this.log.debug(
204
+ `Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
205
+ `for context '${context}' by querying states of Chrome app packages`,
206
+ );
207
+ break;
208
+ }
209
+ }
210
+ } else {
211
+ for (const wm of webviewsMapping) {
212
+ if (wm.webviewName === context && _.has(wm?.info, 'Android-Package')) {
213
+ // XXX: should be a type guard here
214
+ opts.chromeAndroidPackage =
215
+ /** @type {NonNullable<import('../types').WebviewsMapping['info']>} */ (wm.info)[
216
+ 'Android-Package'
217
+ ];
218
+ this.log.debug(
219
+ `Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
220
+ `for context '${context}' by CDP`,
221
+ );
222
+ break;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ cd = await setupNewChromedriver.bind(this)(
230
+ opts,
231
+ /** @type {string} */ (this.adb.curDeviceId),
232
+ context,
233
+ );
234
+ // bind our stop/exit handler, passing in context so we know which
235
+ // one stopped unexpectedly
236
+ cd.on(Chromedriver.EVENT_CHANGED, (msg) => {
237
+ if (msg.state === Chromedriver.STATE_STOPPED) {
238
+ this.onChromedriverStop(context);
239
+ }
240
+ });
241
+ // save the chromedriver object under the context
242
+ this.sessionChromedrivers[context] = cd;
243
+ }
244
+ // hook up the local variables so we can proxy this biz
245
+ this.chromedriver = cd;
246
+ // @ts-ignore chromedriver is defined
247
+ this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
248
+ this.proxyCommand = /** @type {import('@appium/types').ExternalDriver['proxyCommand']} */ (
249
+ // @ts-ignore chromedriver is defined
250
+ this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy)
251
+ );
252
+ this.jwpProxyActive = true;
253
+ }
254
+
255
+ /**
256
+ * Stop proxying to any Chromedriver
257
+ *
258
+ * @this {import('../../driver').AndroidDriver}
259
+ * @returns {void}
260
+ */
261
+ export function suspendChromedriverProxy() {
262
+ this.chromedriver = undefined;
263
+ this.proxyReqRes = undefined;
264
+ this.proxyCommand = undefined;
265
+ this.jwpProxyActive = false;
266
+ }
267
+
268
+ /**
269
+ * Handle an out-of-band Chromedriver stop event
270
+ *
271
+ * @this {import('../../driver').AndroidDriver}
272
+ * @param {string} context
273
+ * @returns {Promise<void>}
274
+ */
275
+ export async function onChromedriverStop(context) {
276
+ this.log.warn(`Chromedriver for context ${context} stopped unexpectedly`);
277
+ if (context === this.curContext) {
278
+ // we exited unexpectedly while automating the current context and so want
279
+ // to shut down the session and respond with an error
280
+ let err = new Error('Chromedriver quit unexpectedly during session');
281
+ await this.startUnexpectedShutdown(err);
282
+ } else {
283
+ // if a Chromedriver in the non-active context barfs, we don't really
284
+ // care, we'll just make a new one next time we need the context.
285
+ this.log.warn(
286
+ "Chromedriver quit unexpectedly, but it wasn't the active " + 'context, ignoring',
287
+ );
288
+ delete this.sessionChromedrivers[context];
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Intentionally stop all the chromedrivers currently active, and ignore
294
+ * their exit events
295
+ *
296
+ * @this {import('../../driver').AndroidDriver}
297
+ * @returns {Promise<void>}
298
+ */
299
+ export async function stopChromedriverProxies() {
300
+ this.suspendChromedriverProxy(); // make sure we turn off the proxy flag
301
+ for (let context of _.keys(this.sessionChromedrivers)) {
302
+ let cd = this.sessionChromedrivers[context];
303
+ this.log.debug(`Stopping chromedriver for context ${context}`);
304
+ // stop listening for the stopped state event
305
+ cd.removeAllListeners(Chromedriver.EVENT_CHANGED);
306
+ try {
307
+ await cd.stop();
308
+ } catch (err) {
309
+ this.log.warn(`Error stopping Chromedriver: ${/** @type {Error} */ (err).message}`);
310
+ }
311
+ delete this.sessionChromedrivers[context];
312
+ }
313
+ }
314
+
315
+ /**
316
+ * @this {import('../../driver').AndroidDriver}
317
+ * @param {string} viewName
318
+ * @returns {boolean}
319
+ */
320
+ export function isChromedriverContext(viewName) {
321
+ return _.includes(viewName, WEBVIEW_WIN) || viewName === CHROMIUM_WIN;
322
+ }
323
+
324
+ /**
325
+ * @this {import('../../driver').AndroidDriver}
326
+ * @returns {Promise<void>}
327
+ */
328
+ export async function startChromeSession() {
329
+ this.log.info('Starting a chrome-based browser session');
330
+ // XXX: this suppresses errors about putting arbitrary stuff on opts
331
+ const opts = /** @type {any} */ (_.cloneDeep(this.opts));
332
+
333
+ const knownPackages = [
334
+ 'org.chromium.chrome.shell',
335
+ 'com.android.chrome',
336
+ 'com.chrome.beta',
337
+ 'org.chromium.chrome',
338
+ 'org.chromium.webview_shell',
339
+ ];
340
+
341
+ if (_.includes(knownPackages, this.opts.appPackage)) {
342
+ opts.chromeBundleId = this.opts.appPackage;
343
+ } else {
344
+ opts.chromeAndroidActivity = this.opts.appActivity;
345
+ }
346
+ this.chromedriver = await setupNewChromedriver.bind(this)(
347
+ opts,
348
+ /** @type {string} */ (this.adb.curDeviceId),
349
+ );
350
+ // @ts-ignore chromedriver is defined
351
+ this.chromedriver.on(Chromedriver.EVENT_CHANGED, (msg) => {
352
+ if (msg.state === Chromedriver.STATE_STOPPED) {
353
+ this.onChromedriverStop(CHROMIUM_WIN);
354
+ }
355
+ });
356
+
357
+ // Now that we have a Chrome session, we ensure that the context is
358
+ // appropriately set and that this chromedriver is added to the list
359
+ // of session chromedrivers so we can switch back and forth
360
+ this.curContext = CHROMIUM_WIN;
361
+ // @ts-ignore chromedriver is defined
362
+ this.sessionChromedrivers[CHROMIUM_WIN] = this.chromedriver;
363
+ // @ts-ignore chromedriver should be defined
364
+ this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
365
+ this.proxyCommand = /** @type {import('@appium/types').ExternalDriver['proxyCommand']} */ (
366
+ // @ts-ignore chromedriver is defined
367
+ this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy)
368
+ );
369
+ this.jwpProxyActive = true;
370
+
371
+ if (shouldDismissChromeWelcome.bind(this)()) {
372
+ // dismiss Chrome welcome dialog
373
+ await dismissChromeWelcome.bind(this)();
374
+ }
375
+ }
376
+
377
+ /**
378
+ * @typedef {import('appium-adb').ADB} ADB
379
+ */