@midscene/android 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/cli.mjs +132 -166
- package/dist/es/index.mjs +131 -165
- package/dist/es/mcp-server.mjs +132 -166
- package/dist/lib/cli.js +131 -165
- package/dist/lib/index.js +130 -164
- package/dist/lib/mcp-server.js +131 -165
- package/dist/types/index.d.ts +10 -12
- package/dist/types/mcp-server.d.ts +10 -12
- package/package.json +4 -4
package/dist/lib/index.js
CHANGED
|
@@ -621,103 +621,30 @@ var __webpack_exports__ = {};
|
|
|
621
621
|
}
|
|
622
622
|
class AndroidDevice {
|
|
623
623
|
actionSpace() {
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
await
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
(0, device_namespaceObject.defineAction)({
|
|
636
|
-
name: 'Input',
|
|
637
|
-
description: 'Input text into the input field',
|
|
638
|
-
interfaceAlias: 'aiInput',
|
|
639
|
-
paramSchema: core_namespaceObject.z.object({
|
|
640
|
-
value: core_namespaceObject.z.string().describe('The text to input. Provide the final content for replace/append modes, or an empty string when using clear mode to remove existing text.'),
|
|
641
|
-
autoDismissKeyboard: core_namespaceObject.z.boolean().optional().describe('If true, the keyboard will be dismissed after the input is completed. Do not set it unless the user asks you to do so.'),
|
|
642
|
-
mode: core_namespaceObject.z.preprocess((val)=>'append' === val ? 'typeOnly' : val, core_namespaceObject.z["enum"]([
|
|
643
|
-
'replace',
|
|
644
|
-
'clear',
|
|
645
|
-
'typeOnly'
|
|
646
|
-
]).default('replace').optional().describe('Input mode: "replace" (default) - clear the field and input the value; "typeOnly" - type the value directly without clearing the field first; "clear" - clear the field without inputting new text.')),
|
|
647
|
-
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
648
|
-
}),
|
|
649
|
-
sample: {
|
|
650
|
-
value: 'test@example.com',
|
|
651
|
-
locate: {
|
|
652
|
-
prompt: 'the email input field'
|
|
653
|
-
}
|
|
624
|
+
const mobileActionContext = {
|
|
625
|
+
input: this.inputPrimitives,
|
|
626
|
+
size: ()=>this.size(),
|
|
627
|
+
sleep: async (timeMs)=>{
|
|
628
|
+
await (0, utils_namespaceObject.sleep)(timeMs);
|
|
629
|
+
},
|
|
630
|
+
getDefaultAutoDismissKeyboard: ()=>this.options?.autoDismissKeyboard,
|
|
631
|
+
systemActions: {
|
|
632
|
+
backButton: {
|
|
633
|
+
name: 'AndroidBackButton',
|
|
634
|
+
description: 'Trigger the system "back" operation on Android devices'
|
|
654
635
|
},
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
autoDismissKeyboard
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
}),
|
|
666
|
-
(0, device_namespaceObject.defineActionScroll)(async (param)=>{
|
|
667
|
-
const element = param.locate;
|
|
668
|
-
const startingPoint = element ? {
|
|
669
|
-
left: element.center[0],
|
|
670
|
-
top: element.center[1]
|
|
671
|
-
} : void 0;
|
|
672
|
-
const scrollToEventName = param?.scrollType;
|
|
673
|
-
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
674
|
-
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
675
|
-
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
676
|
-
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
677
|
-
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
678
|
-
else {
|
|
679
|
-
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
680
|
-
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
681
|
-
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
682
|
-
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
683
|
-
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
684
|
-
await (0, utils_namespaceObject.sleep)(500);
|
|
685
|
-
}
|
|
686
|
-
}),
|
|
687
|
-
(0, device_namespaceObject.defineActionDragAndDrop)(async (param)=>{
|
|
688
|
-
const from = param.from;
|
|
689
|
-
const to = param.to;
|
|
690
|
-
external_node_assert_default()(from, 'missing "from" param for drag and drop');
|
|
691
|
-
external_node_assert_default()(to, 'missing "to" param for drag and drop');
|
|
692
|
-
await this.mouseDrag({
|
|
693
|
-
x: from.center[0],
|
|
694
|
-
y: from.center[1]
|
|
695
|
-
}, {
|
|
696
|
-
x: to.center[0],
|
|
697
|
-
y: to.center[1]
|
|
698
|
-
});
|
|
699
|
-
}),
|
|
700
|
-
(0, device_namespaceObject.defineActionSwipe)(async (param)=>{
|
|
701
|
-
const { startPoint, endPoint, duration, repeatCount } = (0, device_namespaceObject.normalizeMobileSwipeParam)(param, await this.size());
|
|
702
|
-
for(let i = 0; i < repeatCount; i++)await this.mouseDrag(startPoint, endPoint, duration);
|
|
703
|
-
}),
|
|
704
|
-
(0, device_namespaceObject.defineActionKeyboardPress)(async (param)=>{
|
|
705
|
-
await this.keyboardPress(param.keyName);
|
|
706
|
-
}),
|
|
707
|
-
(0, device_namespaceObject.defineActionCursorMove)(async (param)=>{
|
|
708
|
-
const arrowKey = 'left' === param.direction ? 'ArrowLeft' : 'ArrowRight';
|
|
709
|
-
const times = param.times ?? 1;
|
|
710
|
-
for(let i = 0; i < times; i++){
|
|
711
|
-
await this.keyboardPress(arrowKey);
|
|
712
|
-
await (0, utils_namespaceObject.sleep)(100);
|
|
636
|
+
homeButton: {
|
|
637
|
+
name: 'AndroidHomeButton',
|
|
638
|
+
description: 'Trigger the system "home" operation on Android devices'
|
|
639
|
+
},
|
|
640
|
+
recentAppsButton: {
|
|
641
|
+
name: 'AndroidRecentAppsButton',
|
|
642
|
+
description: 'Trigger the system "recent apps" operation on Android devices'
|
|
713
643
|
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
const [x, y] = element.center;
|
|
719
|
-
await this.longPress(x, y, param?.duration);
|
|
720
|
-
}),
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
const defaultActions = [
|
|
647
|
+
...(0, device_namespaceObject.createDefaultMobileActions)(mobileActionContext),
|
|
721
648
|
(0, device_namespaceObject.defineAction)({
|
|
722
649
|
name: 'PullGesture',
|
|
723
650
|
description: 'Trigger pull down to refresh or pull up actions',
|
|
@@ -747,19 +674,6 @@ var __webpack_exports__ = {};
|
|
|
747
674
|
else if ('up' === param.direction) await this.pullUp(startPoint, param.distance, param.duration);
|
|
748
675
|
else throw new Error(`Unknown pull direction: ${param.direction}`);
|
|
749
676
|
}
|
|
750
|
-
}),
|
|
751
|
-
(0, device_namespaceObject.defineActionPinch)(async (param)=>{
|
|
752
|
-
const { centerX, centerY, startDistance, endDistance, duration } = (0, device_namespaceObject.normalizePinchParam)(param, await this.size());
|
|
753
|
-
const { x: adjCenterX, y: adjCenterY } = await this.adjustCoordinates(centerX, centerY);
|
|
754
|
-
const ratio = 0 !== adjCenterX && 0 !== centerX ? adjCenterX / centerX : 1;
|
|
755
|
-
const adjStartDist = Math.round(startDistance * ratio);
|
|
756
|
-
const adjEndDist = Math.round(endDistance * ratio);
|
|
757
|
-
await this.ensureYadb();
|
|
758
|
-
const adb = await this.getAdb();
|
|
759
|
-
await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -pinch ${adjCenterX} ${adjCenterY} ${adjStartDist} ${adjEndDist} ${duration}`);
|
|
760
|
-
}),
|
|
761
|
-
(0, device_namespaceObject.defineActionClearInput)(async (param)=>{
|
|
762
|
-
await this.clearInput(param.locate);
|
|
763
677
|
})
|
|
764
678
|
];
|
|
765
679
|
const platformSpecificActions = Object.values(createPlatformActions(this));
|
|
@@ -770,6 +684,27 @@ var __webpack_exports__ = {};
|
|
|
770
684
|
...customActions
|
|
771
685
|
];
|
|
772
686
|
}
|
|
687
|
+
async performActionScroll(param) {
|
|
688
|
+
const element = param.locate;
|
|
689
|
+
const startingPoint = element ? {
|
|
690
|
+
left: element.center[0],
|
|
691
|
+
top: element.center[1]
|
|
692
|
+
} : void 0;
|
|
693
|
+
const scrollToEventName = param?.scrollType;
|
|
694
|
+
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
695
|
+
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
696
|
+
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
697
|
+
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
698
|
+
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
699
|
+
else {
|
|
700
|
+
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
701
|
+
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
702
|
+
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
703
|
+
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
704
|
+
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
705
|
+
await (0, utils_namespaceObject.sleep)(500);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
773
708
|
describe() {
|
|
774
709
|
return this.description || `DeviceId: ${this.deviceId}`;
|
|
775
710
|
}
|
|
@@ -1257,14 +1192,20 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1257
1192
|
return result;
|
|
1258
1193
|
}
|
|
1259
1194
|
async clearInput(element) {
|
|
1260
|
-
if (element) await this.
|
|
1195
|
+
if (element) await this.tapPoint({
|
|
1196
|
+
x: element.center[0],
|
|
1197
|
+
y: element.center[1]
|
|
1198
|
+
});
|
|
1261
1199
|
await this.ensureYadb();
|
|
1262
1200
|
const adb = await this.getAdb();
|
|
1263
1201
|
const IME_STRATEGY = (this.options?.imeStrategy || env_namespaceObject.globalConfigManager.getEnvConfigValue(env_namespaceObject.MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
|
|
1264
1202
|
if (IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII) await adb.clearTextField(100);
|
|
1265
1203
|
else await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboardClear`);
|
|
1266
1204
|
if (await adb.isSoftKeyboardPresent()) return;
|
|
1267
|
-
if (element) await this.
|
|
1205
|
+
if (element) await this.tapPoint({
|
|
1206
|
+
x: element.center[0],
|
|
1207
|
+
y: element.center[1]
|
|
1208
|
+
});
|
|
1268
1209
|
}
|
|
1269
1210
|
async forceScreenshot(path) {
|
|
1270
1211
|
await this.ensureYadb();
|
|
@@ -1285,7 +1226,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1285
1226
|
x: start.x,
|
|
1286
1227
|
y: Math.round(height)
|
|
1287
1228
|
};
|
|
1288
|
-
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1229
|
+
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1289
1230
|
await (0, utils_namespaceObject.sleep)(1000);
|
|
1290
1231
|
return;
|
|
1291
1232
|
}
|
|
@@ -1302,7 +1243,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1302
1243
|
x: start.x,
|
|
1303
1244
|
y: 0
|
|
1304
1245
|
};
|
|
1305
|
-
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1246
|
+
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1306
1247
|
await (0, utils_namespaceObject.sleep)(1000);
|
|
1307
1248
|
return;
|
|
1308
1249
|
}
|
|
@@ -1320,7 +1261,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1320
1261
|
x: Math.round(width),
|
|
1321
1262
|
y: start.y
|
|
1322
1263
|
};
|
|
1323
|
-
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1264
|
+
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1324
1265
|
await (0, utils_namespaceObject.sleep)(1000);
|
|
1325
1266
|
return;
|
|
1326
1267
|
}
|
|
@@ -1337,7 +1278,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1337
1278
|
x: 0,
|
|
1338
1279
|
y: start.y
|
|
1339
1280
|
};
|
|
1340
|
-
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1281
|
+
await (0, shared_utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1341
1282
|
await (0, utils_namespaceObject.sleep)(1000);
|
|
1342
1283
|
return;
|
|
1343
1284
|
}
|
|
@@ -1355,7 +1296,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1355
1296
|
};
|
|
1356
1297
|
const end = this.calculateScrollEndPoint(start, 0, scrollDistance, 0, height);
|
|
1357
1298
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('up', scrollDistance, Math.abs(end.y - start.y));
|
|
1358
|
-
await this.
|
|
1299
|
+
await this.dragPoint(start, end);
|
|
1359
1300
|
return;
|
|
1360
1301
|
}
|
|
1361
1302
|
await this.scroll(0, -scrollDistance, void 0, hasExplicitDistance, 'up');
|
|
@@ -1371,7 +1312,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1371
1312
|
};
|
|
1372
1313
|
const end = this.calculateScrollEndPoint(start, 0, -scrollDistance, 0, height);
|
|
1373
1314
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('down', scrollDistance, Math.abs(end.y - start.y));
|
|
1374
|
-
await this.
|
|
1315
|
+
await this.dragPoint(start, end);
|
|
1375
1316
|
return;
|
|
1376
1317
|
}
|
|
1377
1318
|
await this.scroll(0, scrollDistance, void 0, hasExplicitDistance, 'down');
|
|
@@ -1387,7 +1328,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1387
1328
|
};
|
|
1388
1329
|
const end = this.calculateScrollEndPoint(start, scrollDistance, 0, width, 0);
|
|
1389
1330
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('left', scrollDistance, Math.abs(end.x - start.x));
|
|
1390
|
-
await this.
|
|
1331
|
+
await this.dragPoint(start, end);
|
|
1391
1332
|
return;
|
|
1392
1333
|
}
|
|
1393
1334
|
await this.scroll(-scrollDistance, 0, void 0, hasExplicitDistance, 'left');
|
|
@@ -1403,7 +1344,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1403
1344
|
};
|
|
1404
1345
|
const end = this.calculateScrollEndPoint(start, -scrollDistance, 0, width, 0);
|
|
1405
1346
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('right', scrollDistance, Math.abs(end.x - start.x));
|
|
1406
|
-
await this.
|
|
1347
|
+
await this.dragPoint(start, end);
|
|
1407
1348
|
return;
|
|
1408
1349
|
}
|
|
1409
1350
|
await this.scroll(scrollDistance, 0, void 0, hasExplicitDistance, 'right');
|
|
@@ -1424,7 +1365,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1424
1365
|
const hasBothQuotes = text.includes('"') && text.includes("'");
|
|
1425
1366
|
return hasNonAscii || hasFormatSpecifiers || hasShellSpecialChars || hasBothQuotes;
|
|
1426
1367
|
}
|
|
1427
|
-
async
|
|
1368
|
+
async typeText(text, options) {
|
|
1428
1369
|
if (!text) return;
|
|
1429
1370
|
const adb = await this.getAdb();
|
|
1430
1371
|
const IME_STRATEGY = (this.options?.imeStrategy || env_namespaceObject.globalConfigManager.getEnvConfigValue(env_namespaceObject.MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
|
|
@@ -1461,7 +1402,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1461
1402
|
const lowerKey = key.toLowerCase();
|
|
1462
1403
|
return keyMap[lowerKey] || key;
|
|
1463
1404
|
}
|
|
1464
|
-
async
|
|
1405
|
+
async pressKey(key) {
|
|
1465
1406
|
const keyCodeMap = {
|
|
1466
1407
|
Enter: 66,
|
|
1467
1408
|
Backspace: 67,
|
|
@@ -1483,14 +1424,14 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1483
1424
|
if (asciiCode >= 65 && asciiCode <= 90) await adb.keyevent(asciiCode - 36);
|
|
1484
1425
|
}
|
|
1485
1426
|
}
|
|
1486
|
-
async
|
|
1427
|
+
async tapPoint(point) {
|
|
1487
1428
|
const adb = await this.getAdb();
|
|
1488
|
-
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(x, y);
|
|
1429
|
+
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(point.x, point.y);
|
|
1489
1430
|
await adb.shell(`input${this.getDisplayArg()} swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} 150`);
|
|
1490
1431
|
}
|
|
1491
|
-
async
|
|
1432
|
+
async doubleTapPoint(point) {
|
|
1492
1433
|
const adb = await this.getAdb();
|
|
1493
|
-
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(x, y);
|
|
1434
|
+
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(point.x, point.y);
|
|
1494
1435
|
const tapCommand = `input${this.getDisplayArg()} tap ${adjustedX} ${adjustedY}`;
|
|
1495
1436
|
await adb.shell(tapCommand);
|
|
1496
1437
|
await (0, utils_namespaceObject.sleep)(50);
|
|
@@ -1499,12 +1440,14 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1499
1440
|
async mouseMove() {
|
|
1500
1441
|
return Promise.resolve();
|
|
1501
1442
|
}
|
|
1502
|
-
async
|
|
1443
|
+
async dragPoint(from, to, duration) {
|
|
1444
|
+
await this.swipePoint(from, to, duration ?? defaultNormalScrollDuration);
|
|
1445
|
+
}
|
|
1446
|
+
async swipePoint(from, to, duration) {
|
|
1503
1447
|
const adb = await this.getAdb();
|
|
1504
1448
|
const { x: fromX, y: fromY } = await this.adjustCoordinates(from.x, from.y);
|
|
1505
1449
|
const { x: toX, y: toY } = await this.adjustCoordinates(to.x, to.y);
|
|
1506
|
-
|
|
1507
|
-
await adb.shell(`input${this.getDisplayArg()} swipe ${fromX} ${fromY} ${toX} ${toY} ${swipeDuration}`);
|
|
1450
|
+
await adb.shell(`input${this.getDisplayArg()} swipe ${fromX} ${fromY} ${toX} ${toY} ${duration}`);
|
|
1508
1451
|
}
|
|
1509
1452
|
async scroll(deltaX, deltaY, duration, warnOnClamp = false, direction) {
|
|
1510
1453
|
if (0 === deltaX && 0 === deltaY) throw new Error('Scroll distance cannot be zero in both directions');
|
|
@@ -1527,11 +1470,14 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1527
1470
|
}
|
|
1528
1471
|
const endX = Math.round(startX - deltaX);
|
|
1529
1472
|
const endY = Math.round(startY - deltaY);
|
|
1530
|
-
const { x: adjustedStartX, y: adjustedStartY } = await this.adjustCoordinates(startX, startY);
|
|
1531
|
-
const { x: adjustedEndX, y: adjustedEndY } = await this.adjustCoordinates(endX, endY);
|
|
1532
|
-
const adb = await this.getAdb();
|
|
1533
1473
|
const swipeDuration = duration ?? defaultNormalScrollDuration;
|
|
1534
|
-
await
|
|
1474
|
+
await this.swipePoint({
|
|
1475
|
+
x: startX,
|
|
1476
|
+
y: startY
|
|
1477
|
+
}, {
|
|
1478
|
+
x: endX,
|
|
1479
|
+
y: endY
|
|
1480
|
+
}, swipeDuration);
|
|
1535
1481
|
}
|
|
1536
1482
|
async destroy() {
|
|
1537
1483
|
if (this.destroyed) return;
|
|
@@ -1579,9 +1525,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1579
1525
|
const adb = await this.getAdb();
|
|
1580
1526
|
await adb.shell(`input${this.getDisplayArg()} keyevent 187`);
|
|
1581
1527
|
}
|
|
1582
|
-
async
|
|
1528
|
+
async longPressPoint(point, duration = 2000) {
|
|
1583
1529
|
const adb = await this.getAdb();
|
|
1584
|
-
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(x, y);
|
|
1530
|
+
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(point.x, point.y);
|
|
1585
1531
|
await adb.shell(`input${this.getDisplayArg()} swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} ${duration}`);
|
|
1586
1532
|
}
|
|
1587
1533
|
async pullDown(startPoint, distance, duration = 800) {
|
|
@@ -1602,10 +1548,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1602
1548
|
await (0, utils_namespaceObject.sleep)(200);
|
|
1603
1549
|
}
|
|
1604
1550
|
async pullDrag(from, to, duration) {
|
|
1605
|
-
|
|
1606
|
-
const { x: fromX, y: fromY } = await this.adjustCoordinates(from.x, from.y);
|
|
1607
|
-
const { x: toX, y: toY } = await this.adjustCoordinates(to.x, to.y);
|
|
1608
|
-
await adb.shell(`input${this.getDisplayArg()} swipe ${fromX} ${fromY} ${toX} ${toY} ${duration}`);
|
|
1551
|
+
await this.swipePoint(from, to, duration);
|
|
1609
1552
|
}
|
|
1610
1553
|
async pullUp(startPoint, distance, duration = 600) {
|
|
1611
1554
|
const { width, height } = await this.size();
|
|
@@ -1706,6 +1649,56 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1706
1649
|
device_define_property(this, "interfaceType", 'android');
|
|
1707
1650
|
device_define_property(this, "uri", void 0);
|
|
1708
1651
|
device_define_property(this, "options", void 0);
|
|
1652
|
+
device_define_property(this, "inputPrimitives", {
|
|
1653
|
+
pointer: {
|
|
1654
|
+
tap: (point)=>this.tapPoint(point),
|
|
1655
|
+
doubleClick: (point)=>this.doubleTapPoint(point),
|
|
1656
|
+
longPress: (point, opts)=>this.longPressPoint(point, opts?.duration),
|
|
1657
|
+
dragAndDrop: (from, to)=>this.dragPoint(from, to)
|
|
1658
|
+
},
|
|
1659
|
+
keyboard: {
|
|
1660
|
+
keyboardPress: (keyName)=>this.pressKey(keyName),
|
|
1661
|
+
typeText: async (value, opts)=>{
|
|
1662
|
+
const target = opts?.target;
|
|
1663
|
+
if (target && opts?.replace !== false) await this.clearInput(target);
|
|
1664
|
+
else if (target) await this.tapPoint({
|
|
1665
|
+
x: target.center[0],
|
|
1666
|
+
y: target.center[1]
|
|
1667
|
+
});
|
|
1668
|
+
if (opts?.focusOnly) return;
|
|
1669
|
+
await this.typeText(value, opts);
|
|
1670
|
+
},
|
|
1671
|
+
clearInput: (target)=>this.clearInput(target),
|
|
1672
|
+
cursorMove: async (direction, times = 1)=>{
|
|
1673
|
+
const arrowKey = 'left' === direction ? 'ArrowLeft' : 'ArrowRight';
|
|
1674
|
+
for(let i = 0; i < times; i++)await this.pressKey(arrowKey);
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
touch: {
|
|
1678
|
+
swipe: async (start, end, opts)=>{
|
|
1679
|
+
const duration = opts?.duration ?? 300;
|
|
1680
|
+
const repeatCount = opts?.repeat ?? 1;
|
|
1681
|
+
for(let i = 0; i < repeatCount; i++)await this.dragPoint(start, end, duration);
|
|
1682
|
+
},
|
|
1683
|
+
pinch: async (center, opts)=>{
|
|
1684
|
+
const { x: adjCenterX, y: adjCenterY } = await this.adjustCoordinates(Math.round(center.x), Math.round(center.y));
|
|
1685
|
+
const ratio = 0 !== adjCenterX && 0 !== center.x ? adjCenterX / center.x : 1;
|
|
1686
|
+
const adjStartDist = Math.round(opts.startDistance * ratio);
|
|
1687
|
+
const adjEndDist = Math.round(opts.endDistance * ratio);
|
|
1688
|
+
await this.ensureYadb();
|
|
1689
|
+
const adb = await this.getAdb();
|
|
1690
|
+
await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -pinch ${adjCenterX} ${adjCenterY} ${adjStartDist} ${adjEndDist} ${opts.duration}`);
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
scroll: {
|
|
1694
|
+
scroll: (param)=>this.performActionScroll(param)
|
|
1695
|
+
},
|
|
1696
|
+
system: {
|
|
1697
|
+
backButton: ()=>this.back(),
|
|
1698
|
+
homeButton: ()=>this.home(),
|
|
1699
|
+
recentAppsButton: ()=>this.recentApps()
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1709
1702
|
external_node_assert_default()(deviceId, 'deviceId is required for AndroidDevice');
|
|
1710
1703
|
this.deviceId = deviceId;
|
|
1711
1704
|
this.options = options;
|
|
@@ -1756,37 +1749,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1756
1749
|
description: 'Terminate (force-stop) an Android app by package name',
|
|
1757
1750
|
interfaceAlias: 'terminate',
|
|
1758
1751
|
paramSchema: terminateParamSchema,
|
|
1759
|
-
delayBeforeRunner: 0,
|
|
1760
|
-
delayAfterRunner: 0,
|
|
1761
1752
|
call: async (param)=>{
|
|
1762
1753
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Terminate requires a non-empty uri parameter');
|
|
1763
1754
|
await device.terminate(param.uri);
|
|
1764
1755
|
}
|
|
1765
|
-
}),
|
|
1766
|
-
AndroidBackButton: (0, device_namespaceObject.defineAction)({
|
|
1767
|
-
name: 'AndroidBackButton',
|
|
1768
|
-
description: 'Trigger the system "back" operation on Android devices',
|
|
1769
|
-
delayBeforeRunner: 0,
|
|
1770
|
-
delayAfterRunner: 0,
|
|
1771
|
-
call: async ()=>{
|
|
1772
|
-
await device.back();
|
|
1773
|
-
}
|
|
1774
|
-
}),
|
|
1775
|
-
AndroidHomeButton: (0, device_namespaceObject.defineAction)({
|
|
1776
|
-
name: 'AndroidHomeButton',
|
|
1777
|
-
description: 'Trigger the system "home" operation on Android devices',
|
|
1778
|
-
delayBeforeRunner: 0,
|
|
1779
|
-
delayAfterRunner: 0,
|
|
1780
|
-
call: async ()=>{
|
|
1781
|
-
await device.home();
|
|
1782
|
-
}
|
|
1783
|
-
}),
|
|
1784
|
-
AndroidRecentAppsButton: (0, device_namespaceObject.defineAction)({
|
|
1785
|
-
name: 'AndroidRecentAppsButton',
|
|
1786
|
-
description: 'Trigger the system "recent apps" operation on Android devices',
|
|
1787
|
-
call: async ()=>{
|
|
1788
|
-
await device.recentApps();
|
|
1789
|
-
}
|
|
1790
1756
|
})
|
|
1791
1757
|
});
|
|
1792
1758
|
const agent_namespaceObject = require("@midscene/core/agent");
|