appium-uiautomator2-driver 6.6.1 → 6.6.3

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 (33) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +14 -9
  3. package/build/lib/commands/screenshot.d.ts +17 -14
  4. package/build/lib/commands/screenshot.d.ts.map +1 -1
  5. package/build/lib/commands/screenshot.js +50 -36
  6. package/build/lib/commands/screenshot.js.map +1 -1
  7. package/build/lib/constraints.d.ts +3 -0
  8. package/build/lib/constraints.d.ts.map +1 -1
  9. package/build/test/unit/commands/general-specs.d.ts +2 -0
  10. package/build/test/unit/commands/general-specs.d.ts.map +1 -0
  11. package/build/test/unit/commands/general-specs.js +80 -0
  12. package/build/test/unit/commands/general-specs.js.map +1 -0
  13. package/build/test/unit/commands/screenshot-specs.d.ts +2 -0
  14. package/build/test/unit/commands/screenshot-specs.d.ts.map +1 -0
  15. package/build/test/unit/commands/screenshot-specs.js +124 -0
  16. package/build/test/unit/commands/screenshot-specs.js.map +1 -0
  17. package/build/test/unit/css-converter-specs.d.ts +2 -0
  18. package/build/test/unit/css-converter-specs.d.ts.map +1 -0
  19. package/build/test/unit/css-converter-specs.js +68 -0
  20. package/build/test/unit/css-converter-specs.js.map +1 -0
  21. package/build/test/unit/driver-specs.d.ts +2 -0
  22. package/build/test/unit/driver-specs.d.ts.map +1 -0
  23. package/build/test/unit/driver-specs.js +328 -0
  24. package/build/test/unit/driver-specs.js.map +1 -0
  25. package/build/test/unit/uiautomator2-specs.d.ts +2 -0
  26. package/build/test/unit/uiautomator2-specs.d.ts.map +1 -0
  27. package/build/test/unit/uiautomator2-specs.js +320 -0
  28. package/build/test/unit/uiautomator2-specs.js.map +1 -0
  29. package/build/tsconfig.tsbuildinfo +1 -1
  30. package/lib/commands/screenshot.ts +146 -0
  31. package/npm-shrinkwrap.json +252 -387
  32. package/package.json +2 -3
  33. package/lib/commands/screenshot.js +0 -116
@@ -0,0 +1,146 @@
1
+ import _ from 'lodash';
2
+ import B from 'bluebird';
3
+ import {imageUtil} from 'appium/support';
4
+ import type {AndroidUiautomator2Driver} from '../driver';
5
+ import type {Screenshot} from './types';
6
+ import type {StringRecord} from '@appium/types';
7
+
8
+ // Matches SurfaceFlinger output format:
9
+ // Physical: Display 4619827259835644672 (HWC display 0): port=0 pnpId=GGL displayName="EMU_display_0"
10
+ // Virtual: Display 11529215049243506835 (Virtual display): displayName="Emulator 2D Display" uniqueId="..."
11
+ const DISPLAY_PATTERN = /^Display\s+(\d+)\s+\((?:HWC\s+display\s+(\d+)|Virtual\s+display)\):.*?displayName="([^"]*)"/gm;
12
+
13
+ /**
14
+ * Parses SurfaceFlinger display output to extract display information.
15
+ * @param displaysInfo - The raw output from `adb shell dumpsys SurfaceFlinger --display-id`
16
+ * @returns A record mapping display IDs to their information (without payload)
17
+ */
18
+ export function parseSurfaceFlingerDisplays(
19
+ displaysInfo: string
20
+ ): Record<string, Partial<Screenshot>> {
21
+ const infos: Record<string, Partial<Screenshot>> = {};
22
+ const lines = displaysInfo.split('\n');
23
+
24
+ for (const line of lines) {
25
+ let match: RegExpExecArray | null;
26
+
27
+ // Try to match display header line
28
+ if ((match = DISPLAY_PATTERN.exec(line))) {
29
+ const [, matchedDisplayId, hwcId, displayName] = match; // Skip match[0] (full match), then Display ID, HWC ID (optional), Display name
30
+
31
+ // Determine if default: HWC display 0 is default, or first physical display if no HWC info
32
+ const isDefault = hwcId !== undefined
33
+ ? hwcId === '0'
34
+ : !line.includes('Virtual') && Object.keys(infos).length === 0;
35
+
36
+ infos[matchedDisplayId] = {
37
+ id: matchedDisplayId,
38
+ isDefault,
39
+ name: displayName || undefined,
40
+ };
41
+
42
+ // Reset regex lastIndex for next iteration
43
+ DISPLAY_PATTERN.lastIndex = 0;
44
+ }
45
+ }
46
+
47
+ return infos;
48
+ }
49
+
50
+ /**
51
+ * Takes a screenshot of the current viewport
52
+ */
53
+ export async function mobileViewportScreenshot(
54
+ this: AndroidUiautomator2Driver
55
+ ): Promise<string> {
56
+ return await this.getViewportScreenshot();
57
+ }
58
+
59
+ /**
60
+ * Gets a screenshot of the current viewport
61
+ */
62
+ export async function getViewportScreenshot(
63
+ this: AndroidUiautomator2Driver
64
+ ): Promise<string> {
65
+ const screenshot = await this.getScreenshot();
66
+ const rect = await this.getViewPortRect();
67
+ return await imageUtil.cropBase64Image(screenshot, rect);
68
+ }
69
+
70
+ /**
71
+ * Gets a screenshot of the current screen
72
+ */
73
+ export async function getScreenshot(
74
+ this: AndroidUiautomator2Driver
75
+ ): Promise<string> {
76
+ if (this.mjpegStream) {
77
+ const data = await this.mjpegStream.lastChunkPNGBase64();
78
+ if (data) {
79
+ return data;
80
+ }
81
+ this.log.warn(
82
+ 'Tried to get screenshot from active MJPEG stream, but there ' +
83
+ 'was no data yet. Falling back to regular screenshot methods.'
84
+ );
85
+ }
86
+ return String(
87
+ await this.uiautomator2.jwproxy.command('/screenshot', 'GET')
88
+ );
89
+ }
90
+
91
+ /**
92
+ * Retrieves screenshots of each display available to Android.
93
+ * This functionality is only supported since Android 10.
94
+ * @param displayId - Android display identifier to take a screenshot for.
95
+ * If not provided then screenshots of all displays are going to be returned.
96
+ * If no matches were found then an error is thrown.
97
+ */
98
+ export async function mobileScreenshots(
99
+ this: AndroidUiautomator2Driver,
100
+ displayId?: number | string
101
+ ): Promise<StringRecord<Screenshot>> {
102
+ const displaysInfo = await this.adb.shell([
103
+ 'dumpsys',
104
+ 'SurfaceFlinger',
105
+ '--display-id',
106
+ ]);
107
+ const infos = parseSurfaceFlingerDisplays(displaysInfo);
108
+ if (_.isEmpty(infos)) {
109
+ this.log.debug(displaysInfo);
110
+ throw new Error('Cannot determine the information about connected Android displays');
111
+ }
112
+ this.log.info(`Parsed Android display infos: ${JSON.stringify(infos)}`);
113
+
114
+ const toB64Screenshot = async (dispId: string): Promise<string> =>
115
+ (await this.adb.takeScreenshot(dispId)).toString('base64');
116
+
117
+ const displayIdStr: string | null =
118
+ _.isNil(displayId) || displayId === ''
119
+ ? null
120
+ : String(displayId);
121
+
122
+ if (displayIdStr) {
123
+ if (!infos[displayIdStr]) {
124
+ throw new Error(
125
+ `The provided display identifier '${displayId}' is not known. ` +
126
+ `Only the following displays have been detected: ${JSON.stringify(infos)}`
127
+ );
128
+ }
129
+ return {
130
+ [displayIdStr]: {
131
+ ...infos[displayIdStr],
132
+ payload: await toB64Screenshot(displayIdStr),
133
+ } as Screenshot,
134
+ };
135
+ }
136
+
137
+ const allInfos = _.values(infos).filter((info): info is Partial<Screenshot> & {id: string} => !!info?.id);
138
+ const screenshots = await B.all(allInfos.map((info) => toB64Screenshot(info.id)));
139
+ for (const [info, payload] of _.zip(allInfos, screenshots) as Array<[Partial<Screenshot>, string]>) {
140
+ if (info && payload) {
141
+ info.payload = payload;
142
+ }
143
+ }
144
+ return infos as StringRecord<Screenshot>;
145
+ }
146
+