@midscene/android 0.26.7-beta-20250821134240.0 → 0.27.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/dist/es/index.mjs +22 -116
- package/dist/lib/index.js +22 -116
- package/dist/types/index.d.ts +0 -6
- package/package.json +4 -4
package/dist/es/index.mjs
CHANGED
|
@@ -204,7 +204,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
204
204
|
async execYadb(keyboardContent) {
|
|
205
205
|
await this.ensureYadb();
|
|
206
206
|
const adb = await this.getAdb();
|
|
207
|
-
await adb.shell(`app_process
|
|
207
|
+
await adb.shell(`app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
|
|
208
208
|
}
|
|
209
209
|
async getElementsInfo() {
|
|
210
210
|
return [];
|
|
@@ -216,36 +216,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
216
216
|
};
|
|
217
217
|
}
|
|
218
218
|
async getScreenSize() {
|
|
219
|
-
var _this_options;
|
|
220
219
|
const adb = await this.getAdb();
|
|
221
|
-
if ('number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId)) try {
|
|
222
|
-
const longDisplayId = await this.getLongDisplayId();
|
|
223
|
-
if (longDisplayId) {
|
|
224
|
-
const stdout = await adb.shell('dumpsys display');
|
|
225
|
-
const lineRegex = new RegExp(`^.*uniqueId "local:${longDisplayId}".*$`, 'm');
|
|
226
|
-
const lineMatch = stdout.match(lineRegex);
|
|
227
|
-
if (lineMatch) {
|
|
228
|
-
const targetLine = lineMatch[0];
|
|
229
|
-
const realMatch = targetLine.match(/real (\d+) x (\d+)/);
|
|
230
|
-
const rotationMatch = targetLine.match(/rotation (\d+)/);
|
|
231
|
-
if (realMatch && rotationMatch) {
|
|
232
|
-
const width = Number(realMatch[1]);
|
|
233
|
-
const height = Number(realMatch[2]);
|
|
234
|
-
const rotation = Number(rotationMatch[1]);
|
|
235
|
-
const sizeStr = `${width}x${height}`;
|
|
236
|
-
debugPage(`Using display info for long ID ${longDisplayId}: ${sizeStr}, rotation: ${rotation}`);
|
|
237
|
-
return {
|
|
238
|
-
override: sizeStr,
|
|
239
|
-
physical: sizeStr,
|
|
240
|
-
orientation: rotation
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
debugPage(`Could not find display info for activeDisplayId ${this.options.activeDisplayId}`);
|
|
246
|
-
} catch (e) {
|
|
247
|
-
debugPage(`Failed to get size from display info for display ${this.options.activeDisplayId}: ${e}`);
|
|
248
|
-
}
|
|
249
220
|
const stdout = await adb.shell([
|
|
250
221
|
'wm',
|
|
251
222
|
'size'
|
|
@@ -264,43 +235,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
264
235
|
debugPage(`Using Physical size: ${physicalSize[1].trim()}`);
|
|
265
236
|
size.physical = physicalSize[1].trim();
|
|
266
237
|
}
|
|
267
|
-
const orientation = await this.getDisplayOrientation();
|
|
268
|
-
if (size.override || size.physical) return {
|
|
269
|
-
...size,
|
|
270
|
-
orientation
|
|
271
|
-
};
|
|
272
|
-
throw new Error(`Failed to get screen size, output: ${stdout}`);
|
|
273
|
-
}
|
|
274
|
-
async getDisplayDensity() {
|
|
275
|
-
var _this_options;
|
|
276
|
-
const adb = await this.getAdb();
|
|
277
|
-
if ('number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId)) try {
|
|
278
|
-
const longDisplayId = await this.getLongDisplayId();
|
|
279
|
-
if (longDisplayId) {
|
|
280
|
-
const stdout = await adb.shell('dumpsys display');
|
|
281
|
-
const lineRegex = new RegExp(`^.*uniqueId "local:${longDisplayId}".*$`, 'm');
|
|
282
|
-
const lineMatch = stdout.match(lineRegex);
|
|
283
|
-
if (lineMatch) {
|
|
284
|
-
const targetLine = lineMatch[0];
|
|
285
|
-
const densityMatch = targetLine.match(/density (\d+)/);
|
|
286
|
-
if (densityMatch) {
|
|
287
|
-
const density = Number(densityMatch[1]);
|
|
288
|
-
debugPage(`Using display density for long ID ${longDisplayId}: ${density}`);
|
|
289
|
-
return density;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
} catch (e) {
|
|
294
|
-
debugPage(`Failed to get density from display info: ${e}`);
|
|
295
|
-
}
|
|
296
|
-
const density = await adb.getScreenDensity();
|
|
297
|
-
return density ?? 160;
|
|
298
|
-
}
|
|
299
|
-
async getDisplayOrientation() {
|
|
300
|
-
const adb = await this.getAdb();
|
|
301
238
|
let orientation = 0;
|
|
302
239
|
try {
|
|
303
|
-
const orientationStdout = await adb.shell(
|
|
240
|
+
const orientationStdout = await adb.shell('dumpsys input | grep SurfaceOrientation');
|
|
304
241
|
const orientationMatch = orientationStdout.match(/SurfaceOrientation:\s*(\d)/);
|
|
305
242
|
if (!orientationMatch) throw new Error('Failed to get orientation from input');
|
|
306
243
|
orientation = Number(orientationMatch[1]);
|
|
@@ -308,7 +245,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
308
245
|
} catch (e) {
|
|
309
246
|
debugPage('Failed to get orientation from input, try display');
|
|
310
247
|
try {
|
|
311
|
-
const orientationStdout = await adb.shell(
|
|
248
|
+
const orientationStdout = await adb.shell('dumpsys display | grep mCurrentOrientation');
|
|
312
249
|
const orientationMatch = orientationStdout.match(/mCurrentOrientation=(\d)/);
|
|
313
250
|
if (!orientationMatch) throw new Error('Failed to get orientation from display');
|
|
314
251
|
orientation = Number(orientationMatch[1]);
|
|
@@ -318,17 +255,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
318
255
|
debugPage('Failed to get orientation from display, default to 0');
|
|
319
256
|
}
|
|
320
257
|
}
|
|
321
|
-
return
|
|
258
|
+
if (size.override || size.physical) return {
|
|
259
|
+
...size,
|
|
260
|
+
orientation
|
|
261
|
+
};
|
|
262
|
+
throw new Error(`Failed to get screen size, output: ${stdout}`);
|
|
322
263
|
}
|
|
323
264
|
async size() {
|
|
324
|
-
await this.getAdb();
|
|
265
|
+
const adb = await this.getAdb();
|
|
325
266
|
const screenSize = await this.getScreenSize();
|
|
326
267
|
const match = (screenSize.override || screenSize.physical).match(/(\d+)x(\d+)/);
|
|
327
268
|
if (!match || match.length < 3) throw new Error(`Unable to parse screen size: ${screenSize}`);
|
|
328
269
|
const isLandscape = 1 === screenSize.orientation || 3 === screenSize.orientation;
|
|
329
270
|
const width = Number.parseInt(match[isLandscape ? 2 : 1], 10);
|
|
330
271
|
const height = Number.parseInt(match[isLandscape ? 1 : 2], 10);
|
|
331
|
-
const densityNum = await
|
|
272
|
+
const densityNum = await adb.getScreenDensity();
|
|
332
273
|
this.devicePixelRatio = Number(densityNum) / 160;
|
|
333
274
|
const { x: logicalWidth, y: logicalHeight } = this.reverseAdjustCoordinates(width, height);
|
|
334
275
|
return {
|
|
@@ -352,18 +293,12 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
352
293
|
};
|
|
353
294
|
}
|
|
354
295
|
async screenshotBase64() {
|
|
355
|
-
var _this_options;
|
|
356
296
|
debugPage('screenshotBase64 begin');
|
|
357
297
|
const { width, height } = await this.size();
|
|
358
298
|
const adb = await this.getAdb();
|
|
359
299
|
let screenshotBuffer;
|
|
360
300
|
const androidScreenshotPath = `/data/local/tmp/midscene_screenshot_${randomUUID()}.png`;
|
|
361
|
-
const useShellScreencap = 'number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId);
|
|
362
301
|
try {
|
|
363
|
-
if (useShellScreencap) {
|
|
364
|
-
var _this_options1;
|
|
365
|
-
throw new Error(`Display ${null == (_this_options1 = this.options) ? void 0 : _this_options1.activeDisplayId} requires shell screencap`);
|
|
366
|
-
}
|
|
367
302
|
debugPage('Taking screenshot via adb.takeScreenshot');
|
|
368
303
|
screenshotBuffer = await adb.takeScreenshot(null);
|
|
369
304
|
debugPage('adb.takeScreenshot completed');
|
|
@@ -373,17 +308,13 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
373
308
|
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
374
309
|
}
|
|
375
310
|
} catch (error) {
|
|
376
|
-
debugPage(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
|
|
377
311
|
const screenshotPath = getTmpFile('png');
|
|
378
312
|
try {
|
|
379
|
-
var _this_options2, _this_options3;
|
|
380
313
|
debugPage('Fallback: taking screenshot via shell screencap');
|
|
381
|
-
const displayId = (null == (_this_options2 = this.options) ? void 0 : _this_options2.useLongDisplayIdForScreenshot) ? await this.getLongDisplayId() : null == (_this_options3 = this.options) ? void 0 : _this_options3.activeDisplayId;
|
|
382
|
-
const displayArg = displayId ? `-d ${displayId}` : '';
|
|
383
314
|
try {
|
|
384
|
-
await adb.shell(`screencap -p ${
|
|
315
|
+
await adb.shell(`screencap -p ${androidScreenshotPath}`);
|
|
385
316
|
debugPage('adb.shell screencap completed');
|
|
386
|
-
} catch (
|
|
317
|
+
} catch (error) {
|
|
387
318
|
debugPage('screencap failed, using forceScreenshot');
|
|
388
319
|
await this.forceScreenshot(androidScreenshotPath);
|
|
389
320
|
debugPage('forceScreenshot completed');
|
|
@@ -426,7 +357,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
426
357
|
await this.ensureYadb();
|
|
427
358
|
const adb = await this.getAdb();
|
|
428
359
|
await this.mouse.click(element.center[0], element.center[1]);
|
|
429
|
-
await adb.shell(
|
|
360
|
+
await adb.shell('app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "~CLEAR~"');
|
|
430
361
|
if (await adb.isSoftKeyboardPresent()) return;
|
|
431
362
|
await this.mouse.click(element.center[0], element.center[1]);
|
|
432
363
|
}
|
|
@@ -628,7 +559,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
628
559
|
async mouseClick(x, y) {
|
|
629
560
|
const adb = await this.getAdb();
|
|
630
561
|
const { x: adjustedX, y: adjustedY } = this.adjustCoordinates(x, y);
|
|
631
|
-
await adb.shell(`input
|
|
562
|
+
await adb.shell(`input swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} 150`);
|
|
632
563
|
}
|
|
633
564
|
async mouseMove(x, y) {
|
|
634
565
|
return Promise.resolve();
|
|
@@ -638,7 +569,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
638
569
|
const { x: fromX, y: fromY } = this.adjustCoordinates(from.x, from.y);
|
|
639
570
|
const { x: toX, y: toY } = this.adjustCoordinates(to.x, to.y);
|
|
640
571
|
const swipeDuration = duration ?? 300;
|
|
641
|
-
await adb.shell(`input
|
|
572
|
+
await adb.shell(`input swipe ${fromX} ${fromY} ${toX} ${toY} ${swipeDuration}`);
|
|
642
573
|
}
|
|
643
574
|
async mouseWheel(deltaX, deltaY, duration) {
|
|
644
575
|
const { width, height } = await this.size();
|
|
@@ -657,7 +588,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
657
588
|
const { x: adjustedEndX, y: adjustedEndY } = this.adjustCoordinates(endX, endY);
|
|
658
589
|
const adb = await this.getAdb();
|
|
659
590
|
const swipeDuration = duration ?? defaultNormalScrollDuration;
|
|
660
|
-
await adb.shell(`input
|
|
591
|
+
await adb.shell(`input swipe ${adjustedStartX} ${adjustedStartY} ${adjustedEndX} ${adjustedEndY} ${swipeDuration}`);
|
|
661
592
|
}
|
|
662
593
|
async destroy() {
|
|
663
594
|
if (this.destroyed) return;
|
|
@@ -672,20 +603,20 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
672
603
|
}
|
|
673
604
|
async back() {
|
|
674
605
|
const adb = await this.getAdb();
|
|
675
|
-
await adb.shell(
|
|
606
|
+
await adb.shell('input keyevent 4');
|
|
676
607
|
}
|
|
677
608
|
async home() {
|
|
678
609
|
const adb = await this.getAdb();
|
|
679
|
-
await adb.shell(
|
|
610
|
+
await adb.shell('input keyevent 3');
|
|
680
611
|
}
|
|
681
612
|
async recentApps() {
|
|
682
613
|
const adb = await this.getAdb();
|
|
683
|
-
await adb.shell(
|
|
614
|
+
await adb.shell('input keyevent 187');
|
|
684
615
|
}
|
|
685
616
|
async longPress(x, y, duration = 1000) {
|
|
686
617
|
const adb = await this.getAdb();
|
|
687
618
|
const { x: adjustedX, y: adjustedY } = this.adjustCoordinates(x, y);
|
|
688
|
-
await adb.shell(`input
|
|
619
|
+
await adb.shell(`input swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} ${duration}`);
|
|
689
620
|
}
|
|
690
621
|
async pullDown(startPoint, distance, duration = 800) {
|
|
691
622
|
const { width, height } = await this.size();
|
|
@@ -708,7 +639,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
708
639
|
const adb = await this.getAdb();
|
|
709
640
|
const { x: fromX, y: fromY } = this.adjustCoordinates(from.x, from.y);
|
|
710
641
|
const { x: toX, y: toY } = this.adjustCoordinates(to.x, to.y);
|
|
711
|
-
await adb.shell(`input
|
|
642
|
+
await adb.shell(`input swipe ${fromX} ${fromY} ${toX} ${toY} ${duration}`);
|
|
712
643
|
}
|
|
713
644
|
async pullUp(startPoint, distance, duration = 600) {
|
|
714
645
|
const { width, height } = await this.size();
|
|
@@ -736,29 +667,6 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
736
667
|
async getElementInfoByXpath(xpath) {
|
|
737
668
|
throw new Error('Not implemented');
|
|
738
669
|
}
|
|
739
|
-
getDisplayArg() {
|
|
740
|
-
var _this_options;
|
|
741
|
-
return 'number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId) ? ` -d ${this.options.activeDisplayId}` : '';
|
|
742
|
-
}
|
|
743
|
-
async getLongDisplayId() {
|
|
744
|
-
var _this_options;
|
|
745
|
-
if ('number' != typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId)) return null;
|
|
746
|
-
const adb = await this.getAdb();
|
|
747
|
-
try {
|
|
748
|
-
const stdout = await adb.shell(`dumpsys SurfaceFlinger --display-id ${this.options.activeDisplayId}`);
|
|
749
|
-
const regex = new RegExp(`Display (\\d+) \\(HWC display ${this.options.activeDisplayId}\\):`);
|
|
750
|
-
const displayMatch = stdout.match(regex);
|
|
751
|
-
if (null == displayMatch ? void 0 : displayMatch[1]) {
|
|
752
|
-
debugPage(`Found long display ID: ${displayMatch[1]} for short ID: ${this.options.activeDisplayId}`);
|
|
753
|
-
return displayMatch[1];
|
|
754
|
-
}
|
|
755
|
-
debugPage(`Could not find long display ID for short ID: ${this.options.activeDisplayId}`);
|
|
756
|
-
return null;
|
|
757
|
-
} catch (error) {
|
|
758
|
-
debugPage(`Error getting long display ID: ${error}`);
|
|
759
|
-
return null;
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
670
|
async hideKeyboard(options, timeoutMs = 1000) {
|
|
763
671
|
var _this_options;
|
|
764
672
|
const adb = await this.getAdb();
|
|
@@ -849,9 +757,7 @@ async function agentFromAdbDevice(deviceId, opts) {
|
|
|
849
757
|
androidAdbPath: null == opts ? void 0 : opts.androidAdbPath,
|
|
850
758
|
remoteAdbHost: null == opts ? void 0 : opts.remoteAdbHost,
|
|
851
759
|
remoteAdbPort: null == opts ? void 0 : opts.remoteAdbPort,
|
|
852
|
-
imeStrategy: null == opts ? void 0 : opts.imeStrategy
|
|
853
|
-
activeDisplayId: null == opts ? void 0 : opts.activeDisplayId,
|
|
854
|
-
useLongDisplayIdForScreenshot: null == opts ? void 0 : opts.useLongDisplayIdForScreenshot
|
|
760
|
+
imeStrategy: null == opts ? void 0 : opts.imeStrategy
|
|
855
761
|
});
|
|
856
762
|
await page.connect();
|
|
857
763
|
return new AndroidAgent(page, opts);
|
package/dist/lib/index.js
CHANGED
|
@@ -250,7 +250,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
250
250
|
async execYadb(keyboardContent) {
|
|
251
251
|
await this.ensureYadb();
|
|
252
252
|
const adb = await this.getAdb();
|
|
253
|
-
await adb.shell(`app_process
|
|
253
|
+
await adb.shell(`app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
|
|
254
254
|
}
|
|
255
255
|
async getElementsInfo() {
|
|
256
256
|
return [];
|
|
@@ -262,36 +262,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
262
262
|
};
|
|
263
263
|
}
|
|
264
264
|
async getScreenSize() {
|
|
265
|
-
var _this_options;
|
|
266
265
|
const adb = await this.getAdb();
|
|
267
|
-
if ('number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId)) try {
|
|
268
|
-
const longDisplayId = await this.getLongDisplayId();
|
|
269
|
-
if (longDisplayId) {
|
|
270
|
-
const stdout = await adb.shell('dumpsys display');
|
|
271
|
-
const lineRegex = new RegExp(`^.*uniqueId "local:${longDisplayId}".*$`, 'm');
|
|
272
|
-
const lineMatch = stdout.match(lineRegex);
|
|
273
|
-
if (lineMatch) {
|
|
274
|
-
const targetLine = lineMatch[0];
|
|
275
|
-
const realMatch = targetLine.match(/real (\d+) x (\d+)/);
|
|
276
|
-
const rotationMatch = targetLine.match(/rotation (\d+)/);
|
|
277
|
-
if (realMatch && rotationMatch) {
|
|
278
|
-
const width = Number(realMatch[1]);
|
|
279
|
-
const height = Number(realMatch[2]);
|
|
280
|
-
const rotation = Number(rotationMatch[1]);
|
|
281
|
-
const sizeStr = `${width}x${height}`;
|
|
282
|
-
debugPage(`Using display info for long ID ${longDisplayId}: ${sizeStr}, rotation: ${rotation}`);
|
|
283
|
-
return {
|
|
284
|
-
override: sizeStr,
|
|
285
|
-
physical: sizeStr,
|
|
286
|
-
orientation: rotation
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
debugPage(`Could not find display info for activeDisplayId ${this.options.activeDisplayId}`);
|
|
292
|
-
} catch (e) {
|
|
293
|
-
debugPage(`Failed to get size from display info for display ${this.options.activeDisplayId}: ${e}`);
|
|
294
|
-
}
|
|
295
266
|
const stdout = await adb.shell([
|
|
296
267
|
'wm',
|
|
297
268
|
'size'
|
|
@@ -310,43 +281,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
310
281
|
debugPage(`Using Physical size: ${physicalSize[1].trim()}`);
|
|
311
282
|
size.physical = physicalSize[1].trim();
|
|
312
283
|
}
|
|
313
|
-
const orientation = await this.getDisplayOrientation();
|
|
314
|
-
if (size.override || size.physical) return {
|
|
315
|
-
...size,
|
|
316
|
-
orientation
|
|
317
|
-
};
|
|
318
|
-
throw new Error(`Failed to get screen size, output: ${stdout}`);
|
|
319
|
-
}
|
|
320
|
-
async getDisplayDensity() {
|
|
321
|
-
var _this_options;
|
|
322
|
-
const adb = await this.getAdb();
|
|
323
|
-
if ('number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId)) try {
|
|
324
|
-
const longDisplayId = await this.getLongDisplayId();
|
|
325
|
-
if (longDisplayId) {
|
|
326
|
-
const stdout = await adb.shell('dumpsys display');
|
|
327
|
-
const lineRegex = new RegExp(`^.*uniqueId "local:${longDisplayId}".*$`, 'm');
|
|
328
|
-
const lineMatch = stdout.match(lineRegex);
|
|
329
|
-
if (lineMatch) {
|
|
330
|
-
const targetLine = lineMatch[0];
|
|
331
|
-
const densityMatch = targetLine.match(/density (\d+)/);
|
|
332
|
-
if (densityMatch) {
|
|
333
|
-
const density = Number(densityMatch[1]);
|
|
334
|
-
debugPage(`Using display density for long ID ${longDisplayId}: ${density}`);
|
|
335
|
-
return density;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
} catch (e) {
|
|
340
|
-
debugPage(`Failed to get density from display info: ${e}`);
|
|
341
|
-
}
|
|
342
|
-
const density = await adb.getScreenDensity();
|
|
343
|
-
return density ?? 160;
|
|
344
|
-
}
|
|
345
|
-
async getDisplayOrientation() {
|
|
346
|
-
const adb = await this.getAdb();
|
|
347
284
|
let orientation = 0;
|
|
348
285
|
try {
|
|
349
|
-
const orientationStdout = await adb.shell(
|
|
286
|
+
const orientationStdout = await adb.shell('dumpsys input | grep SurfaceOrientation');
|
|
350
287
|
const orientationMatch = orientationStdout.match(/SurfaceOrientation:\s*(\d)/);
|
|
351
288
|
if (!orientationMatch) throw new Error('Failed to get orientation from input');
|
|
352
289
|
orientation = Number(orientationMatch[1]);
|
|
@@ -354,7 +291,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
354
291
|
} catch (e) {
|
|
355
292
|
debugPage('Failed to get orientation from input, try display');
|
|
356
293
|
try {
|
|
357
|
-
const orientationStdout = await adb.shell(
|
|
294
|
+
const orientationStdout = await adb.shell('dumpsys display | grep mCurrentOrientation');
|
|
358
295
|
const orientationMatch = orientationStdout.match(/mCurrentOrientation=(\d)/);
|
|
359
296
|
if (!orientationMatch) throw new Error('Failed to get orientation from display');
|
|
360
297
|
orientation = Number(orientationMatch[1]);
|
|
@@ -364,17 +301,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
364
301
|
debugPage('Failed to get orientation from display, default to 0');
|
|
365
302
|
}
|
|
366
303
|
}
|
|
367
|
-
return
|
|
304
|
+
if (size.override || size.physical) return {
|
|
305
|
+
...size,
|
|
306
|
+
orientation
|
|
307
|
+
};
|
|
308
|
+
throw new Error(`Failed to get screen size, output: ${stdout}`);
|
|
368
309
|
}
|
|
369
310
|
async size() {
|
|
370
|
-
await this.getAdb();
|
|
311
|
+
const adb = await this.getAdb();
|
|
371
312
|
const screenSize = await this.getScreenSize();
|
|
372
313
|
const match = (screenSize.override || screenSize.physical).match(/(\d+)x(\d+)/);
|
|
373
314
|
if (!match || match.length < 3) throw new Error(`Unable to parse screen size: ${screenSize}`);
|
|
374
315
|
const isLandscape = 1 === screenSize.orientation || 3 === screenSize.orientation;
|
|
375
316
|
const width = Number.parseInt(match[isLandscape ? 2 : 1], 10);
|
|
376
317
|
const height = Number.parseInt(match[isLandscape ? 1 : 2], 10);
|
|
377
|
-
const densityNum = await
|
|
318
|
+
const densityNum = await adb.getScreenDensity();
|
|
378
319
|
this.devicePixelRatio = Number(densityNum) / 160;
|
|
379
320
|
const { x: logicalWidth, y: logicalHeight } = this.reverseAdjustCoordinates(width, height);
|
|
380
321
|
return {
|
|
@@ -398,18 +339,12 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
398
339
|
};
|
|
399
340
|
}
|
|
400
341
|
async screenshotBase64() {
|
|
401
|
-
var _this_options;
|
|
402
342
|
debugPage('screenshotBase64 begin');
|
|
403
343
|
const { width, height } = await this.size();
|
|
404
344
|
const adb = await this.getAdb();
|
|
405
345
|
let screenshotBuffer;
|
|
406
346
|
const androidScreenshotPath = `/data/local/tmp/midscene_screenshot_${(0, external_node_crypto_namespaceObject.randomUUID)()}.png`;
|
|
407
|
-
const useShellScreencap = 'number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId);
|
|
408
347
|
try {
|
|
409
|
-
if (useShellScreencap) {
|
|
410
|
-
var _this_options1;
|
|
411
|
-
throw new Error(`Display ${null == (_this_options1 = this.options) ? void 0 : _this_options1.activeDisplayId} requires shell screencap`);
|
|
412
|
-
}
|
|
413
348
|
debugPage('Taking screenshot via adb.takeScreenshot');
|
|
414
349
|
screenshotBuffer = await adb.takeScreenshot(null);
|
|
415
350
|
debugPage('adb.takeScreenshot completed');
|
|
@@ -419,17 +354,13 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
419
354
|
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
420
355
|
}
|
|
421
356
|
} catch (error) {
|
|
422
|
-
debugPage(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
|
|
423
357
|
const screenshotPath = (0, utils_namespaceObject.getTmpFile)('png');
|
|
424
358
|
try {
|
|
425
|
-
var _this_options2, _this_options3;
|
|
426
359
|
debugPage('Fallback: taking screenshot via shell screencap');
|
|
427
|
-
const displayId = (null == (_this_options2 = this.options) ? void 0 : _this_options2.useLongDisplayIdForScreenshot) ? await this.getLongDisplayId() : null == (_this_options3 = this.options) ? void 0 : _this_options3.activeDisplayId;
|
|
428
|
-
const displayArg = displayId ? `-d ${displayId}` : '';
|
|
429
360
|
try {
|
|
430
|
-
await adb.shell(`screencap -p ${
|
|
361
|
+
await adb.shell(`screencap -p ${androidScreenshotPath}`);
|
|
431
362
|
debugPage('adb.shell screencap completed');
|
|
432
|
-
} catch (
|
|
363
|
+
} catch (error) {
|
|
433
364
|
debugPage('screencap failed, using forceScreenshot');
|
|
434
365
|
await this.forceScreenshot(androidScreenshotPath);
|
|
435
366
|
debugPage('forceScreenshot completed');
|
|
@@ -472,7 +403,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
472
403
|
await this.ensureYadb();
|
|
473
404
|
const adb = await this.getAdb();
|
|
474
405
|
await this.mouse.click(element.center[0], element.center[1]);
|
|
475
|
-
await adb.shell(
|
|
406
|
+
await adb.shell('app_process -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "~CLEAR~"');
|
|
476
407
|
if (await adb.isSoftKeyboardPresent()) return;
|
|
477
408
|
await this.mouse.click(element.center[0], element.center[1]);
|
|
478
409
|
}
|
|
@@ -674,7 +605,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
674
605
|
async mouseClick(x, y) {
|
|
675
606
|
const adb = await this.getAdb();
|
|
676
607
|
const { x: adjustedX, y: adjustedY } = this.adjustCoordinates(x, y);
|
|
677
|
-
await adb.shell(`input
|
|
608
|
+
await adb.shell(`input swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} 150`);
|
|
678
609
|
}
|
|
679
610
|
async mouseMove(x, y) {
|
|
680
611
|
return Promise.resolve();
|
|
@@ -684,7 +615,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
684
615
|
const { x: fromX, y: fromY } = this.adjustCoordinates(from.x, from.y);
|
|
685
616
|
const { x: toX, y: toY } = this.adjustCoordinates(to.x, to.y);
|
|
686
617
|
const swipeDuration = duration ?? 300;
|
|
687
|
-
await adb.shell(`input
|
|
618
|
+
await adb.shell(`input swipe ${fromX} ${fromY} ${toX} ${toY} ${swipeDuration}`);
|
|
688
619
|
}
|
|
689
620
|
async mouseWheel(deltaX, deltaY, duration) {
|
|
690
621
|
const { width, height } = await this.size();
|
|
@@ -703,7 +634,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
703
634
|
const { x: adjustedEndX, y: adjustedEndY } = this.adjustCoordinates(endX, endY);
|
|
704
635
|
const adb = await this.getAdb();
|
|
705
636
|
const swipeDuration = duration ?? defaultNormalScrollDuration;
|
|
706
|
-
await adb.shell(`input
|
|
637
|
+
await adb.shell(`input swipe ${adjustedStartX} ${adjustedStartY} ${adjustedEndX} ${adjustedEndY} ${swipeDuration}`);
|
|
707
638
|
}
|
|
708
639
|
async destroy() {
|
|
709
640
|
if (this.destroyed) return;
|
|
@@ -718,20 +649,20 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
718
649
|
}
|
|
719
650
|
async back() {
|
|
720
651
|
const adb = await this.getAdb();
|
|
721
|
-
await adb.shell(
|
|
652
|
+
await adb.shell('input keyevent 4');
|
|
722
653
|
}
|
|
723
654
|
async home() {
|
|
724
655
|
const adb = await this.getAdb();
|
|
725
|
-
await adb.shell(
|
|
656
|
+
await adb.shell('input keyevent 3');
|
|
726
657
|
}
|
|
727
658
|
async recentApps() {
|
|
728
659
|
const adb = await this.getAdb();
|
|
729
|
-
await adb.shell(
|
|
660
|
+
await adb.shell('input keyevent 187');
|
|
730
661
|
}
|
|
731
662
|
async longPress(x, y, duration = 1000) {
|
|
732
663
|
const adb = await this.getAdb();
|
|
733
664
|
const { x: adjustedX, y: adjustedY } = this.adjustCoordinates(x, y);
|
|
734
|
-
await adb.shell(`input
|
|
665
|
+
await adb.shell(`input swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} ${duration}`);
|
|
735
666
|
}
|
|
736
667
|
async pullDown(startPoint, distance, duration = 800) {
|
|
737
668
|
const { width, height } = await this.size();
|
|
@@ -754,7 +685,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
754
685
|
const adb = await this.getAdb();
|
|
755
686
|
const { x: fromX, y: fromY } = this.adjustCoordinates(from.x, from.y);
|
|
756
687
|
const { x: toX, y: toY } = this.adjustCoordinates(to.x, to.y);
|
|
757
|
-
await adb.shell(`input
|
|
688
|
+
await adb.shell(`input swipe ${fromX} ${fromY} ${toX} ${toY} ${duration}`);
|
|
758
689
|
}
|
|
759
690
|
async pullUp(startPoint, distance, duration = 600) {
|
|
760
691
|
const { width, height } = await this.size();
|
|
@@ -782,29 +713,6 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
782
713
|
async getElementInfoByXpath(xpath) {
|
|
783
714
|
throw new Error('Not implemented');
|
|
784
715
|
}
|
|
785
|
-
getDisplayArg() {
|
|
786
|
-
var _this_options;
|
|
787
|
-
return 'number' == typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId) ? ` -d ${this.options.activeDisplayId}` : '';
|
|
788
|
-
}
|
|
789
|
-
async getLongDisplayId() {
|
|
790
|
-
var _this_options;
|
|
791
|
-
if ('number' != typeof (null == (_this_options = this.options) ? void 0 : _this_options.activeDisplayId)) return null;
|
|
792
|
-
const adb = await this.getAdb();
|
|
793
|
-
try {
|
|
794
|
-
const stdout = await adb.shell(`dumpsys SurfaceFlinger --display-id ${this.options.activeDisplayId}`);
|
|
795
|
-
const regex = new RegExp(`Display (\\d+) \\(HWC display ${this.options.activeDisplayId}\\):`);
|
|
796
|
-
const displayMatch = stdout.match(regex);
|
|
797
|
-
if (null == displayMatch ? void 0 : displayMatch[1]) {
|
|
798
|
-
debugPage(`Found long display ID: ${displayMatch[1]} for short ID: ${this.options.activeDisplayId}`);
|
|
799
|
-
return displayMatch[1];
|
|
800
|
-
}
|
|
801
|
-
debugPage(`Could not find long display ID for short ID: ${this.options.activeDisplayId}`);
|
|
802
|
-
return null;
|
|
803
|
-
} catch (error) {
|
|
804
|
-
debugPage(`Error getting long display ID: ${error}`);
|
|
805
|
-
return null;
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
716
|
async hideKeyboard(options, timeoutMs = 1000) {
|
|
809
717
|
var _this_options;
|
|
810
718
|
const adb = await this.getAdb();
|
|
@@ -896,9 +804,7 @@ async function agentFromAdbDevice(deviceId, opts) {
|
|
|
896
804
|
androidAdbPath: null == opts ? void 0 : opts.androidAdbPath,
|
|
897
805
|
remoteAdbHost: null == opts ? void 0 : opts.remoteAdbHost,
|
|
898
806
|
remoteAdbPort: null == opts ? void 0 : opts.remoteAdbPort,
|
|
899
|
-
imeStrategy: null == opts ? void 0 : opts.imeStrategy
|
|
900
|
-
activeDisplayId: null == opts ? void 0 : opts.activeDisplayId,
|
|
901
|
-
useLongDisplayIdForScreenshot: null == opts ? void 0 : opts.useLongDisplayIdForScreenshot
|
|
807
|
+
imeStrategy: null == opts ? void 0 : opts.imeStrategy
|
|
902
808
|
});
|
|
903
809
|
await page.connect();
|
|
904
810
|
return new AndroidAgent(page, opts);
|
package/dist/types/index.d.ts
CHANGED
|
@@ -41,8 +41,6 @@ export declare class AndroidDevice implements AndroidDevicePage {
|
|
|
41
41
|
getElementsInfo(): Promise<ElementInfo[]>;
|
|
42
42
|
getElementsNodeTree(): Promise<any>;
|
|
43
43
|
private getScreenSize;
|
|
44
|
-
private getDisplayDensity;
|
|
45
|
-
private getDisplayOrientation;
|
|
46
44
|
size(): Promise<Size>;
|
|
47
45
|
private adjustCoordinates;
|
|
48
46
|
private reverseAdjustCoordinates;
|
|
@@ -99,8 +97,6 @@ export declare class AndroidDevice implements AndroidDevicePage {
|
|
|
99
97
|
getXpathsById(id: string): Promise<string[]>;
|
|
100
98
|
getXpathsByPoint(point: Point, isOrderSensitive: boolean): Promise<string[]>;
|
|
101
99
|
getElementInfoByXpath(xpath: string): Promise<ElementInfo>;
|
|
102
|
-
private getDisplayArg;
|
|
103
|
-
private getLongDisplayId;
|
|
104
100
|
hideKeyboard(options?: AndroidDeviceInputOpt, timeoutMs?: number): Promise<boolean>;
|
|
105
101
|
}
|
|
106
102
|
|
|
@@ -109,8 +105,6 @@ declare type AndroidDeviceOpt = {
|
|
|
109
105
|
remoteAdbHost?: string;
|
|
110
106
|
remoteAdbPort?: number;
|
|
111
107
|
imeStrategy?: 'always-yadb' | 'yadb-for-non-ascii';
|
|
112
|
-
activeDisplayId?: number;
|
|
113
|
-
useLongDisplayIdForScreenshot?: boolean;
|
|
114
108
|
} & AndroidDeviceInputOpt;
|
|
115
109
|
|
|
116
110
|
export declare function getConnectedDevices(): Promise<Device[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/android",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Android automation library for Midscene",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Android UI automation",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"appium-adb": "12.12.1",
|
|
30
|
-
"@midscene/core": "0.
|
|
31
|
-
"@midscene/
|
|
32
|
-
"@midscene/
|
|
30
|
+
"@midscene/core": "0.27.0",
|
|
31
|
+
"@midscene/web": "0.27.0",
|
|
32
|
+
"@midscene/shared": "0.27.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@microsoft/api-extractor": "^7.52.10",
|