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,10 +1,11 @@
1
+ // @ts-check
2
+
3
+ import {mixin} from './mixins';
1
4
  import _ from 'lodash';
2
- import { errors } from 'appium/driver';
3
- import { util } from 'appium/support';
5
+ import {errors} from 'appium/driver';
6
+ import {util} from 'appium/support';
4
7
  import B from 'bluebird';
5
8
 
6
- let commands = {}, helpers = {}, extensions = {};
7
-
8
9
  const AIRPLANE_MODE_MASK = 0b001;
9
10
  const WIFI_MASK = 0b010;
10
11
  const DATA_MASK = 0b100;
@@ -17,313 +18,283 @@ const GEO_EPSILON = Number.MIN_VALUE;
17
18
  const WIFI_KEY_NAME = 'wifi';
18
19
  const DATA_KEY_NAME = 'data';
19
20
  const AIRPLANE_MODE_KEY_NAME = 'airplaneMode';
20
- const SUPPORTED_SERVICE_NAMES = [WIFI_KEY_NAME, DATA_KEY_NAME, AIRPLANE_MODE_KEY_NAME];
21
-
22
- commands.getNetworkConnection = async function getNetworkConnection () {
23
- this.log.info('Getting network connection');
24
- let airplaneModeOn = await this.adb.isAirplaneModeOn();
25
- let connection = airplaneModeOn ? AIRPLANE_MODE_MASK : 0;
26
-
27
- // no need to check anything else if we are in airplane mode
28
- if (!airplaneModeOn) {
29
- let wifiOn = await this.isWifiOn();
30
- connection |= (wifiOn ? WIFI_MASK : 0);
31
- let dataOn = await this.adb.isDataOn();
32
- connection |= (dataOn ? DATA_MASK : 0);
33
- }
34
-
35
- return connection;
36
- };
21
+ const SUPPORTED_SERVICE_NAMES = /** @type {const} */ ([
22
+ WIFI_KEY_NAME,
23
+ DATA_KEY_NAME,
24
+ AIRPLANE_MODE_KEY_NAME,
25
+ ]);
37
26
 
38
27
  /**
39
- * decoupling to override the behaviour in other drivers like UiAutomator2.
28
+ * @type {import('./mixins').NetworkMixin & ThisType<import('../driver').AndroidDriver>}
29
+ * @satisfies {import('@appium/types').ExternalDriver}
40
30
  */
41
- commands.isWifiOn = async function isWifiOn () {
42
- return await this.adb.isWifiOn();
43
- };
31
+ const NetworkMixin = {
32
+ async getNetworkConnection() {
33
+ const adb = /** @type {ADB} */ (this.adb);
34
+ this.log.info('Getting network connection');
35
+ let airplaneModeOn = await adb.isAirplaneModeOn();
36
+ let connection = airplaneModeOn ? AIRPLANE_MODE_MASK : 0;
37
+
38
+ // no need to check anything else if we are in airplane mode
39
+ if (!airplaneModeOn) {
40
+ let wifiOn = await this.isWifiOn();
41
+ connection |= wifiOn ? WIFI_MASK : 0;
42
+ let dataOn = await adb.isDataOn();
43
+ connection |= dataOn ? DATA_MASK : 0;
44
+ }
44
45
 
45
- /**
46
- * @typedef {Object} SetConnectivityOptions
47
- * @property {boolean?} wifi Either to enable or disable Wi-Fi.
48
- * An unset value means to not change the state for the given service.
49
- * @property {boolean?} data Either to enable or disable mobile data connection.
50
- * An unset value means to not change the state for the given service.
51
- * @property {boolean?} airplaneMode Either to enable to disable the Airplane Mode
52
- * An unset value means to not change the state for the given service.
53
- */
46
+ return connection;
47
+ },
54
48
 
55
- /**
56
- * Set the connectivity state for different services
57
- *
58
- * @param {SetConnectivityOptions} opts
59
- * @throws {Error} If none of known properties were provided or there was an error
60
- * while changing connectivity states
61
- */
62
- commands.mobileSetConnectivity = async function mobileSetConnectivity (opts = {}) {
63
- const {
64
- wifi,
65
- data,
66
- airplaneMode,
67
- } = opts;
49
+ async isWifiOn() {
50
+ return await /** @type {ADB} */ (this.adb).isWifiOn();
51
+ },
68
52
 
69
- if (_.every([wifi, data, airplaneMode], _.isUndefined)) {
70
- throw new errors.InvalidArgumentError(
71
- `Either one of ${JSON.stringify(SUPPORTED_SERVICE_NAMES)} options must be provided`
72
- );
73
- }
53
+ async mobileSetConnectivity(opts = {}) {
54
+ const {wifi, data, airplaneMode} = opts;
55
+ const adb = /** @type {ADB} */ (this.adb);
56
+ if (_.every([wifi, data, airplaneMode], _.isUndefined)) {
57
+ throw new errors.InvalidArgumentError(
58
+ `Either one of ${JSON.stringify(SUPPORTED_SERVICE_NAMES)} options must be provided`
59
+ );
60
+ }
74
61
 
75
- const currentState = await this.mobileGetConnectivity({
76
- services: [
77
- ...(_.isUndefined(wifi) ? [] : [WIFI_KEY_NAME]),
78
- ...(_.isUndefined(data) ? [] : [DATA_KEY_NAME]),
79
- ...(_.isUndefined(airplaneMode) ? [] : [AIRPLANE_MODE_KEY_NAME]),
80
- ]
81
- });
82
- const setters = [];
83
- if (!_.isUndefined(wifi) && currentState.wifi !== Boolean(wifi)) {
84
- setters.push(this.adb.setWifiState(wifi, this.isEmulator()));
85
- }
86
- if (!_.isUndefined(data) && currentState.data !== Boolean(data)) {
87
- setters.push(this.adb.setDataState(data, this.isEmulator()));
88
- }
89
- if (!_.isUndefined(airplaneMode) && currentState.airplaneMode !== Boolean(airplaneMode)) {
90
- setters.push(async () => {
91
- await this.adb.setAirplaneMode(airplaneMode);
92
- if (this.adb.getApiLevel() < 30) {
93
- await this.adb.broadcastAirplaneMode(airplaneMode);
94
- }
62
+ const currentState = await this.mobileGetConnectivity({
63
+ services: /** @type {import('./types').ServiceType[]} */ ([
64
+ ...(_.isUndefined(wifi) ? [] : [WIFI_KEY_NAME]),
65
+ ...(_.isUndefined(data) ? [] : [DATA_KEY_NAME]),
66
+ ...(_.isUndefined(airplaneMode) ? [] : [AIRPLANE_MODE_KEY_NAME]),
67
+ ]),
95
68
  });
96
- }
97
- if (!_.isEmpty(setters)) {
98
- await B.all(setters);
99
- }
100
- };
69
+ /** @type {(Promise<any>|(() => Promise<any>))[]} */
70
+ const setters = [];
71
+ if (!_.isUndefined(wifi) && currentState.wifi !== Boolean(wifi)) {
72
+ setters.push(adb.setWifiState(wifi, this.isEmulator()));
73
+ }
74
+ if (!_.isUndefined(data) && currentState.data !== Boolean(data)) {
75
+ setters.push(adb.setDataState(data, this.isEmulator()));
76
+ }
77
+ if (!_.isUndefined(airplaneMode) && currentState.airplaneMode !== Boolean(airplaneMode)) {
78
+ setters.push(async () => {
79
+ await adb.setAirplaneMode(airplaneMode);
80
+ if ((await adb.getApiLevel()) < 30) {
81
+ await adb.broadcastAirplaneMode(airplaneMode);
82
+ }
83
+ });
84
+ }
85
+ if (!_.isEmpty(setters)) {
86
+ await B.all(setters);
87
+ }
88
+ },
89
+
90
+ async mobileGetConnectivity(opts = {}) {
91
+ let {services = SUPPORTED_SERVICE_NAMES} = opts;
92
+ const svcs = _.castArray(services);
93
+ const unsupportedServices = _.difference(services, SUPPORTED_SERVICE_NAMES);
94
+ if (!_.isEmpty(unsupportedServices)) {
95
+ throw new errors.InvalidArgumentError(
96
+ `${util.pluralize(
97
+ 'Service name',
98
+ unsupportedServices.length,
99
+ false
100
+ )} ${unsupportedServices} ` +
101
+ `${
102
+ unsupportedServices.length === 1 ? 'is' : 'are'
103
+ } not known. Only the following services are ` +
104
+ `suported: ${SUPPORTED_SERVICE_NAMES}`
105
+ );
106
+ }
107
+ const adb = /** @type {ADB} */ (this.adb);
108
+
109
+ const statePromises = {
110
+ wifi: B.resolve(svcs.includes(WIFI_KEY_NAME) ? adb.isWifiOn() : undefined),
111
+ data: B.resolve(svcs.includes(DATA_KEY_NAME) ? adb.isDataOn() : undefined),
112
+ airplaneMode: B.resolve(
113
+ svcs.includes(AIRPLANE_MODE_KEY_NAME) ? adb.isAirplaneModeOn() : undefined
114
+ ),
115
+ };
116
+ await B.all(_.values(statePromises));
117
+ return {
118
+ wifi: Boolean(statePromises.wifi.value()),
119
+ data: Boolean(statePromises.data.value()),
120
+ airplaneMode: Boolean(statePromises.airplaneMode.value()),
121
+ };
122
+ },
123
+
124
+ async setNetworkConnection(type) {
125
+ this.log.info('Setting network connection');
126
+ // decode the input
127
+ const shouldEnableAirplaneMode = (type & AIRPLANE_MODE_MASK) !== 0;
128
+ const shouldEnableWifi = (type & WIFI_MASK) !== 0;
129
+ const shouldEnableDataConnection = (type & DATA_MASK) !== 0;
130
+
131
+ const currentState = await this.getNetworkConnection();
132
+ const isAirplaneModeEnabled = (currentState & AIRPLANE_MODE_MASK) !== 0;
133
+ const isWiFiEnabled = (currentState & WIFI_MASK) !== 0;
134
+ const isDataEnabled = (currentState & DATA_MASK) !== 0;
135
+
136
+ const adb = /** @type {ADB} */ (this.adb);
137
+ if (shouldEnableAirplaneMode !== isAirplaneModeEnabled) {
138
+ await this.wrapBootstrapDisconnect(async () => {
139
+ await adb.setAirplaneMode(shouldEnableAirplaneMode);
140
+ });
141
+ await this.wrapBootstrapDisconnect(async () => {
142
+ if ((await adb.getApiLevel()) < 30) {
143
+ await adb.broadcastAirplaneMode(shouldEnableAirplaneMode);
144
+ }
145
+ });
146
+ } else {
147
+ this.log.info(
148
+ `Not changing airplane mode, since it is already ${
149
+ shouldEnableAirplaneMode ? 'enabled' : 'disabled'
150
+ }`
151
+ );
152
+ }
101
153
 
102
- /**
103
- * @typedef {Object} GetConnectivityResult
104
- * @property {boolean} wifi True if wifi is enabled
105
- * @property {boolean} data True if mobile data connection is enabled
106
- * @property {boolean} airplaneMode True if Airplane Mode is enabled
107
- */
154
+ if (shouldEnableWifi === isWiFiEnabled && shouldEnableDataConnection === isDataEnabled) {
155
+ this.log.info(
156
+ 'Not changing data connection/Wi-Fi states, since they are already set to expected values'
157
+ );
158
+ if (await adb.isAirplaneModeOn()) {
159
+ return AIRPLANE_MODE_MASK | currentState;
160
+ }
161
+ return ~AIRPLANE_MODE_MASK & currentState;
162
+ }
108
163
 
109
- /**
110
- * @typedef {Object} GetConnectivityOptions
111
- * @property {string[]|string?} services one or more services to get the connectivity for.
112
- * Supported service names are: wifi, data, airplaneMode.
113
- */
164
+ await this.wrapBootstrapDisconnect(async () => {
165
+ if (shouldEnableWifi !== isWiFiEnabled) {
166
+ await this.setWifiState(shouldEnableWifi);
167
+ } else {
168
+ this.log.info(
169
+ `Not changing Wi-Fi state, since it is already ` +
170
+ `${shouldEnableWifi ? 'enabled' : 'disabled'}`
171
+ );
172
+ }
114
173
 
115
- /**
116
- * Retrieves the connectivity properties from the device under test
117
- *
118
- * @param {GetConnectivityOptions?} opts If no service names are provided then the
119
- * connectivity state is returned for all of them.
120
- * @returns {GetConnectivityResult}
121
- */
122
- commands.mobileGetConnectivity = async function mobileGetConnectivity (opts = {}) {
123
- let {
124
- services = SUPPORTED_SERVICE_NAMES,
125
- } = opts;
126
- if (!_.isArray(services)) {
127
- services = [services];
128
- }
129
- const unsupportedServices = _.difference(services, SUPPORTED_SERVICE_NAMES);
130
- if (!_.isEmpty(unsupportedServices)) {
131
- throw new errors.InvalidArgumentError(
132
- `${util.pluralize('Service name', unsupportedServices.length, false)} ${unsupportedServices} ` +
133
- `${unsupportedServices.length === 1 ? 'is' : 'are'} not known. Only the following services are ` +
134
- `suported: ${SUPPORTED_SERVICE_NAMES}`
135
- );
136
- }
174
+ if (shouldEnableAirplaneMode) {
175
+ this.log.info('Not changing data connection state, because airplane mode is enabled');
176
+ } else if (shouldEnableDataConnection === isDataEnabled) {
177
+ this.log.info(
178
+ `Not changing data connection state, since it is already ` +
179
+ `${shouldEnableDataConnection ? 'enabled' : 'disabled'}`
180
+ );
181
+ } else {
182
+ await adb.setDataState(shouldEnableDataConnection, this.isEmulator());
183
+ }
184
+ });
137
185
 
138
- const statePromises = {
139
- wifi: B.resolve(services.includes(WIFI_KEY_NAME) ? this.adb.isWifiOn() : undefined),
140
- data: B.resolve(services.includes(DATA_KEY_NAME) ? this.adb.isDataOn() : undefined),
141
- airplaneMode: B.resolve(
142
- services.includes(AIRPLANE_MODE_KEY_NAME) ? this.adb.isAirplaneModeOn() : undefined
143
- ),
144
- };
145
- await B.all(_.values(statePromises));
146
- return _.fromPairs(services.map((k) => [k, statePromises[k].value()]));
147
- };
186
+ return await this.getNetworkConnection();
187
+ },
148
188
 
149
- commands.setNetworkConnection = async function setNetworkConnection (type) {
150
- this.log.info('Setting network connection');
151
- // decode the input
152
- const shouldEnableAirplaneMode = (type & AIRPLANE_MODE_MASK) !== 0;
153
- const shouldEnableWifi = (type & WIFI_MASK) !== 0;
154
- const shouldEnableDataConnection = (type & DATA_MASK) !== 0;
189
+ async setWifiState(wifi) {
190
+ await /** @type {ADB} */ (this.adb).setWifiState(wifi, this.isEmulator());
191
+ },
155
192
 
156
- const currentState = await this.getNetworkConnection();
157
- const isAirplaneModeEnabled = (currentState & AIRPLANE_MODE_MASK) !== 0;
158
- const isWiFiEnabled = (currentState & WIFI_MASK) !== 0;
159
- const isDataEnabled = (currentState & DATA_MASK) !== 0;
193
+ async toggleData() {
194
+ const adb = /** @type {ADB} */ (this.adb);
195
+ let data = !(await adb.isDataOn());
196
+ this.log.info(`Turning network data ${data ? 'on' : 'off'}`);
197
+ await this.wrapBootstrapDisconnect(async () => {
198
+ await adb.setWifiAndData({data}, this.isEmulator());
199
+ });
200
+ },
160
201
 
161
- if (shouldEnableAirplaneMode !== isAirplaneModeEnabled) {
202
+ async toggleWiFi() {
203
+ const adb = /** @type {ADB} */ (this.adb);
204
+ let wifi = !(await adb.isWifiOn());
205
+ this.log.info(`Turning WiFi ${wifi ? 'on' : 'off'}`);
206
+ await this.wrapBootstrapDisconnect(async () => {
207
+ await adb.setWifiAndData({wifi}, this.isEmulator());
208
+ });
209
+ },
210
+
211
+ async toggleFlightMode() {
212
+ const adb = /** @type {ADB} */ (this.adb);
213
+ /*
214
+ * TODO: Implement isRealDevice(). This method fails on
215
+ * real devices, it should throw a NotYetImplementedError
216
+ */
217
+ let flightMode = !(await adb.isAirplaneModeOn());
218
+ this.log.info(`Turning flight mode ${flightMode ? 'on' : 'off'}`);
162
219
  await this.wrapBootstrapDisconnect(async () => {
163
- await this.adb.setAirplaneMode(shouldEnableAirplaneMode);
220
+ await adb.setAirplaneMode(flightMode);
164
221
  });
165
222
  await this.wrapBootstrapDisconnect(async () => {
166
- if (await this.adb.getApiLevel() < 30) {
167
- await this.adb.broadcastAirplaneMode(shouldEnableAirplaneMode);
223
+ if ((await adb.getApiLevel()) < 30) {
224
+ await adb.broadcastAirplaneMode(flightMode);
168
225
  }
169
226
  });
170
- } else {
171
- this.log.info(
172
- `Not changing airplane mode, since it is already ${shouldEnableAirplaneMode ? 'enabled' : 'disabled'}`
173
- );
174
- }
175
-
176
- if (shouldEnableWifi === isWiFiEnabled && shouldEnableDataConnection === isDataEnabled) {
177
- this.log.info('Not changing data connection/Wi-Fi states, since they are already set to expected values');
178
- if (await this.adb.isAirplaneModeOn()) {
179
- return AIRPLANE_MODE_MASK | currentState;
180
- }
181
- return ~AIRPLANE_MODE_MASK & currentState;
182
- }
183
-
184
- await this.wrapBootstrapDisconnect(async () => {
185
- if (shouldEnableWifi !== isWiFiEnabled) {
186
- await this.setWifiState(shouldEnableWifi);
187
- } else {
188
- this.log.info(`Not changing Wi-Fi state, since it is already ` +
189
- `${shouldEnableWifi ? 'enabled' : 'disabled'}`);
190
- }
191
-
192
- if (shouldEnableAirplaneMode) {
193
- this.log.info('Not changing data connection state, because airplane mode is enabled');
194
- } else if (shouldEnableDataConnection === isDataEnabled) {
195
- this.log.info(`Not changing data connection state, since it is already ` +
196
- `${shouldEnableDataConnection ? 'enabled' : 'disabled'}`);
197
- } else {
198
- await this.adb.setDataState(shouldEnableDataConnection, this.isEmulator());
227
+ },
228
+
229
+ async setGeoLocation(location) {
230
+ await /** @type {ADB} */ (this.adb).setGeoLocation(location, this.isEmulator());
231
+ try {
232
+ return await this.getGeoLocation();
233
+ } catch (e) {
234
+ this.log.warn(
235
+ `Could not get the current geolocation info: ${/** @type {Error} */ (e).message}`
236
+ );
237
+ this.log.warn(`Returning the default zero'ed values`);
238
+ return {
239
+ latitude: GEO_EPSILON,
240
+ longitude: GEO_EPSILON,
241
+ altitude: GEO_EPSILON,
242
+ };
199
243
  }
200
- });
201
-
202
- return await this.getNetworkConnection();
203
- };
204
-
205
- /**
206
- * decoupling to override behaviour in other drivers like UiAutomator2.
207
- */
208
- commands.setWifiState = async function setWifiState (wifi) {
209
- await this.adb.setWifiState(wifi, this.isEmulator());
210
- };
211
-
212
- commands.toggleData = async function toggleData () {
213
- let data = !(await this.adb.isDataOn());
214
- this.log.info(`Turning network data ${data ? 'on' : 'off'}`);
215
- await this.wrapBootstrapDisconnect(async () => {
216
- await this.adb.setWifiAndData({data}, this.isEmulator());
217
- });
218
- };
219
-
220
- commands.toggleWiFi = async function toggleWiFi () {
221
- let wifi = !(await this.adb.isWifiOn());
222
- this.log.info(`Turning WiFi ${wifi ? 'on' : 'off'}`);
223
- await this.wrapBootstrapDisconnect(async () => {
224
- await this.adb.setWifiAndData({wifi}, this.isEmulator());
225
- });
226
- };
244
+ },
227
245
 
228
- commands.toggleFlightMode = async function toggleFlightMode () {
229
- /*
230
- * TODO: Implement isRealDevice(). This method fails on
231
- * real devices, it should throw a NotYetImplementedError
232
- */
233
- let flightMode = !(await this.adb.isAirplaneModeOn());
234
- this.log.info(`Turning flight mode ${flightMode ? 'on' : 'off'}`);
235
- await this.wrapBootstrapDisconnect(async () => {
236
- await this.adb.setAirplaneMode(flightMode);
237
- });
238
- await this.wrapBootstrapDisconnect(async () => {
239
- if (await this.adb.getApiLevel() < 30) {
240
- await this.adb.broadcastAirplaneMode(flightMode);
241
- }
242
- });
243
- };
246
+ async mobileRefreshGpsCache(opts = {}) {
247
+ const {timeoutMs} = opts;
248
+ await /** @type {ADB} */ (this.adb).refreshGeoLocationCache(timeoutMs);
249
+ },
244
250
 
245
- commands.setGeoLocation = async function setGeoLocation (location) {
246
- await this.adb.setGeoLocation(location, this.isEmulator());
247
- try {
248
- return await this.getGeoLocation();
249
- } catch (e) {
250
- this.log.warn(`Could not get the current geolocation info: ${e.message}`);
251
- this.log.warn(`Returning the default zero'ed values`);
251
+ async getGeoLocation() {
252
+ const {latitude, longitude, altitude} = await /** @type {ADB} */ (this.adb).getGeoLocation();
252
253
  return {
253
- latitude: GEO_EPSILON,
254
- longitude: GEO_EPSILON,
255
- altitude: GEO_EPSILON,
254
+ latitude: parseFloat(String(latitude)) || GEO_EPSILON,
255
+ longitude: parseFloat(String(longitude)) || GEO_EPSILON,
256
+ altitude: parseFloat(String(altitude)) || GEO_EPSILON,
256
257
  };
257
- }
258
- };
258
+ },
259
+
260
+ async isLocationServicesEnabled() {
261
+ return (await /** @type {ADB} */ (this.adb).getLocationProviders()).includes('gps');
262
+ },
263
+
264
+ async toggleLocationServices() {
265
+ this.log.info('Toggling location services');
266
+ const isGpsEnabled = await this.isLocationServicesEnabled();
267
+ this.log.debug(
268
+ `Current GPS state: ${isGpsEnabled}. ` +
269
+ `The service is going to be ${isGpsEnabled ? 'disabled' : 'enabled'}`
270
+ );
271
+ await /** @type {ADB} */ (this.adb).toggleGPSLocationProvider(!isGpsEnabled);
272
+ },
259
273
 
260
- /**
261
- * @typedef {Object} GpsCacheRefreshOptions
262
- * @property {number} timeoutMs [20000] The maximum number of milliseconds
263
- * to block until GPS cache is refreshed. Providing zero or a negative
264
- * value to it skips waiting completely.
265
- */
274
+ async wrapBootstrapDisconnect(wrapped) {
275
+ if (!this.bootstrap) {
276
+ return await wrapped();
277
+ }
266
278
 
267
- /**
268
- * Sends an async request to refresh the GPS cache.
269
- * This feature only works if the device under test has
270
- * Google Play Services installed. In case the vanilla
271
- * LocationManager is used the device API level must be at
272
- * version 30 (Android R) or higher.
273
- *
274
- * @param {GpsCacheRefreshOptions} opts
275
- */
276
- commands.mobileRefreshGpsCache = async function mobileRefreshGpsCache (opts = {}) {
277
- const { timeoutMs } = opts;
278
- await this.adb.refreshGeoLocationCache(timeoutMs);
279
+ this.bootstrap.ignoreUnexpectedShutdown = true;
280
+ try {
281
+ await wrapped();
282
+ await /** @type {ADB} */ (this.adb).restart();
283
+ await this.bootstrap.start(
284
+ this.opts.appPackage,
285
+ this.opts.disableAndroidWatchers,
286
+ this.opts.acceptSslCerts
287
+ );
288
+ } finally {
289
+ this.bootstrap.ignoreUnexpectedShutdown = false;
290
+ }
291
+ },
279
292
  };
280
293
 
281
- commands.getGeoLocation = async function getGeoLocation () {
282
- const {latitude, longitude, altitude} = await this.adb.getGeoLocation();
283
- return {
284
- latitude: parseFloat(latitude) || GEO_EPSILON,
285
- longitude: parseFloat(longitude) || GEO_EPSILON,
286
- altitude: parseFloat(altitude) || GEO_EPSILON,
287
- };
288
- };
294
+ mixin(NetworkMixin);
289
295
 
290
- /**
291
- * Checks if GPS is enabled
292
- *
293
- * @returns {Promise<Boolean>} True if yes
294
- */
295
- commands.isLocationServicesEnabled = async function iLocationServicesEnabled () {
296
- return (await this.adb.getLocationProviders()).includes('gps');
297
- };
296
+ export default NetworkMixin;
298
297
 
299
298
  /**
300
- * Toggles GPS state
299
+ * @typedef {import('appium-adb').ADB} ADB
301
300
  */
302
- commands.toggleLocationServices = async function toggleLocationServices () {
303
- this.log.info('Toggling location services');
304
- const isGpsEnabled = await this.isLocationServicesEnabled();
305
- this.log.debug(
306
- `Current GPS state: ${isGpsEnabled}. ` +
307
- `The service is going to be ${isGpsEnabled ? 'disabled' : 'enabled'}`
308
- );
309
- await this.adb.toggleGPSLocationProvider(!isGpsEnabled);
310
- };
311
-
312
- helpers.wrapBootstrapDisconnect = async function wrapBootstrapDisconnect (wrapped) {
313
- if (!this.bootstrap) {
314
- return await wrapped();
315
- }
316
-
317
- this.bootstrap.ignoreUnexpectedShutdown = true;
318
- try {
319
- await wrapped();
320
- await this.adb.restart();
321
- await this.bootstrap.start(this.opts.appPackage, this.opts.disableAndroidWatchers, this.opts.acceptSslCerts);
322
- } finally {
323
- this.bootstrap.ignoreUnexpectedShutdown = false;
324
- }
325
- };
326
-
327
- Object.assign(extensions, commands, helpers);
328
- export { commands, helpers };
329
- export default extensions;