appium-android-driver 5.14.7 → 6.0.1

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 (210) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/lib/commands/actions.d.ts +6 -224
  3. package/build/lib/commands/actions.d.ts.map +1 -1
  4. package/build/lib/commands/actions.js +306 -405
  5. package/build/lib/commands/actions.js.map +1 -1
  6. package/build/lib/commands/alert.d.ts +7 -9
  7. package/build/lib/commands/alert.d.ts.map +1 -1
  8. package/build/lib/commands/alert.js +24 -18
  9. package/build/lib/commands/alert.js.map +1 -1
  10. package/build/lib/commands/app-management.d.ts +7 -313
  11. package/build/lib/commands/app-management.d.ts.map +1 -1
  12. package/build/lib/commands/app-management.js +135 -293
  13. package/build/lib/commands/app-management.js.map +1 -1
  14. package/build/lib/commands/context.d.ts +8 -92
  15. package/build/lib/commands/context.d.ts.map +1 -1
  16. package/build/lib/commands/context.js +381 -439
  17. package/build/lib/commands/context.js.map +1 -1
  18. package/build/lib/commands/element.d.ts +8 -35
  19. package/build/lib/commands/element.d.ts.map +1 -1
  20. package/build/lib/commands/element.js +153 -136
  21. package/build/lib/commands/element.js.map +1 -1
  22. package/build/lib/commands/emu-console.d.ts +6 -48
  23. package/build/lib/commands/emu-console.d.ts.map +1 -1
  24. package/build/lib/commands/emu-console.js +19 -34
  25. package/build/lib/commands/emu-console.js.map +1 -1
  26. package/build/lib/commands/execute.d.ts +6 -5
  27. package/build/lib/commands/execute.d.ts.map +1 -1
  28. package/build/lib/commands/execute.js +77 -66
  29. package/build/lib/commands/execute.js.map +1 -1
  30. package/build/lib/commands/file-actions.d.ts +7 -128
  31. package/build/lib/commands/file-actions.d.ts.map +1 -1
  32. package/build/lib/commands/file-actions.js +183 -219
  33. package/build/lib/commands/file-actions.js.map +1 -1
  34. package/build/lib/commands/find.d.ts +8 -12
  35. package/build/lib/commands/find.d.ts.map +1 -1
  36. package/build/lib/commands/find.js +19 -23
  37. package/build/lib/commands/find.js.map +1 -1
  38. package/build/lib/commands/general.d.ts +9 -132
  39. package/build/lib/commands/general.d.ts.map +1 -1
  40. package/build/lib/commands/general.js +281 -312
  41. package/build/lib/commands/general.js.map +1 -1
  42. package/build/lib/commands/ime.d.ts +7 -10
  43. package/build/lib/commands/ime.d.ts.map +1 -1
  44. package/build/lib/commands/ime.js +47 -35
  45. package/build/lib/commands/ime.js.map +1 -1
  46. package/build/lib/commands/index.d.ts +27 -2
  47. package/build/lib/commands/index.d.ts.map +1 -1
  48. package/build/lib/commands/index.js +41 -19
  49. package/build/lib/commands/index.js.map +1 -1
  50. package/build/lib/commands/intent.d.ts +7 -417
  51. package/build/lib/commands/intent.d.ts.map +1 -1
  52. package/build/lib/commands/intent.js +104 -216
  53. package/build/lib/commands/intent.js.map +1 -1
  54. package/build/lib/commands/keyboard.d.ts +6 -5
  55. package/build/lib/commands/keyboard.d.ts.map +1 -1
  56. package/build/lib/commands/keyboard.js +16 -8
  57. package/build/lib/commands/keyboard.js.map +1 -1
  58. package/build/lib/commands/log.d.ts +7 -44
  59. package/build/lib/commands/log.d.ts.map +1 -1
  60. package/build/lib/commands/log.js +146 -108
  61. package/build/lib/commands/log.js.map +1 -1
  62. package/build/lib/commands/media-projection.d.ts +7 -143
  63. package/build/lib/commands/media-projection.d.ts.map +1 -1
  64. package/build/lib/commands/media-projection.js +113 -140
  65. package/build/lib/commands/media-projection.js.map +1 -1
  66. package/build/lib/commands/mixins.d.ts +740 -0
  67. package/build/lib/commands/mixins.d.ts.map +1 -0
  68. package/build/lib/commands/mixins.js +19 -0
  69. package/build/lib/commands/mixins.js.map +1 -0
  70. package/build/lib/commands/network.d.ts +7 -138
  71. package/build/lib/commands/network.d.ts.map +1 -1
  72. package/build/lib/commands/network.js +212 -254
  73. package/build/lib/commands/network.js.map +1 -1
  74. package/build/lib/commands/performance.d.ts +24 -70
  75. package/build/lib/commands/performance.d.ts.map +1 -1
  76. package/build/lib/commands/performance.js +144 -100
  77. package/build/lib/commands/performance.js.map +1 -1
  78. package/build/lib/commands/permissions.d.ts +8 -92
  79. package/build/lib/commands/permissions.d.ts.map +1 -1
  80. package/build/lib/commands/permissions.js +75 -87
  81. package/build/lib/commands/permissions.js.map +1 -1
  82. package/build/lib/commands/recordscreen.d.ts +7 -193
  83. package/build/lib/commands/recordscreen.d.ts.map +1 -1
  84. package/build/lib/commands/recordscreen.js +151 -182
  85. package/build/lib/commands/recordscreen.js.map +1 -1
  86. package/build/lib/commands/shell.d.ts +7 -7
  87. package/build/lib/commands/shell.d.ts.map +1 -1
  88. package/build/lib/commands/shell.js +40 -33
  89. package/build/lib/commands/shell.js.map +1 -1
  90. package/build/lib/commands/streamscreen.d.ts +9 -103
  91. package/build/lib/commands/streamscreen.d.ts.map +1 -1
  92. package/build/lib/commands/streamscreen.js +261 -218
  93. package/build/lib/commands/streamscreen.js.map +1 -1
  94. package/build/lib/commands/system-bars.d.ts +22 -90
  95. package/build/lib/commands/system-bars.d.ts.map +1 -1
  96. package/build/lib/commands/system-bars.js +76 -74
  97. package/build/lib/commands/system-bars.js.map +1 -1
  98. package/build/lib/commands/touch.d.ts +10 -29
  99. package/build/lib/commands/touch.d.ts.map +1 -1
  100. package/build/lib/commands/touch.js +301 -285
  101. package/build/lib/commands/touch.js.map +1 -1
  102. package/build/lib/commands/types.d.ts +978 -0
  103. package/build/lib/commands/types.d.ts.map +1 -0
  104. package/build/lib/commands/types.js +3 -0
  105. package/build/lib/commands/types.js.map +1 -0
  106. package/build/lib/constraints.d.ts +291 -0
  107. package/build/lib/constraints.d.ts.map +1 -0
  108. package/build/lib/{desired-caps.js → constraints.js} +103 -102
  109. package/build/lib/constraints.js.map +1 -0
  110. package/build/lib/driver.d.ts +68 -37
  111. package/build/lib/driver.d.ts.map +1 -1
  112. package/build/lib/driver.js +123 -80
  113. package/build/lib/driver.js.map +1 -1
  114. package/build/lib/helpers/android.d.ts +164 -0
  115. package/build/lib/helpers/android.d.ts.map +1 -0
  116. package/build/lib/helpers/android.js +819 -0
  117. package/build/lib/helpers/android.js.map +1 -0
  118. package/build/lib/helpers/index.d.ts +7 -0
  119. package/build/lib/helpers/index.d.ts.map +1 -0
  120. package/build/lib/helpers/index.js +29 -0
  121. package/build/lib/helpers/index.js.map +1 -0
  122. package/build/lib/helpers/types.d.ts +121 -0
  123. package/build/lib/helpers/types.d.ts.map +1 -0
  124. package/build/lib/helpers/types.js +3 -0
  125. package/build/lib/helpers/types.js.map +1 -0
  126. package/build/lib/helpers/unlock.d.ts +32 -0
  127. package/build/lib/helpers/unlock.d.ts.map +1 -0
  128. package/build/lib/helpers/unlock.js +273 -0
  129. package/build/lib/helpers/unlock.js.map +1 -0
  130. package/build/lib/helpers/webview.d.ts +74 -0
  131. package/build/lib/helpers/webview.d.ts.map +1 -0
  132. package/build/lib/helpers/webview.js +421 -0
  133. package/build/lib/helpers/webview.js.map +1 -0
  134. package/build/lib/index.d.ts +9 -0
  135. package/build/lib/index.d.ts.map +1 -0
  136. package/build/lib/index.js +37 -0
  137. package/build/lib/index.js.map +1 -0
  138. package/build/lib/method-map.d.ts +0 -8
  139. package/build/lib/method-map.d.ts.map +1 -1
  140. package/build/lib/method-map.js +63 -74
  141. package/build/lib/method-map.js.map +1 -1
  142. package/build/lib/stubs.d.ts +0 -1
  143. package/build/lib/stubs.d.ts.map +1 -1
  144. package/build/lib/stubs.js +1 -0
  145. package/build/lib/stubs.js.map +1 -1
  146. package/build/lib/utils.d.ts +1 -1
  147. package/build/lib/utils.d.ts.map +1 -1
  148. package/lib/commands/actions.js +351 -464
  149. package/lib/commands/alert.js +27 -17
  150. package/lib/commands/app-management.js +156 -314
  151. package/lib/commands/context.js +457 -441
  152. package/lib/commands/element.js +201 -157
  153. package/lib/commands/emu-console.js +25 -45
  154. package/lib/commands/execute.js +106 -90
  155. package/lib/commands/file-actions.js +222 -240
  156. package/lib/commands/find.ts +103 -0
  157. package/lib/commands/general.js +327 -339
  158. package/lib/commands/ime.js +50 -34
  159. package/lib/commands/{index.js → index.ts} +20 -24
  160. package/lib/commands/intent.js +108 -249
  161. package/lib/commands/keyboard.js +20 -8
  162. package/lib/commands/log.js +172 -116
  163. package/lib/commands/media-projection.js +134 -161
  164. package/lib/commands/mixins.ts +966 -0
  165. package/lib/commands/network.js +252 -281
  166. package/lib/commands/performance.js +203 -132
  167. package/lib/commands/permissions.js +108 -109
  168. package/lib/commands/recordscreen.js +212 -209
  169. package/lib/commands/shell.js +51 -40
  170. package/lib/commands/streamscreen.js +355 -289
  171. package/lib/commands/system-bars.js +92 -83
  172. package/lib/commands/touch.js +357 -294
  173. package/lib/commands/types.ts +1097 -0
  174. package/lib/{desired-caps.js → constraints.ts} +106 -103
  175. package/lib/{driver.js → driver.ts} +278 -132
  176. package/lib/helpers/android.ts +1143 -0
  177. package/lib/helpers/index.ts +6 -0
  178. package/lib/helpers/types.ts +134 -0
  179. package/lib/helpers/unlock.ts +329 -0
  180. package/lib/helpers/webview.ts +582 -0
  181. package/lib/index.ts +18 -0
  182. package/lib/method-map.js +87 -98
  183. package/lib/stubs.ts +0 -1
  184. package/package.json +26 -19
  185. package/build/index.js +0 -51
  186. package/build/lib/android-helpers.d.ts +0 -136
  187. package/build/lib/android-helpers.d.ts.map +0 -1
  188. package/build/lib/android-helpers.js +0 -855
  189. package/build/lib/android-helpers.js.map +0 -1
  190. package/build/lib/commands/coverage.d.ts +0 -5
  191. package/build/lib/commands/coverage.d.ts.map +0 -1
  192. package/build/lib/commands/coverage.js +0 -19
  193. package/build/lib/commands/coverage.js.map +0 -1
  194. package/build/lib/desired-caps.d.ts +0 -353
  195. package/build/lib/desired-caps.d.ts.map +0 -1
  196. package/build/lib/desired-caps.js.map +0 -1
  197. package/build/lib/unlock-helpers.d.ts +0 -38
  198. package/build/lib/unlock-helpers.d.ts.map +0 -1
  199. package/build/lib/unlock-helpers.js +0 -266
  200. package/build/lib/unlock-helpers.js.map +0 -1
  201. package/build/lib/webview-helpers.d.ts +0 -224
  202. package/build/lib/webview-helpers.d.ts.map +0 -1
  203. package/build/lib/webview-helpers.js +0 -528
  204. package/build/lib/webview-helpers.js.map +0 -1
  205. package/index.js +0 -24
  206. package/lib/android-helpers.js +0 -983
  207. package/lib/commands/coverage.js +0 -18
  208. package/lib/commands/find.js +0 -82
  209. package/lib/unlock-helpers.js +0 -278
  210. package/lib/webview-helpers.js +0 -602
@@ -0,0 +1,6 @@
1
+ export {default as WebviewHelpers} from './webview';
2
+ export * from './webview';
3
+ export * from './unlock';
4
+ export * from './types';
5
+ export {default as AndroidHelpers} from './android';
6
+ export * from './android';
@@ -0,0 +1,134 @@
1
+ import type {ADB} from 'appium-adb';
2
+ import {AndroidDriverCaps} from '../driver';
3
+ import {StringRecord} from '@appium/types';
4
+
5
+ export interface WebviewProc {
6
+ /**
7
+ * The webview process name (as returned by getPotentialWebviewProcs)
8
+ */
9
+ proc: string;
10
+ /**
11
+ * The actual webview context name
12
+ */
13
+ webview: string;
14
+ }
15
+
16
+ export interface DetailCollectionOptions {
17
+ /**
18
+ * The starting port to use for webview page presence check (if not the default of 9222).
19
+ */
20
+ webviewDevtoolsPort?: number | null;
21
+ /**
22
+ * Whether to check for webview pages presence
23
+ */
24
+ ensureWebviewsHavePages?: boolean | null;
25
+ /**
26
+ * Whether to collect web view details and send them to Chromedriver constructor, so it could
27
+ * select a binary more precisely based on this info.
28
+ */
29
+ enableWebviewDetailsCollection?: boolean | null;
30
+ }
31
+
32
+ export interface WebviewProps {
33
+ /**
34
+ * The name of the Devtools Unix socket
35
+ */
36
+ proc: string;
37
+ /**
38
+ * The web view alias. Looks like `WEBVIEW_` prefix plus PID or package name
39
+ */
40
+ webview: string;
41
+ /**
42
+ * Webview information as it is retrieved by /json/version CDP endpoint
43
+ */
44
+ info?: object | null;
45
+ /**
46
+ * Webview pages list as it is retrieved by /json/list CDP endpoint
47
+ */
48
+ pages?: object[] | null;
49
+ }
50
+
51
+ export interface GetWebviewsOpts {
52
+ /**
53
+ * device socket name
54
+ */
55
+ androidDeviceSocket?: string | null;
56
+ /**
57
+ * whether to check for webview page presence
58
+ */
59
+ ensureWebviewsHavePages?: boolean | null;
60
+ /**
61
+ * port to use for webview page presence check.
62
+ */
63
+ webviewDevtoolsPort?: number | null;
64
+ /**
65
+ * whether to collect web view details and send them to Chromedriver constructor, so it could select a binary more precisely based on this info.
66
+ */
67
+ enableWebviewDetailsCollection?: boolean | null;
68
+ /**
69
+ * @privateRemarks This is referenced but was not previously declared
70
+ */
71
+ isChromeSession?: boolean;
72
+ }
73
+
74
+ export interface ProcessInfo {
75
+ /**
76
+ * The process name
77
+ */
78
+ name: string;
79
+ /**
80
+ * The process id (if could be retrieved)
81
+ */
82
+ id?: string | null;
83
+ }
84
+
85
+ export interface WebViewDetails {
86
+ /**
87
+ * Web view process details
88
+ */
89
+ process?: ProcessInfo | null;
90
+ /**
91
+ * Web view details as returned by /json/version CDP endpoint
92
+ * @example
93
+ * {
94
+ * "Browser": "Chrome/72.0.3601.0",
95
+ * "Protocol-Version": "1.3",
96
+ * "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3601.0 Safari/537.36",
97
+ * "V8-Version": "7.2.233",
98
+ * "WebKit-Version": "537.36 (@cfede9db1d154de0468cb0538479f34c0755a0f4)",
99
+ * "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/b0b8a4fb-bb17-4359-9533-a8d9f3908bd8"
100
+ * }
101
+ */
102
+ info?: StringRecord;
103
+ }
104
+
105
+ /**
106
+ * @deprecated
107
+ */
108
+ export type TADB = ADB;
109
+
110
+ /**
111
+ * XXX Placeholder for ADB options
112
+ */
113
+ export type TADBOptions = any;
114
+
115
+ export interface FastUnlockOptions {
116
+ credential: string;
117
+ /**
118
+ * @privateRemarks FIXME: narrow this type to whatever `appium-adb` expects
119
+ */
120
+ credentialType: string;
121
+ }
122
+
123
+ /**
124
+ * XXX May be wrong
125
+ */
126
+ export interface ADBDeviceInfo {
127
+ udid: string;
128
+ emPort: number | false;
129
+ }
130
+
131
+ export type ADBLaunchInfo = Pick<
132
+ AndroidDriverCaps,
133
+ 'appPackage' | 'appWaitActivity' | 'appActivity' | 'appWaitPackage'
134
+ >;
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Unlocking helpers
3
+ * @module
4
+ */
5
+
6
+ import {util} from '@appium/support';
7
+ import type {Capabilities, Position, StringRecord} from '@appium/types';
8
+ import {sleep} from 'asyncbox';
9
+ import _ from 'lodash';
10
+ import type {AndroidDriver} from '../driver';
11
+ import type {AndroidDriverConstraints} from '../constraints';
12
+ import logger from '../logger';
13
+ import type {FastUnlockOptions} from './types';
14
+ import ADB from 'appium-adb';
15
+ import {TouchAction} from '../commands/types';
16
+
17
+ const PIN_UNLOCK = 'pin';
18
+ const PIN_UNLOCK_KEY_EVENT = 'pinWithKeyEvent';
19
+ const PASSWORD_UNLOCK = 'password';
20
+ const PATTERN_UNLOCK = 'pattern';
21
+ const FINGERPRINT_UNLOCK = 'fingerprint';
22
+ const UNLOCK_TYPES = [
23
+ PIN_UNLOCK,
24
+ PIN_UNLOCK_KEY_EVENT,
25
+ PASSWORD_UNLOCK,
26
+ PATTERN_UNLOCK,
27
+ FINGERPRINT_UNLOCK,
28
+ ] as const;
29
+ const KEYCODE_NUMPAD_ENTER = 66;
30
+ const UNLOCK_WAIT_TIME = 100;
31
+ const INPUT_KEYS_WAIT_TIME = 100;
32
+ const NUMBER_ZERO_KEYCODE = 7;
33
+
34
+ interface UnlockHelpers {
35
+ validateUnlockCapabilities: <C extends AndroidDriverConstraints>(
36
+ caps: Capabilities<C>
37
+ ) => Capabilities<C>;
38
+ fastUnlock(adb: ADB, opts: FastUnlockOptions): Promise<void>;
39
+ encodePassword(key: string): string;
40
+ stringKeyToArr(key: any): string[];
41
+ fingerprintUnlock<C extends AndroidDriverConstraints>(
42
+ adb: ADB,
43
+ driver: AndroidDriver,
44
+ capabilities: Capabilities<C>
45
+ ): Promise<void>;
46
+ pinUnlock<C extends AndroidDriverConstraints>(
47
+ adb: ADB,
48
+ driver: AndroidDriver,
49
+ capabilities: Capabilities<C>
50
+ ): Promise<void>;
51
+ pinUnlockWithKeyEvent<C extends AndroidDriverConstraints>(
52
+ adb: ADB,
53
+ driver: AndroidDriver,
54
+ capabilities: Capabilities<C>
55
+ ): Promise<void>;
56
+ passwordUnlock<C extends AndroidDriverConstraints>(
57
+ adb: ADB,
58
+ driver: AndroidDriver,
59
+ capabilities: Capabilities<C>
60
+ ): Promise<void>;
61
+ getPatternKeyPosition(key: number, initPos: Position, piece: number): Position;
62
+ getPatternActions(keys: string[] | number[], initPos: Position, piece: number): TouchAction[];
63
+ patternUnlock<C extends AndroidDriverConstraints>(
64
+ adb: ADB,
65
+ driver: AndroidDriver,
66
+ capabilities: Capabilities<C>
67
+ ): Promise<void>;
68
+ }
69
+
70
+ function isNonEmptyString(value: any): value is string {
71
+ return typeof value === 'string' && value !== '';
72
+ }
73
+
74
+ /**
75
+ * Wait for the display to be unlocked.
76
+ * Some devices automatically accept typed 'pin' and 'password' code
77
+ * without pressing the Enter key. But some devices need it.
78
+ * This method waits a few seconds first for such automatic acceptance case.
79
+ * If the device is still locked, then this method will try to send
80
+ * the enter key code.
81
+ *
82
+ * @param adb The instance of ADB
83
+ */
84
+ async function waitForUnlock(adb: ADB) {
85
+ await sleep(UNLOCK_WAIT_TIME);
86
+ if (!(await adb.isScreenLocked())) {
87
+ return;
88
+ }
89
+
90
+ await adb.keyevent(KEYCODE_NUMPAD_ENTER);
91
+ await sleep(UNLOCK_WAIT_TIME);
92
+ }
93
+
94
+ const UnlockHelpers: UnlockHelpers = {
95
+ validateUnlockCapabilities(caps) {
96
+ const {unlockKey, unlockType} = (caps ?? {}) as Capabilities<AndroidDriverConstraints>;
97
+ if (!isNonEmptyString(unlockType)) {
98
+ throw new Error('A non-empty unlock key value must be provided');
99
+ }
100
+
101
+ if ([PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, FINGERPRINT_UNLOCK].includes(unlockType)) {
102
+ if (!/^[0-9]+$/.test(_.trim(unlockKey))) {
103
+ throw new Error(`Unlock key value '${unlockKey}' must only consist of digits`);
104
+ }
105
+ } else if (unlockType === PATTERN_UNLOCK) {
106
+ if (!/^[1-9]{2,9}$/.test(_.trim(unlockKey))) {
107
+ throw new Error(
108
+ `Unlock key value '${unlockKey}' must only include from two to nine digits in range 1..9`
109
+ );
110
+ }
111
+ if (/([1-9]).*?\1/.test(_.trim(unlockKey))) {
112
+ throw new Error(
113
+ `Unlock key value '${unlockKey}' must define a valid pattern where repeats are not allowed`
114
+ );
115
+ }
116
+ } else if (unlockType === PASSWORD_UNLOCK) {
117
+ // Dont trim password key, you can use blank spaces in your android password
118
+ // ¯\_(ツ)_/¯
119
+ if (!/.{4,}/g.test(String(unlockKey))) {
120
+ throw new Error(
121
+ `The minimum allowed length of unlock key value '${unlockKey}' is 4 characters`
122
+ );
123
+ }
124
+ } else {
125
+ throw new Error(
126
+ `Invalid unlock type '${unlockType}'. ` +
127
+ `Only the following unlock types are supported: ${UNLOCK_TYPES}`
128
+ );
129
+ }
130
+ return caps;
131
+ },
132
+
133
+ async fastUnlock(adb, opts) {
134
+ const {credential, credentialType} = opts;
135
+ logger.info(`Unlocking the device via ADB using ${credentialType} credential '${credential}'`);
136
+ const wasLockEnabled = await adb.isLockEnabled();
137
+ if (wasLockEnabled) {
138
+ await adb.clearLockCredential(credential);
139
+ // not sure why, but the device's screen still remains locked
140
+ // if a preliminary wake up cycle has not been performed
141
+ await adb.cycleWakeUp();
142
+ } else {
143
+ logger.info('No active lock has been detected. Proceeding to the keyguard dismissal');
144
+ }
145
+ try {
146
+ await adb.dismissKeyguard();
147
+ } finally {
148
+ if (wasLockEnabled) {
149
+ await adb.setLockCredential(credentialType, credential);
150
+ }
151
+ }
152
+ },
153
+
154
+ encodePassword(key) {
155
+ return `${key}`.replace(/\s/gi, '%s');
156
+ },
157
+
158
+ stringKeyToArr(key) {
159
+ return `${key}`.trim().replace(/\s+/g, '').split(/\s*/);
160
+ },
161
+
162
+ async fingerprintUnlock(adb, driver, capabilities) {
163
+ if ((await adb.getApiLevel()) < 23) {
164
+ throw new Error('Fingerprint unlock only works for Android 6+ emulators');
165
+ }
166
+ await adb.fingerprint(String(capabilities.unlockKey));
167
+ await sleep(UNLOCK_WAIT_TIME);
168
+ },
169
+
170
+ async pinUnlock(adb, driver, capabilities) {
171
+ logger.info(`Trying to unlock device using pin ${capabilities.unlockKey}`);
172
+ await adb.dismissKeyguard();
173
+ const keys = this.stringKeyToArr(capabilities.unlockKey);
174
+ if ((await adb.getApiLevel()) >= 21) {
175
+ const els = await driver.findElOrEls('id', 'com.android.systemui:id/digit_text', true);
176
+ if (_.isEmpty(els)) {
177
+ // fallback to pin with key event
178
+ return await this.pinUnlockWithKeyEvent(adb, driver, capabilities);
179
+ }
180
+ const pins: StringRecord = {};
181
+ for (const el of els) {
182
+ const text = await driver.getAttribute('text', util.unwrapElement(el));
183
+ pins[text] = el;
184
+ }
185
+ for (const pin of keys) {
186
+ const el = pins[pin];
187
+ await driver.click(util.unwrapElement(el));
188
+ }
189
+ } else {
190
+ for (const pin of keys) {
191
+ const el = await driver.findElOrEls('id', `com.android.keyguard:id/key${pin}`, false);
192
+ if (el === null) {
193
+ // fallback to pin with key event
194
+ return await this.pinUnlockWithKeyEvent(adb, driver, capabilities);
195
+ }
196
+ await driver.click(util.unwrapElement(el));
197
+ }
198
+ }
199
+ await waitForUnlock(adb);
200
+ },
201
+
202
+ async pinUnlockWithKeyEvent(adb, driver, capabilities) {
203
+ logger.info(`Trying to unlock device using pin with keycode ${capabilities.unlockKey}`);
204
+ await adb.dismissKeyguard();
205
+ const keys = this.stringKeyToArr(capabilities.unlockKey);
206
+
207
+ // Some device does not have system key ids like 'com.android.keyguard:id/key'
208
+ // Then, sending keyevents are more reliable to unlock the screen.
209
+ for (const pin of keys) {
210
+ // 'pin' is number (0-9) in string.
211
+ // Number '0' is keycode '7'. number '9' is keycode '16'.
212
+ await adb.shell(['input', 'keyevent', String(parseInt(pin, 10) + NUMBER_ZERO_KEYCODE)]);
213
+ }
214
+ await waitForUnlock(adb);
215
+ },
216
+
217
+ async passwordUnlock(adb, driver, capabilities) {
218
+ const {unlockKey} = capabilities;
219
+ logger.info(`Trying to unlock device using password ${unlockKey}`);
220
+ await adb.dismissKeyguard();
221
+ // Replace blank spaces with %s
222
+ const key = this.encodePassword(unlockKey as string);
223
+ // Why adb ? It was less flaky
224
+ await adb.shell(['input', 'text', key]);
225
+ // Why sleeps ? Avoid some flakyness waiting for the input to receive the keys
226
+ await sleep(INPUT_KEYS_WAIT_TIME);
227
+ await adb.shell(['input', 'keyevent', String(KEYCODE_NUMPAD_ENTER)]);
228
+ // Waits a bit for the device to be unlocked
229
+ await waitForUnlock(adb);
230
+ },
231
+
232
+ getPatternKeyPosition(key, initPos, piece) {
233
+ /*
234
+ How the math works:
235
+ We have 9 buttons divided in 3 columns and 3 rows inside the lockPatternView,
236
+ every button has a position on the screen corresponding to the lockPatternView since
237
+ it is the parent view right at the middle of each column or row.
238
+ */
239
+ const cols = 3;
240
+ const pins = 9;
241
+ const xPos = (key: number, x: number, piece: number) =>
242
+ Math.round(x + (key % cols || cols) * piece - piece / 2);
243
+ const yPos = (key: number, y: number, piece: number) =>
244
+ Math.round(y + (Math.ceil((key % pins || pins) / cols) * piece - piece / 2));
245
+ return {
246
+ x: xPos(key, initPos.x, piece),
247
+ y: yPos(key, initPos.y, piece),
248
+ };
249
+ },
250
+
251
+ getPatternActions(keys, initPos, piece) {
252
+ const actions: TouchAction[] = [];
253
+ keys = keys.map((key: string | number) => (_.isString(key) ? _.parseInt(key) : key));
254
+ let lastPos: Position;
255
+ for (const key of keys) {
256
+ const keyPos = UnlockHelpers.getPatternKeyPosition(key, initPos, piece);
257
+ if (key === keys[0]) {
258
+ actions.push({action: 'press', options: {element: undefined, x: keyPos.x, y: keyPos.y}});
259
+ lastPos = keyPos;
260
+ continue;
261
+ }
262
+ const moveTo = {x: 0, y: 0};
263
+ const diffX = keyPos.x - lastPos!.x;
264
+ if (diffX > 0) {
265
+ moveTo.x = piece;
266
+ if (Math.abs(diffX) > piece) {
267
+ moveTo.x += piece;
268
+ }
269
+ } else if (diffX < 0) {
270
+ moveTo.x = -1 * piece;
271
+ if (Math.abs(diffX) > piece) {
272
+ moveTo.x -= piece;
273
+ }
274
+ }
275
+ const diffY = keyPos.y - lastPos!.y;
276
+ if (diffY > 0) {
277
+ moveTo.y = piece;
278
+ if (Math.abs(diffY) > piece) {
279
+ moveTo.y += piece;
280
+ }
281
+ } else if (diffY < 0) {
282
+ moveTo.y = -1 * piece;
283
+ if (Math.abs(diffY) > piece) {
284
+ moveTo.y -= piece;
285
+ }
286
+ }
287
+ actions.push({
288
+ action: 'moveTo',
289
+ options: {element: undefined, x: moveTo.x + lastPos!.x, y: moveTo.y + lastPos!.y},
290
+ });
291
+ lastPos = keyPos;
292
+ }
293
+ actions.push({action: 'release'});
294
+ return actions;
295
+ },
296
+
297
+ async patternUnlock(adb, driver, capabilities) {
298
+ const {unlockKey} = capabilities;
299
+ logger.info(`Trying to unlock device using pattern ${unlockKey}`);
300
+ await adb.dismissKeyguard();
301
+ const keys = this.stringKeyToArr(unlockKey);
302
+ /* We set the device pattern buttons as number of a regular phone
303
+ * | • • • | | 1 2 3 |
304
+ * | • • • | --> | 4 5 6 |
305
+ * | • • • | | 7 8 9 |
306
+
307
+ The pattern view buttons are not seeing by the uiautomator since they are
308
+ included inside a FrameLayout, so we are going to try clicking on the buttons
309
+ using the parent view bounds and math.
310
+ */
311
+ const apiLevel = await adb.getApiLevel();
312
+ const el = await driver.findElOrEls(
313
+ 'id',
314
+ `com.android.${apiLevel >= 21 ? 'systemui' : 'keyguard'}:id/lockPatternView`,
315
+ false
316
+ );
317
+ const initPos = await driver.getLocation(util.unwrapElement(el));
318
+ const size = await driver.getSize(util.unwrapElement(el));
319
+ // Get actions to perform
320
+ const actions = UnlockHelpers.getPatternActions(keys, initPos, size.width / 3);
321
+ // Perform gesture
322
+ await driver.performTouch(actions);
323
+ // Waits a bit for the device to be unlocked
324
+ await sleep(UNLOCK_WAIT_TIME);
325
+ },
326
+ };
327
+
328
+ export {FINGERPRINT_UNLOCK, PASSWORD_UNLOCK, PATTERN_UNLOCK, PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT};
329
+ export default UnlockHelpers;