appium-android-driver 12.6.6 → 12.7.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.
- package/CHANGELOG.md +12 -0
- package/build/lib/commands/app-management.d.ts +10 -0
- package/build/lib/commands/app-management.d.ts.map +1 -1
- package/build/lib/commands/app-management.js +21 -4
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/appearance.d.ts.map +1 -1
- package/build/lib/commands/appearance.js.map +1 -1
- package/build/lib/commands/bidi/models.d.ts.map +1 -1
- package/build/lib/commands/bidi/models.js.map +1 -1
- package/build/lib/commands/bidi/types.js +0 -1
- package/build/lib/commands/bidi/types.js.map +1 -1
- package/build/lib/commands/bluetooth.d.ts +1 -1
- package/build/lib/commands/bluetooth.d.ts.map +1 -1
- package/build/lib/commands/bluetooth.js.map +1 -1
- package/build/lib/commands/context/exports.d.ts.map +1 -1
- package/build/lib/commands/context/exports.js.map +1 -1
- package/build/lib/commands/context/helpers.d.ts.map +1 -1
- package/build/lib/commands/context/helpers.js +1 -2
- package/build/lib/commands/context/helpers.js.map +1 -1
- package/build/lib/commands/device/common.d.ts.map +1 -1
- package/build/lib/commands/device/common.js +2 -3
- package/build/lib/commands/device/common.js.map +1 -1
- package/build/lib/commands/device/emulator-actions.d.ts.map +1 -1
- package/build/lib/commands/device/emulator-actions.js.map +1 -1
- package/build/lib/commands/device/utils.d.ts.map +1 -1
- package/build/lib/commands/device/utils.js +2 -2
- package/build/lib/commands/device/utils.js.map +1 -1
- package/build/lib/commands/deviceidle.d.ts +1 -1
- package/build/lib/commands/deviceidle.d.ts.map +1 -1
- package/build/lib/commands/deviceidle.js.map +1 -1
- package/build/lib/commands/element.d.ts.map +1 -1
- package/build/lib/commands/element.js +1 -1
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/execute.d.ts.map +1 -1
- package/build/lib/commands/execute.js +1 -2
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/geolocation.d.ts.map +1 -1
- package/build/lib/commands/geolocation.js.map +1 -1
- package/build/lib/commands/gestures.d.ts.map +1 -1
- package/build/lib/commands/gestures.js.map +1 -1
- package/build/lib/commands/image-injection.d.ts.map +1 -1
- package/build/lib/commands/image-injection.js.map +1 -1
- package/build/lib/commands/ime.d.ts.map +1 -1
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/intent.d.ts.map +1 -1
- package/build/lib/commands/intent.js +2 -8
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts.map +1 -1
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/legacy.d.ts.map +1 -1
- package/build/lib/commands/legacy.js.map +1 -1
- package/build/lib/commands/lock/exports.d.ts.map +1 -1
- package/build/lib/commands/lock/exports.js.map +1 -1
- package/build/lib/commands/lock/helpers.d.ts.map +1 -1
- package/build/lib/commands/lock/helpers.js.map +1 -1
- package/build/lib/commands/log.d.ts.map +1 -1
- package/build/lib/commands/log.js +5 -3
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/misc.d.ts.map +1 -1
- package/build/lib/commands/misc.js.map +1 -1
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +1 -1
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/nfc.d.ts.map +1 -1
- package/build/lib/commands/nfc.js.map +1 -1
- package/build/lib/commands/performance.d.ts.map +1 -1
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +4 -4
- package/build/lib/commands/permissions.d.ts.map +1 -1
- package/build/lib/commands/permissions.js +1 -3
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts.map +1 -1
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/resources.js +3 -4
- package/build/lib/commands/resources.js.map +1 -1
- package/build/lib/commands/shell.d.ts.map +1 -1
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts.map +1 -1
- package/build/lib/commands/system-bars.js +4 -4
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/time.d.ts.map +1 -1
- package/build/lib/commands/time.js.map +1 -1
- package/build/lib/constraints.js +2 -2
- package/build/lib/driver.d.ts +8 -1
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +1 -0
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts +6 -0
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +38 -64
- package/build/lib/execute-method-map.js.map +1 -1
- package/build/lib/method-map.js +54 -54
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js.map +1 -1
- package/lib/commands/app-management.ts +54 -30
- package/lib/commands/appearance.ts +1 -4
- package/lib/commands/bidi/models.ts +12 -10
- package/lib/commands/bidi/types.ts +1 -1
- package/lib/commands/bluetooth.ts +3 -7
- package/lib/commands/context/cache.ts +0 -1
- package/lib/commands/context/exports.ts +3 -14
- package/lib/commands/context/helpers.ts +7 -8
- package/lib/commands/device/common.ts +51 -52
- package/lib/commands/device/emulator-actions.ts +15 -34
- package/lib/commands/device/emulator-console.ts +0 -1
- package/lib/commands/device/utils.ts +4 -3
- package/lib/commands/deviceidle.ts +1 -2
- package/lib/commands/element.ts +10 -38
- package/lib/commands/execute.ts +3 -5
- package/lib/commands/file-actions.ts +4 -17
- package/lib/commands/geolocation.ts +21 -39
- package/lib/commands/gestures.ts +1 -5
- package/lib/commands/image-injection.ts +9 -8
- package/lib/commands/ime.ts +5 -17
- package/lib/commands/intent.ts +58 -57
- package/lib/commands/keyboard.ts +6 -21
- package/lib/commands/legacy.ts +4 -11
- package/lib/commands/lock/exports.ts +4 -2
- package/lib/commands/lock/helpers.ts +4 -1
- package/lib/commands/log.ts +15 -25
- package/lib/commands/media-projection.ts +0 -1
- package/lib/commands/memory.ts +0 -1
- package/lib/commands/misc.ts +6 -20
- package/lib/commands/network.ts +9 -28
- package/lib/commands/nfc.ts +2 -6
- package/lib/commands/performance.ts +2 -8
- package/lib/commands/permissions.ts +10 -9
- package/lib/commands/recordscreen.ts +16 -18
- package/lib/commands/resources.ts +6 -7
- package/lib/commands/shell.ts +1 -1
- package/lib/commands/streamscreen.ts +2 -7
- package/lib/commands/system-bars.ts +32 -38
- package/lib/commands/time.ts +3 -10
- package/lib/constraints.ts +2 -2
- package/lib/doctor/checks.ts +0 -1
- package/lib/doctor/utils.ts +0 -1
- package/lib/driver.ts +9 -20
- package/lib/execute-method-map.ts +38 -64
- package/lib/method-map.ts +56 -57
- package/lib/utils.ts +5 -6
- package/package.json +4 -3
package/lib/commands/legacy.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {errors} from 'appium/driver';
|
|
2
2
|
import type {AndroidDriver} from '../driver';
|
|
3
3
|
|
|
4
4
|
const ISSUE_URL = 'https://github.com/appium/appium/issues/15807';
|
|
@@ -9,9 +9,7 @@ const ISSUE_URL = 'https://github.com/appium/appium/issues/15807';
|
|
|
9
9
|
* @returns Promise that resolves when the app is launched.
|
|
10
10
|
* @throws {errors.UnsupportedOperationError} This API is not supported anymore.
|
|
11
11
|
*/
|
|
12
|
-
export async function launchApp(
|
|
13
|
-
this: AndroidDriver,
|
|
14
|
-
): Promise<void> {
|
|
12
|
+
export async function launchApp(this: AndroidDriver): Promise<void> {
|
|
15
13
|
throw new errors.UnsupportedOperationError(`This API is not supported anymore. See ${ISSUE_URL}`);
|
|
16
14
|
}
|
|
17
15
|
|
|
@@ -21,9 +19,7 @@ export async function launchApp(
|
|
|
21
19
|
* @returns Promise that resolves when the app is closed.
|
|
22
20
|
* @throws {errors.UnsupportedOperationError} This API is not supported anymore.
|
|
23
21
|
*/
|
|
24
|
-
export async function closeApp(
|
|
25
|
-
this: AndroidDriver,
|
|
26
|
-
): Promise<void> {
|
|
22
|
+
export async function closeApp(this: AndroidDriver): Promise<void> {
|
|
27
23
|
throw new errors.UnsupportedOperationError(`This API is not supported anymore. See ${ISSUE_URL}`);
|
|
28
24
|
}
|
|
29
25
|
|
|
@@ -33,9 +29,6 @@ export async function closeApp(
|
|
|
33
29
|
* @returns Promise that resolves when the app is reset.
|
|
34
30
|
* @throws {errors.UnsupportedOperationError} This API is not supported anymore.
|
|
35
31
|
*/
|
|
36
|
-
export async function reset(
|
|
37
|
-
this: AndroidDriver,
|
|
38
|
-
): Promise<void> {
|
|
32
|
+
export async function reset(this: AndroidDriver): Promise<void> {
|
|
39
33
|
throw new errors.UnsupportedOperationError(`This API is not supported anymore. See ${ISSUE_URL}`);
|
|
40
34
|
}
|
|
41
|
-
|
|
@@ -127,7 +127,10 @@ export async function unlockWithOptions(
|
|
|
127
127
|
credentialType: toCredentialType(unlockType as UnlockType),
|
|
128
128
|
});
|
|
129
129
|
} else {
|
|
130
|
-
const unlockMethodMap: Record<
|
|
130
|
+
const unlockMethodMap: Record<
|
|
131
|
+
string,
|
|
132
|
+
(this: AndroidDriver, caps: AndroidDriverCaps) => Promise<void>
|
|
133
|
+
> = {
|
|
131
134
|
[PIN_UNLOCK]: pinUnlock,
|
|
132
135
|
[PIN_UNLOCK_KEY_EVENT]: pinUnlockWithKeyEvent,
|
|
133
136
|
[PASSWORD_UNLOCK]: passwordUnlock,
|
|
@@ -144,4 +147,3 @@ export async function unlockWithOptions(
|
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
// #endregion
|
|
147
|
-
|
|
@@ -331,7 +331,10 @@ export function getPatternActions(
|
|
|
331
331
|
* @param timeoutMs - Optional timeout in milliseconds (default: 2000)
|
|
332
332
|
* @throws {Error} If the device fails to unlock within the timeout
|
|
333
333
|
*/
|
|
334
|
-
export async function verifyUnlock(
|
|
334
|
+
export async function verifyUnlock(
|
|
335
|
+
this: AndroidDriver,
|
|
336
|
+
timeoutMs: number | null = null,
|
|
337
|
+
): Promise<void> {
|
|
335
338
|
try {
|
|
336
339
|
await waitForCondition(async () => !(await this.adb.isScreenLocked()), {
|
|
337
340
|
waitMs: timeoutMs ?? 2000,
|
package/lib/commands/log.ts
CHANGED
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
nativeLogEntryToSeleniumEntry,
|
|
13
13
|
type LogEntry,
|
|
14
14
|
} from '../utils';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import {NATIVE_WIN} from './context/helpers';
|
|
16
|
+
import {BIDI_EVENT_NAME} from './bidi/constants';
|
|
17
|
+
import {makeLogEntryAddedEvent} from './bidi/models';
|
|
18
18
|
import type {AndroidDriver} from '../driver';
|
|
19
19
|
|
|
20
20
|
export const supportedLogTypes = {
|
|
@@ -49,9 +49,7 @@ export const supportedLogTypes = {
|
|
|
49
49
|
*
|
|
50
50
|
* @returns Promise that resolves when the logcat broadcasting websocket is started.
|
|
51
51
|
*/
|
|
52
|
-
export async function mobileStartLogsBroadcast(
|
|
53
|
-
this: AndroidDriver,
|
|
54
|
-
): Promise<void> {
|
|
52
|
+
export async function mobileStartLogsBroadcast(this: AndroidDriver): Promise<void> {
|
|
55
53
|
const server = this.server as AppiumServer;
|
|
56
54
|
const pathname = WEBSOCKET_ENDPOINT(this.sessionId as string);
|
|
57
55
|
if (!_.isEmpty(await server.getWebSocketHandlers(pathname))) {
|
|
@@ -113,9 +111,7 @@ export async function mobileStartLogsBroadcast(
|
|
|
113
111
|
*
|
|
114
112
|
* @returns Promise that resolves when the logcat broadcasting websocket is stopped.
|
|
115
113
|
*/
|
|
116
|
-
export async function mobileStopLogsBroadcast(
|
|
117
|
-
this: AndroidDriver,
|
|
118
|
-
): Promise<void> {
|
|
114
|
+
export async function mobileStopLogsBroadcast(this: AndroidDriver): Promise<void> {
|
|
119
115
|
const pathname = WEBSOCKET_ENDPOINT(this.sessionId as string);
|
|
120
116
|
const server = this.server as AppiumServer;
|
|
121
117
|
if (_.isEmpty(await server.getWebSocketHandlers(pathname))) {
|
|
@@ -134,13 +130,14 @@ export async function mobileStopLogsBroadcast(
|
|
|
134
130
|
*
|
|
135
131
|
* @returns Promise that resolves to an array of log type names.
|
|
136
132
|
*/
|
|
137
|
-
export async function getLogTypes(
|
|
138
|
-
this: AndroidDriver,
|
|
139
|
-
): Promise<string[]> {
|
|
133
|
+
export async function getLogTypes(this: AndroidDriver): Promise<string[]> {
|
|
140
134
|
// XXX why doesn't `super` work here?
|
|
141
135
|
const nativeLogTypes = await BaseDriver.prototype.getLogTypes.call(this);
|
|
142
136
|
if (this.isWebContext()) {
|
|
143
|
-
const webLogTypes = await (this.chromedriver as Chromedriver).jwproxy.command(
|
|
137
|
+
const webLogTypes = (await (this.chromedriver as Chromedriver).jwproxy.command(
|
|
138
|
+
'/log/types',
|
|
139
|
+
'GET',
|
|
140
|
+
)) as string[];
|
|
144
141
|
return [...nativeLogTypes, ...webLogTypes];
|
|
145
142
|
}
|
|
146
143
|
return nativeLogTypes;
|
|
@@ -161,12 +158,7 @@ export function assignBiDiLogListener<EE extends EventEmitter>(
|
|
|
161
158
|
logEmitter: EE,
|
|
162
159
|
properties: BiDiListenerProperties,
|
|
163
160
|
): [EE, LogListener] {
|
|
164
|
-
const {
|
|
165
|
-
type,
|
|
166
|
-
context = NATIVE_WIN,
|
|
167
|
-
srcEventName = 'output',
|
|
168
|
-
entryTransformer,
|
|
169
|
-
} = properties;
|
|
161
|
+
const {type, context = NATIVE_WIN, srcEventName = 'output', entryTransformer} = properties;
|
|
170
162
|
const listener: LogListener = (logEntry: LogEntry) => {
|
|
171
163
|
const finalEntry = entryTransformer ? entryTransformer(logEntry) : logEntry;
|
|
172
164
|
this.eventEmitter.emit(BIDI_EVENT_NAME, makeLogEntryAddedEvent(finalEntry, context, type));
|
|
@@ -181,12 +173,11 @@ export function assignBiDiLogListener<EE extends EventEmitter>(
|
|
|
181
173
|
* @param logType The type of logs to retrieve.
|
|
182
174
|
* @returns Promise that resolves to the logs for the specified type.
|
|
183
175
|
*/
|
|
184
|
-
export async function getLog(
|
|
185
|
-
this: AndroidDriver,
|
|
186
|
-
logType: string,
|
|
187
|
-
): Promise<any> {
|
|
176
|
+
export async function getLog(this: AndroidDriver, logType: string): Promise<any> {
|
|
188
177
|
if (this.isWebContext() && !_.keys(this.supportedLogTypes).includes(logType)) {
|
|
189
|
-
return await (this.chromedriver as Chromedriver).jwproxy.command('/log', 'POST', {
|
|
178
|
+
return await (this.chromedriver as Chromedriver).jwproxy.command('/log', 'POST', {
|
|
179
|
+
type: logType,
|
|
180
|
+
});
|
|
190
181
|
}
|
|
191
182
|
return await BaseDriver.prototype.getLog.call(this, logType);
|
|
192
183
|
}
|
|
@@ -212,4 +203,3 @@ export interface BiDiListenerProperties {
|
|
|
212
203
|
}
|
|
213
204
|
|
|
214
205
|
export type LogListener = (logEntry: LogEntry) => any;
|
|
215
|
-
|
package/lib/commands/memory.ts
CHANGED
package/lib/commands/misc.ts
CHANGED
|
@@ -9,9 +9,7 @@ import type {SmsListResult, ListSmsOpts} from './types';
|
|
|
9
9
|
* @returns Promise that resolves to the window size (width, height).
|
|
10
10
|
* @throws {errors.NotImplementedError} This method is not implemented.
|
|
11
11
|
*/
|
|
12
|
-
export async function getWindowSize(
|
|
13
|
-
this: AndroidDriver,
|
|
14
|
-
): Promise<Size> {
|
|
12
|
+
export async function getWindowSize(this: AndroidDriver): Promise<Size> {
|
|
15
13
|
throw new errors.NotImplementedError('Not implemented');
|
|
16
14
|
}
|
|
17
15
|
|
|
@@ -20,9 +18,7 @@ export async function getWindowSize(
|
|
|
20
18
|
*
|
|
21
19
|
* @returns Promise that resolves to the window rectangle.
|
|
22
20
|
*/
|
|
23
|
-
export async function getWindowRect(
|
|
24
|
-
this: AndroidDriver,
|
|
25
|
-
): Promise<Rect> {
|
|
21
|
+
export async function getWindowRect(this: AndroidDriver): Promise<Rect> {
|
|
26
22
|
const {width, height} = await this.getWindowSize();
|
|
27
23
|
return {
|
|
28
24
|
width,
|
|
@@ -41,10 +37,7 @@ export async function getWindowRect(
|
|
|
41
37
|
* @param uri The Android URI to navigate to.
|
|
42
38
|
* @returns Promise that resolves when the URI is opened.
|
|
43
39
|
*/
|
|
44
|
-
export async function setUrl(
|
|
45
|
-
this: AndroidDriver,
|
|
46
|
-
uri: string,
|
|
47
|
-
): Promise<void> {
|
|
40
|
+
export async function setUrl(this: AndroidDriver, uri: string): Promise<void> {
|
|
48
41
|
await this.adb.startUri(uri, this.opts.appPackage as string);
|
|
49
42
|
}
|
|
50
43
|
|
|
@@ -54,9 +47,7 @@ export async function setUrl(
|
|
|
54
47
|
* @returns Promise that resolves to the display density value.
|
|
55
48
|
* @throws {Error} If the display density cannot be retrieved.
|
|
56
49
|
*/
|
|
57
|
-
export async function getDisplayDensity(
|
|
58
|
-
this: AndroidDriver,
|
|
59
|
-
): Promise<number> {
|
|
50
|
+
export async function getDisplayDensity(this: AndroidDriver): Promise<number> {
|
|
60
51
|
// first try the property for devices
|
|
61
52
|
let out = await this.adb.shell(['getprop', 'ro.sf.lcd_density']);
|
|
62
53
|
if (out) {
|
|
@@ -85,9 +76,7 @@ export async function getDisplayDensity(
|
|
|
85
76
|
*
|
|
86
77
|
* @returns Promise that resolves to an object containing notification information.
|
|
87
78
|
*/
|
|
88
|
-
export async function mobileGetNotifications(
|
|
89
|
-
this: AndroidDriver,
|
|
90
|
-
): Promise<StringRecord> {
|
|
79
|
+
export async function mobileGetNotifications(this: AndroidDriver): Promise<StringRecord> {
|
|
91
80
|
return await this.settingsApp.getNotifications();
|
|
92
81
|
}
|
|
93
82
|
|
|
@@ -110,9 +99,6 @@ export async function mobileListSms(
|
|
|
110
99
|
* @returns Promise that resolves when the notifications panel is opened.
|
|
111
100
|
* @throws {errors.NotImplementedError} This method is not implemented.
|
|
112
101
|
*/
|
|
113
|
-
export async function openNotifications(
|
|
114
|
-
this: AndroidDriver,
|
|
115
|
-
): Promise<void> {
|
|
102
|
+
export async function openNotifications(this: AndroidDriver): Promise<void> {
|
|
116
103
|
throw new errors.NotImplementedError('Not implemented');
|
|
117
104
|
}
|
|
118
|
-
|
package/lib/commands/network.ts
CHANGED
|
@@ -26,9 +26,7 @@ const SUPPORTED_SERVICE_NAMES: ServiceType[] = [
|
|
|
26
26
|
* - Bit 1 (0b010) = Wi-Fi
|
|
27
27
|
* - Bit 2 (0b100) = Data connection
|
|
28
28
|
*/
|
|
29
|
-
export async function getNetworkConnection(
|
|
30
|
-
this: AndroidDriver,
|
|
31
|
-
): Promise<number> {
|
|
29
|
+
export async function getNetworkConnection(this: AndroidDriver): Promise<number> {
|
|
32
30
|
this.log.info('Getting network connection');
|
|
33
31
|
const airplaneModeOn = await this.adb.isAirplaneModeOn();
|
|
34
32
|
let connection = airplaneModeOn ? AIRPLANE_MODE_MASK : 0;
|
|
@@ -49,9 +47,7 @@ export async function getNetworkConnection(
|
|
|
49
47
|
*
|
|
50
48
|
* @returns Promise that resolves to `true` if Wi-Fi is enabled, `false` otherwise.
|
|
51
49
|
*/
|
|
52
|
-
export async function isWifiOn(
|
|
53
|
-
this: AndroidDriver,
|
|
54
|
-
): Promise<boolean> {
|
|
50
|
+
export async function isWifiOn(this: AndroidDriver): Promise<boolean> {
|
|
55
51
|
return await this.adb.isWifiOn();
|
|
56
52
|
}
|
|
57
53
|
|
|
@@ -148,7 +144,7 @@ export async function mobileGetConnectivity(
|
|
|
148
144
|
await B.all(_.values(statePromises));
|
|
149
145
|
return _.reduce(
|
|
150
146
|
statePromises,
|
|
151
|
-
(state, v, k) => _.isUndefined(v.value()) ? state : {...state, [k]: Boolean(v.value())},
|
|
147
|
+
(state, v, k) => (_.isUndefined(v.value()) ? state : {...state, [k]: Boolean(v.value())}),
|
|
152
148
|
{} as GetConnectivityResult,
|
|
153
149
|
);
|
|
154
150
|
}
|
|
@@ -164,10 +160,7 @@ export async function mobileGetConnectivity(
|
|
|
164
160
|
* - Bit 2 (0b100) = Data connection
|
|
165
161
|
* @returns Promise that resolves to the current network connection state after the change.
|
|
166
162
|
*/
|
|
167
|
-
export async function setNetworkConnection(
|
|
168
|
-
this: AndroidDriver,
|
|
169
|
-
type: number,
|
|
170
|
-
): Promise<number> {
|
|
163
|
+
export async function setNetworkConnection(this: AndroidDriver, type: number): Promise<number> {
|
|
171
164
|
this.log.info('Setting network connection');
|
|
172
165
|
// decode the input
|
|
173
166
|
const shouldEnableAirplaneMode = (type & AIRPLANE_MODE_MASK) !== 0;
|
|
@@ -232,10 +225,7 @@ export async function setNetworkConnection(
|
|
|
232
225
|
* @param isOn `true` to enable Wi-Fi, `false` to disable it.
|
|
233
226
|
* @returns Promise that resolves when the Wi-Fi state is set.
|
|
234
227
|
*/
|
|
235
|
-
export async function setWifiState(
|
|
236
|
-
this: AndroidDriver,
|
|
237
|
-
isOn: boolean,
|
|
238
|
-
): Promise<void> {
|
|
228
|
+
export async function setWifiState(this: AndroidDriver, isOn: boolean): Promise<void> {
|
|
239
229
|
await this.settingsApp.setWifiState(isOn, this.isEmulator());
|
|
240
230
|
}
|
|
241
231
|
|
|
@@ -246,10 +236,7 @@ export async function setWifiState(
|
|
|
246
236
|
* @param isOn `true` to enable mobile data, `false` to disable it.
|
|
247
237
|
* @returns Promise that resolves when the data connection state is set.
|
|
248
238
|
*/
|
|
249
|
-
export async function setDataState(
|
|
250
|
-
this: AndroidDriver,
|
|
251
|
-
isOn: boolean,
|
|
252
|
-
): Promise<void> {
|
|
239
|
+
export async function setDataState(this: AndroidDriver, isOn: boolean): Promise<void> {
|
|
253
240
|
await this.settingsApp.setDataState(isOn, this.isEmulator());
|
|
254
241
|
}
|
|
255
242
|
|
|
@@ -259,9 +246,7 @@ export async function setDataState(
|
|
|
259
246
|
* @since Android 12 (only real devices, emulators work in all APIs)
|
|
260
247
|
* @returns Promise that resolves when the data connection state is toggled.
|
|
261
248
|
*/
|
|
262
|
-
export async function toggleData(
|
|
263
|
-
this: AndroidDriver,
|
|
264
|
-
): Promise<void> {
|
|
249
|
+
export async function toggleData(this: AndroidDriver): Promise<void> {
|
|
265
250
|
const isOn = await this.adb.isDataOn();
|
|
266
251
|
this.log.info(`Turning network data ${!isOn ? 'on' : 'off'}`);
|
|
267
252
|
await this.setDataState(!isOn);
|
|
@@ -273,9 +258,7 @@ export async function toggleData(
|
|
|
273
258
|
* @since Android 12 (only real devices, emulators work in all APIs)
|
|
274
259
|
* @returns Promise that resolves when the Wi-Fi state is toggled.
|
|
275
260
|
*/
|
|
276
|
-
export async function toggleWiFi(
|
|
277
|
-
this: AndroidDriver,
|
|
278
|
-
): Promise<void> {
|
|
261
|
+
export async function toggleWiFi(this: AndroidDriver): Promise<void> {
|
|
279
262
|
const isOn = await this.adb.isWifiOn();
|
|
280
263
|
this.log.info(`Turning WiFi ${!isOn ? 'on' : 'off'}`);
|
|
281
264
|
await this.setWifiState(!isOn);
|
|
@@ -287,9 +270,7 @@ export async function toggleWiFi(
|
|
|
287
270
|
* @since Android 12 (only real devices, emulators work in all APIs)
|
|
288
271
|
* @returns Promise that resolves when the airplane mode state is toggled.
|
|
289
272
|
*/
|
|
290
|
-
export async function toggleFlightMode(
|
|
291
|
-
this: AndroidDriver,
|
|
292
|
-
): Promise<void> {
|
|
273
|
+
export async function toggleFlightMode(this: AndroidDriver): Promise<void> {
|
|
293
274
|
const flightMode = !(await this.adb.isAirplaneModeOn());
|
|
294
275
|
this.log.info(`Turning flight mode ${flightMode ? 'on' : 'off'}`);
|
|
295
276
|
await this.adb.setAirplaneMode(flightMode);
|
package/lib/commands/nfc.ts
CHANGED
|
@@ -17,10 +17,7 @@ const SUPPORTED_ACTIONS = {
|
|
|
17
17
|
* or there was a failure while performing the action.
|
|
18
18
|
* @throws {errors.InvalidArgumentError} If the action is not one of the supported actions.
|
|
19
19
|
*/
|
|
20
|
-
export async function mobileNfc(
|
|
21
|
-
this: AndroidDriver,
|
|
22
|
-
action: NfcAction,
|
|
23
|
-
): Promise<void> {
|
|
20
|
+
export async function mobileNfc(this: AndroidDriver, action: NfcAction): Promise<void> {
|
|
24
21
|
switch (action) {
|
|
25
22
|
case SUPPORTED_ACTIONS.ENABLE:
|
|
26
23
|
await this.adb.setNfcOn(true);
|
|
@@ -30,8 +27,7 @@ export async function mobileNfc(
|
|
|
30
27
|
break;
|
|
31
28
|
default:
|
|
32
29
|
throw new errors.InvalidArgumentError(
|
|
33
|
-
`You must provide a valid 'action' argument. Supported actions are: ${_.values(SUPPORTED_ACTIONS)}
|
|
30
|
+
`You must provide a valid 'action' argument. Supported actions are: ${_.values(SUPPORTED_ACTIONS)}`,
|
|
34
31
|
);
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
|
-
|
|
@@ -67,9 +67,7 @@ const RETRY_PAUSE_MS = 1000;
|
|
|
67
67
|
* @returns An array of supported performance data type names.
|
|
68
68
|
* The possible values are: 'cpuinfo', 'memoryinfo', 'batteryinfo', 'networkinfo'.
|
|
69
69
|
*/
|
|
70
|
-
export async function getPerformanceDataTypes(
|
|
71
|
-
this: AndroidDriver,
|
|
72
|
-
): Promise<PerformanceDataType[]> {
|
|
70
|
+
export async function getPerformanceDataTypes(this: AndroidDriver): Promise<PerformanceDataType[]> {
|
|
73
71
|
return _.keys(SUPPORTED_PERFORMANCE_DATA_TYPES) as PerformanceDataType[];
|
|
74
72
|
}
|
|
75
73
|
|
|
@@ -525,10 +523,7 @@ export async function getCPUInfo(
|
|
|
525
523
|
* and the second row contains the battery level as a string (0-100).
|
|
526
524
|
* @throws {Error} If battery data cannot be retrieved or parsed.
|
|
527
525
|
*/
|
|
528
|
-
export async function getBatteryInfo(
|
|
529
|
-
this: AndroidDriver,
|
|
530
|
-
retries: number = 2,
|
|
531
|
-
): Promise<any[][]> {
|
|
526
|
+
export async function getBatteryInfo(this: AndroidDriver, retries: number = 2): Promise<any[][]> {
|
|
532
527
|
return (await retryInterval(retries, RETRY_PAUSE_MS, async () => {
|
|
533
528
|
const cmd = ['dumpsys', 'battery', '|', 'grep', 'level'];
|
|
534
529
|
const data = await this.adb.shell(cmd);
|
|
@@ -545,4 +540,3 @@ export async function getBatteryInfo(
|
|
|
545
540
|
}
|
|
546
541
|
|
|
547
542
|
// #endregion
|
|
548
|
-
|
|
@@ -57,9 +57,7 @@ export async function mobileChangePermissions(
|
|
|
57
57
|
target: PermissionTarget = PERMISSION_TARGET.PM,
|
|
58
58
|
): Promise<void> {
|
|
59
59
|
appPackage ??= this.opts.appPackage;
|
|
60
|
-
action ??= _.toLower(target) === PERMISSION_TARGET.APPOPS
|
|
61
|
-
? APPOPS_ACTION.ALLOW
|
|
62
|
-
: PM_ACTION.GRANT;
|
|
60
|
+
action ??= _.toLower(target) === PERMISSION_TARGET.APPOPS ? APPOPS_ACTION.ALLOW : PM_ACTION.GRANT;
|
|
63
61
|
if (_.isNil(permissions)) {
|
|
64
62
|
throw new errors.InvalidArgumentError(`'permissions' argument is required`);
|
|
65
63
|
}
|
|
@@ -69,7 +67,11 @@ export async function mobileChangePermissions(
|
|
|
69
67
|
|
|
70
68
|
switch (_.toLower(target)) {
|
|
71
69
|
case PERMISSION_TARGET.PM:
|
|
72
|
-
return await changePermissionsViaPm.bind(this)(
|
|
70
|
+
return await changePermissionsViaPm.bind(this)(
|
|
71
|
+
permissions,
|
|
72
|
+
appPackage,
|
|
73
|
+
_.toLower(action) as PMAction,
|
|
74
|
+
);
|
|
73
75
|
case PERMISSION_TARGET.APPOPS:
|
|
74
76
|
this.assertFeatureEnabled(ADB_SHELL_FEATURE);
|
|
75
77
|
return await changePermissionsViaAppops.bind(this)(
|
|
@@ -185,8 +187,7 @@ async function changePermissionsViaAppops(
|
|
|
185
187
|
|
|
186
188
|
// #endregion
|
|
187
189
|
|
|
188
|
-
type PMAction = typeof PM_ACTION[keyof typeof PM_ACTION];
|
|
189
|
-
type AppOpsAction = typeof APPOPS_ACTION[keyof typeof APPOPS_ACTION];
|
|
190
|
-
type PermissionTarget = typeof PERMISSION_TARGET[keyof typeof PERMISSION_TARGET];
|
|
191
|
-
type PermissionsType = typeof PERMISSIONS_TYPE[keyof typeof PERMISSIONS_TYPE];
|
|
192
|
-
|
|
190
|
+
type PMAction = (typeof PM_ACTION)[keyof typeof PM_ACTION];
|
|
191
|
+
type AppOpsAction = (typeof APPOPS_ACTION)[keyof typeof APPOPS_ACTION];
|
|
192
|
+
type PermissionTarget = (typeof PERMISSION_TARGET)[keyof typeof PERMISSION_TARGET];
|
|
193
|
+
type PermissionsType = (typeof PERMISSIONS_TYPE)[keyof typeof PERMISSIONS_TYPE];
|
|
@@ -6,7 +6,11 @@ import path from 'node:path';
|
|
|
6
6
|
import {exec} from 'teen_process';
|
|
7
7
|
import type {AndroidDriver} from '../driver';
|
|
8
8
|
import type {ADB} from 'appium-adb';
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
StartScreenRecordingOpts,
|
|
11
|
+
StopScreenRecordingOpts,
|
|
12
|
+
ScreenRecordingProperties,
|
|
13
|
+
} from './types';
|
|
10
14
|
|
|
11
15
|
const RETRY_PAUSE = 300;
|
|
12
16
|
const RETRY_TIMEOUT = 5000;
|
|
@@ -135,10 +139,7 @@ export async function stopRecordingScreen(
|
|
|
135
139
|
|
|
136
140
|
if (props.recordingProcess?.isRunning) {
|
|
137
141
|
try {
|
|
138
|
-
await props.recordingProcess.stop(
|
|
139
|
-
'SIGINT',
|
|
140
|
-
PROCESS_SHUTDOWN_TIMEOUT,
|
|
141
|
-
);
|
|
142
|
+
await props.recordingProcess.stop('SIGINT', PROCESS_SHUTDOWN_TIMEOUT);
|
|
142
143
|
} catch {
|
|
143
144
|
throw this.log.errorWithException(
|
|
144
145
|
`Unable to stop screen recording within ${PROCESS_SHUTDOWN_TIMEOUT}ms`,
|
|
@@ -160,7 +161,7 @@ export async function stopRecordingScreen(
|
|
|
160
161
|
for (const pathOnDevice of props.records) {
|
|
161
162
|
const relativePath = path.resolve(tmpRoot, path.posix.basename(pathOnDevice));
|
|
162
163
|
localRecords.push(relativePath);
|
|
163
|
-
await this.adb.pull(pathOnDevice, relativePath, {
|
|
164
|
+
await this.adb.pull(pathOnDevice, relativePath, {timeout: ADB_PULL_TIMEOUT});
|
|
164
165
|
await this.adb.rimraf(pathOnDevice);
|
|
165
166
|
}
|
|
166
167
|
let resultFilePath = _.last(localRecords) as string;
|
|
@@ -295,10 +296,7 @@ async function scheduleScreenRecord(
|
|
|
295
296
|
recordingProperties.recordingProcess = recordingProc;
|
|
296
297
|
}
|
|
297
298
|
|
|
298
|
-
async function mergeScreenRecords(
|
|
299
|
-
this: AndroidDriver,
|
|
300
|
-
mediaFiles: string[],
|
|
301
|
-
): Promise<string> {
|
|
299
|
+
async function mergeScreenRecords(this: AndroidDriver, mediaFiles: string[]): Promise<string> {
|
|
302
300
|
try {
|
|
303
301
|
await fs.which(FFMPEG_BINARY);
|
|
304
302
|
} catch {
|
|
@@ -330,17 +328,17 @@ async function terminateBackgroundScreenRecording(adb: ADB, force = true): Promi
|
|
|
330
328
|
|
|
331
329
|
try {
|
|
332
330
|
await adb.shell(['kill', force ? '-15' : '-2', ...screenrecordPids.map(String)]);
|
|
333
|
-
await waitForCondition(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
331
|
+
await waitForCondition(
|
|
332
|
+
async () => _.isEmpty(await adb.getProcessIdsByName(SCREENRECORD_BINARY)),
|
|
333
|
+
{
|
|
334
|
+
waitMs: PROCESS_SHUTDOWN_TIMEOUT,
|
|
335
|
+
intervalMs: 500,
|
|
336
|
+
},
|
|
337
|
+
);
|
|
337
338
|
return true;
|
|
338
339
|
} catch (err) {
|
|
339
|
-
throw new Error(
|
|
340
|
-
`Unable to stop the background screen recording: ${(err as Error).message}`,
|
|
341
|
-
);
|
|
340
|
+
throw new Error(`Unable to stop the background screen recording: ${(err as Error).message}`);
|
|
342
341
|
}
|
|
343
342
|
}
|
|
344
343
|
|
|
345
344
|
// #endregion
|
|
346
|
-
|
|
@@ -111,17 +111,16 @@ async function fetchLocaleSuggestions(
|
|
|
111
111
|
country?: string,
|
|
112
112
|
): Promise<Locale[]> {
|
|
113
113
|
const supportedLocales = await this.settingsApp.listSupportedLocales();
|
|
114
|
-
const suggestedLocales = supportedLocales
|
|
115
|
-
|
|
116
|
-
_.toLower(language) === _.toLower(locale.language)
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
const suggestedLocales = supportedLocales.filter(
|
|
115
|
+
(locale) =>
|
|
116
|
+
_.toLower(language) === _.toLower(locale.language) ||
|
|
117
|
+
_.toLower(country) === _.toLower(locale.country),
|
|
118
|
+
);
|
|
119
119
|
return _.isEmpty(suggestedLocales) ? supportedLocales : suggestedLocales;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
function toLocaleAbbr({language, country, script}: Locale): string {
|
|
123
|
-
return `${language}_${country}${script ?
|
|
123
|
+
return `${language}_${country}${script ? '-' + script : ''}`;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// #endregion
|
|
127
|
-
|
package/lib/commands/shell.ts
CHANGED
|
@@ -31,7 +31,7 @@ export async function mobileShell<T extends boolean>(
|
|
|
31
31
|
args: string[] = [],
|
|
32
32
|
timeout: number = 20000,
|
|
33
33
|
includeStderr?: T,
|
|
34
|
-
): Promise<T extends true ? {
|
|
34
|
+
): Promise<T extends true ? {stdout: string; stderr: string} : string> {
|
|
35
35
|
this.assertFeatureEnabled(ADB_SHELL_FEATURE);
|
|
36
36
|
|
|
37
37
|
if (!_.isString(command)) {
|
|
@@ -404,9 +404,7 @@ async function initDeviceStreamingProc(
|
|
|
404
404
|
});
|
|
405
405
|
} catch (e) {
|
|
406
406
|
throw log.errorWithException(
|
|
407
|
-
`Cannot start the screen streaming process. Original error: ${
|
|
408
|
-
(e as Error).message
|
|
409
|
-
}`,
|
|
407
|
+
`Cannot start the screen streaming process. Original error: ${(e as Error).message}`,
|
|
410
408
|
);
|
|
411
409
|
} finally {
|
|
412
410
|
deviceStreaming.stderr.removeListener('data', errorsListener);
|
|
@@ -491,9 +489,7 @@ async function initGstreamerPipeline(
|
|
|
491
489
|
} catch (e) {
|
|
492
490
|
didFail = true;
|
|
493
491
|
throw log.errorWithException(
|
|
494
|
-
`Cannot start the screen streaming pipeline. Original error: ${
|
|
495
|
-
(e as Error).message
|
|
496
|
-
}`,
|
|
492
|
+
`Cannot start the screen streaming pipeline. Original error: ${(e as Error).message}`,
|
|
497
493
|
);
|
|
498
494
|
} finally {
|
|
499
495
|
if (!logPipelineDetails || didFail) {
|
|
@@ -517,4 +513,3 @@ function extractRemoteAddress(req: http.IncomingMessage): string {
|
|
|
517
513
|
}
|
|
518
514
|
|
|
519
515
|
// #endregion
|
|
520
|
-
|
|
@@ -28,16 +28,12 @@ const DEFAULT_WINDOW_PROPERTIES: WindowProperties = {
|
|
|
28
28
|
* @returns Promise that resolves to an object containing statusBar and navigationBar properties.
|
|
29
29
|
* @throws {Error} If system bars details cannot be retrieved or parsed.
|
|
30
30
|
*/
|
|
31
|
-
export async function getSystemBars(
|
|
32
|
-
this: AndroidDriver,
|
|
33
|
-
): Promise<StringRecord> {
|
|
31
|
+
export async function getSystemBars(this: AndroidDriver): Promise<StringRecord> {
|
|
34
32
|
let stdout: string;
|
|
35
33
|
try {
|
|
36
34
|
stdout = await this.adb.shell(['dumpsys', 'window', 'windows']);
|
|
37
35
|
} catch (e) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`Cannot retrieve system bars details. Original error: ${(e as Error).message}`,
|
|
40
|
-
);
|
|
36
|
+
throw new Error(`Cannot retrieve system bars details. Original error: ${(e as Error).message}`);
|
|
41
37
|
}
|
|
42
38
|
return parseWindows.bind(this)(stdout);
|
|
43
39
|
}
|
|
@@ -57,27 +53,27 @@ export async function mobilePerformStatusBarCommand(
|
|
|
57
53
|
command: StatusBarCommand,
|
|
58
54
|
component?: string,
|
|
59
55
|
): Promise<string> {
|
|
60
|
-
const toStatusBarCommandCallable =
|
|
61
|
-
cmd: string,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
...(argsCallable ? _.castArray(argsCallable()) : []),
|
|
69
|
-
]);
|
|
56
|
+
const toStatusBarCommandCallable =
|
|
57
|
+
(cmd: string, argsCallable?: () => string[] | string) => async (): Promise<string> =>
|
|
58
|
+
await this.adb.shell([
|
|
59
|
+
'cmd',
|
|
60
|
+
'statusbar',
|
|
61
|
+
cmd,
|
|
62
|
+
...(argsCallable ? _.castArray(argsCallable()) : []),
|
|
63
|
+
]);
|
|
70
64
|
const tileCommandArgsCallable = () => component as string;
|
|
71
65
|
const statusBarCommands = _.fromPairs(
|
|
72
|
-
(
|
|
73
|
-
[
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
(
|
|
67
|
+
[
|
|
68
|
+
['expandNotifications', ['expand-notifications']],
|
|
69
|
+
['expandSettings', ['expand-settings']],
|
|
70
|
+
['collapse', ['collapse']],
|
|
71
|
+
['addTile', ['add-tile', tileCommandArgsCallable]],
|
|
72
|
+
['removeTile', ['remove-tile', tileCommandArgsCallable]],
|
|
73
|
+
['clickTile', ['click-tile', tileCommandArgsCallable]],
|
|
74
|
+
['getStatusIcons', ['get-status-icons']],
|
|
75
|
+
] as const
|
|
76
|
+
).map(([name, args]) => [name, toStatusBarCommandCallable(args[0], args[1])]),
|
|
81
77
|
) as Record<StatusBarCommand, () => Promise<string>>;
|
|
82
78
|
|
|
83
79
|
const action = statusBarCommands[command];
|
|
@@ -135,10 +131,7 @@ export function parseWindowProperties(
|
|
|
135
131
|
* and values are corresponding WindowProperties objects
|
|
136
132
|
* @throws {Error} If no window properties could be parsed
|
|
137
133
|
*/
|
|
138
|
-
export function parseWindows(
|
|
139
|
-
this: AndroidDriver,
|
|
140
|
-
lines: string,
|
|
141
|
-
): SystemBarsResult {
|
|
134
|
+
export function parseWindows(this: AndroidDriver, lines: string): SystemBarsResult {
|
|
142
135
|
const windows: StringRecord<string[]> = {};
|
|
143
136
|
let currentWindowName: string | null = null;
|
|
144
137
|
for (const line of lines.split('\n').map(_.trimEnd)) {
|
|
@@ -165,21 +158,23 @@ export function parseWindows(
|
|
|
165
158
|
const result: SystemBarsResult = {};
|
|
166
159
|
for (const [name, props] of _.toPairs(windows)) {
|
|
167
160
|
if (
|
|
168
|
-
name.startsWith(STATUS_BAR_WINDOW_NAME_PREFIX)
|
|
169
|
-
|
|
161
|
+
name.startsWith(STATUS_BAR_WINDOW_NAME_PREFIX) ||
|
|
162
|
+
props.some((line: string) => STATUS_BAR_TYPE_PATTERN.test(line))
|
|
170
163
|
) {
|
|
171
164
|
result.statusBar = parseWindowProperties.bind(this)(name, props);
|
|
172
165
|
} else if (
|
|
173
|
-
name.startsWith(NAVIGATION_BAR_WINDOW_NAME_PREFIX)
|
|
174
|
-
|
|
166
|
+
name.startsWith(NAVIGATION_BAR_WINDOW_NAME_PREFIX) ||
|
|
167
|
+
props.some((line: string) => NAVIGATION_BAR_TYPE_PATTERN.test(line))
|
|
175
168
|
) {
|
|
176
169
|
result.navigationBar = parseWindowProperties.bind(this)(name, props);
|
|
177
170
|
}
|
|
178
171
|
}
|
|
179
|
-
const unmatchedWindows = (
|
|
180
|
-
[
|
|
181
|
-
|
|
182
|
-
|
|
172
|
+
const unmatchedWindows = (
|
|
173
|
+
[
|
|
174
|
+
['statusBar', STATUS_BAR_WINDOW_NAME_PREFIX],
|
|
175
|
+
['navigationBar', NAVIGATION_BAR_WINDOW_NAME_PREFIX],
|
|
176
|
+
] as const
|
|
177
|
+
).filter(([name]) => _.isNil(result[name as keyof SystemBarsResult]));
|
|
183
178
|
for (const [window, namePrefix] of unmatchedWindows) {
|
|
184
179
|
this.log.info(
|
|
185
180
|
`No windows have been found whose title matches to ` +
|
|
@@ -197,4 +192,3 @@ interface SystemBarsResult {
|
|
|
197
192
|
statusBar?: WindowProperties;
|
|
198
193
|
navigationBar?: WindowProperties;
|
|
199
194
|
}
|
|
200
|
-
|