@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/cli.js
CHANGED
|
@@ -699,103 +699,30 @@ var __webpack_exports__ = {};
|
|
|
699
699
|
}
|
|
700
700
|
class AndroidDevice {
|
|
701
701
|
actionSpace() {
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
await
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
(0, device_namespaceObject.defineAction)({
|
|
714
|
-
name: 'Input',
|
|
715
|
-
description: 'Input text into the input field',
|
|
716
|
-
interfaceAlias: 'aiInput',
|
|
717
|
-
paramSchema: core_namespaceObject.z.object({
|
|
718
|
-
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.'),
|
|
719
|
-
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.'),
|
|
720
|
-
mode: core_namespaceObject.z.preprocess((val)=>'append' === val ? 'typeOnly' : val, core_namespaceObject.z["enum"]([
|
|
721
|
-
'replace',
|
|
722
|
-
'clear',
|
|
723
|
-
'typeOnly'
|
|
724
|
-
]).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.')),
|
|
725
|
-
locate: (0, core_namespaceObject.getMidsceneLocationSchema)().describe('The input field to be filled').optional()
|
|
726
|
-
}),
|
|
727
|
-
sample: {
|
|
728
|
-
value: 'test@example.com',
|
|
729
|
-
locate: {
|
|
730
|
-
prompt: 'the email input field'
|
|
731
|
-
}
|
|
702
|
+
const mobileActionContext = {
|
|
703
|
+
input: this.inputPrimitives,
|
|
704
|
+
size: ()=>this.size(),
|
|
705
|
+
sleep: async (timeMs)=>{
|
|
706
|
+
await (0, core_utils_namespaceObject.sleep)(timeMs);
|
|
707
|
+
},
|
|
708
|
+
getDefaultAutoDismissKeyboard: ()=>this.options?.autoDismissKeyboard,
|
|
709
|
+
systemActions: {
|
|
710
|
+
backButton: {
|
|
711
|
+
name: 'AndroidBackButton',
|
|
712
|
+
description: 'Trigger the system "back" operation on Android devices'
|
|
732
713
|
},
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
autoDismissKeyboard
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
}),
|
|
744
|
-
(0, device_namespaceObject.defineActionScroll)(async (param)=>{
|
|
745
|
-
const element = param.locate;
|
|
746
|
-
const startingPoint = element ? {
|
|
747
|
-
left: element.center[0],
|
|
748
|
-
top: element.center[1]
|
|
749
|
-
} : void 0;
|
|
750
|
-
const scrollToEventName = param?.scrollType;
|
|
751
|
-
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
752
|
-
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
753
|
-
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
754
|
-
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
755
|
-
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
756
|
-
else {
|
|
757
|
-
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
758
|
-
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
759
|
-
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
760
|
-
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
761
|
-
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
762
|
-
await (0, core_utils_namespaceObject.sleep)(500);
|
|
763
|
-
}
|
|
764
|
-
}),
|
|
765
|
-
(0, device_namespaceObject.defineActionDragAndDrop)(async (param)=>{
|
|
766
|
-
const from = param.from;
|
|
767
|
-
const to = param.to;
|
|
768
|
-
external_node_assert_default()(from, 'missing "from" param for drag and drop');
|
|
769
|
-
external_node_assert_default()(to, 'missing "to" param for drag and drop');
|
|
770
|
-
await this.mouseDrag({
|
|
771
|
-
x: from.center[0],
|
|
772
|
-
y: from.center[1]
|
|
773
|
-
}, {
|
|
774
|
-
x: to.center[0],
|
|
775
|
-
y: to.center[1]
|
|
776
|
-
});
|
|
777
|
-
}),
|
|
778
|
-
(0, device_namespaceObject.defineActionSwipe)(async (param)=>{
|
|
779
|
-
const { startPoint, endPoint, duration, repeatCount } = (0, device_namespaceObject.normalizeMobileSwipeParam)(param, await this.size());
|
|
780
|
-
for(let i = 0; i < repeatCount; i++)await this.mouseDrag(startPoint, endPoint, duration);
|
|
781
|
-
}),
|
|
782
|
-
(0, device_namespaceObject.defineActionKeyboardPress)(async (param)=>{
|
|
783
|
-
await this.keyboardPress(param.keyName);
|
|
784
|
-
}),
|
|
785
|
-
(0, device_namespaceObject.defineActionCursorMove)(async (param)=>{
|
|
786
|
-
const arrowKey = 'left' === param.direction ? 'ArrowLeft' : 'ArrowRight';
|
|
787
|
-
const times = param.times ?? 1;
|
|
788
|
-
for(let i = 0; i < times; i++){
|
|
789
|
-
await this.keyboardPress(arrowKey);
|
|
790
|
-
await (0, core_utils_namespaceObject.sleep)(100);
|
|
714
|
+
homeButton: {
|
|
715
|
+
name: 'AndroidHomeButton',
|
|
716
|
+
description: 'Trigger the system "home" operation on Android devices'
|
|
717
|
+
},
|
|
718
|
+
recentAppsButton: {
|
|
719
|
+
name: 'AndroidRecentAppsButton',
|
|
720
|
+
description: 'Trigger the system "recent apps" operation on Android devices'
|
|
791
721
|
}
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const [x, y] = element.center;
|
|
797
|
-
await this.longPress(x, y, param?.duration);
|
|
798
|
-
}),
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
const defaultActions = [
|
|
725
|
+
...(0, device_namespaceObject.createDefaultMobileActions)(mobileActionContext),
|
|
799
726
|
(0, device_namespaceObject.defineAction)({
|
|
800
727
|
name: 'PullGesture',
|
|
801
728
|
description: 'Trigger pull down to refresh or pull up actions',
|
|
@@ -825,19 +752,6 @@ var __webpack_exports__ = {};
|
|
|
825
752
|
else if ('up' === param.direction) await this.pullUp(startPoint, param.distance, param.duration);
|
|
826
753
|
else throw new Error(`Unknown pull direction: ${param.direction}`);
|
|
827
754
|
}
|
|
828
|
-
}),
|
|
829
|
-
(0, device_namespaceObject.defineActionPinch)(async (param)=>{
|
|
830
|
-
const { centerX, centerY, startDistance, endDistance, duration } = (0, device_namespaceObject.normalizePinchParam)(param, await this.size());
|
|
831
|
-
const { x: adjCenterX, y: adjCenterY } = await this.adjustCoordinates(centerX, centerY);
|
|
832
|
-
const ratio = 0 !== adjCenterX && 0 !== centerX ? adjCenterX / centerX : 1;
|
|
833
|
-
const adjStartDist = Math.round(startDistance * ratio);
|
|
834
|
-
const adjEndDist = Math.round(endDistance * ratio);
|
|
835
|
-
await this.ensureYadb();
|
|
836
|
-
const adb = await this.getAdb();
|
|
837
|
-
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}`);
|
|
838
|
-
}),
|
|
839
|
-
(0, device_namespaceObject.defineActionClearInput)(async (param)=>{
|
|
840
|
-
await this.clearInput(param.locate);
|
|
841
755
|
})
|
|
842
756
|
];
|
|
843
757
|
const platformSpecificActions = Object.values(createPlatformActions(this));
|
|
@@ -848,6 +762,27 @@ var __webpack_exports__ = {};
|
|
|
848
762
|
...customActions
|
|
849
763
|
];
|
|
850
764
|
}
|
|
765
|
+
async performActionScroll(param) {
|
|
766
|
+
const element = param.locate;
|
|
767
|
+
const startingPoint = element ? {
|
|
768
|
+
left: element.center[0],
|
|
769
|
+
top: element.center[1]
|
|
770
|
+
} : void 0;
|
|
771
|
+
const scrollToEventName = param?.scrollType;
|
|
772
|
+
if ('scrollToTop' === scrollToEventName) await this.scrollUntilTop(startingPoint);
|
|
773
|
+
else if ('scrollToBottom' === scrollToEventName) await this.scrollUntilBottom(startingPoint);
|
|
774
|
+
else if ('scrollToRight' === scrollToEventName) await this.scrollUntilRight(startingPoint);
|
|
775
|
+
else if ('scrollToLeft' === scrollToEventName) await this.scrollUntilLeft(startingPoint);
|
|
776
|
+
else if ('singleAction' !== scrollToEventName && scrollToEventName) throw new Error(`Unknown scroll event type: ${scrollToEventName}, param: ${JSON.stringify(param)}`);
|
|
777
|
+
else {
|
|
778
|
+
if (param?.direction !== 'down' && param && param.direction) if ('up' === param.direction) await this.scrollUp(param.distance || void 0, startingPoint);
|
|
779
|
+
else if ('left' === param.direction) await this.scrollLeft(param.distance || void 0, startingPoint);
|
|
780
|
+
else if ('right' === param.direction) await this.scrollRight(param.distance || void 0, startingPoint);
|
|
781
|
+
else throw new Error(`Unknown scroll direction: ${param.direction}`);
|
|
782
|
+
else await this.scrollDown(param?.distance || void 0, startingPoint);
|
|
783
|
+
await (0, core_utils_namespaceObject.sleep)(500);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
851
786
|
describe() {
|
|
852
787
|
return this.description || `DeviceId: ${this.deviceId}`;
|
|
853
788
|
}
|
|
@@ -1335,14 +1270,20 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1335
1270
|
return result;
|
|
1336
1271
|
}
|
|
1337
1272
|
async clearInput(element) {
|
|
1338
|
-
if (element) await this.
|
|
1273
|
+
if (element) await this.tapPoint({
|
|
1274
|
+
x: element.center[0],
|
|
1275
|
+
y: element.center[1]
|
|
1276
|
+
});
|
|
1339
1277
|
await this.ensureYadb();
|
|
1340
1278
|
const adb = await this.getAdb();
|
|
1341
1279
|
const IME_STRATEGY = (this.options?.imeStrategy || env_namespaceObject.globalConfigManager.getEnvConfigValue(env_namespaceObject.MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
|
|
1342
1280
|
if (IME_STRATEGY === IME_STRATEGY_YADB_FOR_NON_ASCII) await adb.clearTextField(100);
|
|
1343
1281
|
else await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboardClear`);
|
|
1344
1282
|
if (await adb.isSoftKeyboardPresent()) return;
|
|
1345
|
-
if (element) await this.
|
|
1283
|
+
if (element) await this.tapPoint({
|
|
1284
|
+
x: element.center[0],
|
|
1285
|
+
y: element.center[1]
|
|
1286
|
+
});
|
|
1346
1287
|
}
|
|
1347
1288
|
async forceScreenshot(path) {
|
|
1348
1289
|
await this.ensureYadb();
|
|
@@ -1363,7 +1304,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1363
1304
|
x: start.x,
|
|
1364
1305
|
y: Math.round(height)
|
|
1365
1306
|
};
|
|
1366
|
-
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1307
|
+
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1367
1308
|
await (0, core_utils_namespaceObject.sleep)(1000);
|
|
1368
1309
|
return;
|
|
1369
1310
|
}
|
|
@@ -1380,7 +1321,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1380
1321
|
x: start.x,
|
|
1381
1322
|
y: 0
|
|
1382
1323
|
};
|
|
1383
|
-
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1324
|
+
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1384
1325
|
await (0, core_utils_namespaceObject.sleep)(1000);
|
|
1385
1326
|
return;
|
|
1386
1327
|
}
|
|
@@ -1398,7 +1339,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1398
1339
|
x: Math.round(width),
|
|
1399
1340
|
y: start.y
|
|
1400
1341
|
};
|
|
1401
|
-
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1342
|
+
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1402
1343
|
await (0, core_utils_namespaceObject.sleep)(1000);
|
|
1403
1344
|
return;
|
|
1404
1345
|
}
|
|
@@ -1415,7 +1356,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1415
1356
|
x: 0,
|
|
1416
1357
|
y: start.y
|
|
1417
1358
|
};
|
|
1418
|
-
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.
|
|
1359
|
+
await (0, utils_namespaceObject.repeat)(defaultScrollUntilTimes, ()=>this.dragPoint(start, end, defaultFastScrollDuration));
|
|
1419
1360
|
await (0, core_utils_namespaceObject.sleep)(1000);
|
|
1420
1361
|
return;
|
|
1421
1362
|
}
|
|
@@ -1433,7 +1374,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1433
1374
|
};
|
|
1434
1375
|
const end = this.calculateScrollEndPoint(start, 0, scrollDistance, 0, height);
|
|
1435
1376
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('up', scrollDistance, Math.abs(end.y - start.y));
|
|
1436
|
-
await this.
|
|
1377
|
+
await this.dragPoint(start, end);
|
|
1437
1378
|
return;
|
|
1438
1379
|
}
|
|
1439
1380
|
await this.scroll(0, -scrollDistance, void 0, hasExplicitDistance, 'up');
|
|
@@ -1449,7 +1390,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1449
1390
|
};
|
|
1450
1391
|
const end = this.calculateScrollEndPoint(start, 0, -scrollDistance, 0, height);
|
|
1451
1392
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('down', scrollDistance, Math.abs(end.y - start.y));
|
|
1452
|
-
await this.
|
|
1393
|
+
await this.dragPoint(start, end);
|
|
1453
1394
|
return;
|
|
1454
1395
|
}
|
|
1455
1396
|
await this.scroll(0, scrollDistance, void 0, hasExplicitDistance, 'down');
|
|
@@ -1465,7 +1406,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1465
1406
|
};
|
|
1466
1407
|
const end = this.calculateScrollEndPoint(start, scrollDistance, 0, width, 0);
|
|
1467
1408
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('left', scrollDistance, Math.abs(end.x - start.x));
|
|
1468
|
-
await this.
|
|
1409
|
+
await this.dragPoint(start, end);
|
|
1469
1410
|
return;
|
|
1470
1411
|
}
|
|
1471
1412
|
await this.scroll(-scrollDistance, 0, void 0, hasExplicitDistance, 'left');
|
|
@@ -1481,7 +1422,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1481
1422
|
};
|
|
1482
1423
|
const end = this.calculateScrollEndPoint(start, -scrollDistance, 0, width, 0);
|
|
1483
1424
|
if (hasExplicitDistance) this.warnScrollDistanceClamped('right', scrollDistance, Math.abs(end.x - start.x));
|
|
1484
|
-
await this.
|
|
1425
|
+
await this.dragPoint(start, end);
|
|
1485
1426
|
return;
|
|
1486
1427
|
}
|
|
1487
1428
|
await this.scroll(scrollDistance, 0, void 0, hasExplicitDistance, 'right');
|
|
@@ -1502,7 +1443,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1502
1443
|
const hasBothQuotes = text.includes('"') && text.includes("'");
|
|
1503
1444
|
return hasNonAscii || hasFormatSpecifiers || hasShellSpecialChars || hasBothQuotes;
|
|
1504
1445
|
}
|
|
1505
|
-
async
|
|
1446
|
+
async typeText(text, options) {
|
|
1506
1447
|
if (!text) return;
|
|
1507
1448
|
const adb = await this.getAdb();
|
|
1508
1449
|
const IME_STRATEGY = (this.options?.imeStrategy || env_namespaceObject.globalConfigManager.getEnvConfigValue(env_namespaceObject.MIDSCENE_ANDROID_IME_STRATEGY)) ?? IME_STRATEGY_YADB_FOR_NON_ASCII;
|
|
@@ -1539,7 +1480,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1539
1480
|
const lowerKey = key.toLowerCase();
|
|
1540
1481
|
return keyMap[lowerKey] || key;
|
|
1541
1482
|
}
|
|
1542
|
-
async
|
|
1483
|
+
async pressKey(key) {
|
|
1543
1484
|
const keyCodeMap = {
|
|
1544
1485
|
Enter: 66,
|
|
1545
1486
|
Backspace: 67,
|
|
@@ -1561,14 +1502,14 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1561
1502
|
if (asciiCode >= 65 && asciiCode <= 90) await adb.keyevent(asciiCode - 36);
|
|
1562
1503
|
}
|
|
1563
1504
|
}
|
|
1564
|
-
async
|
|
1505
|
+
async tapPoint(point) {
|
|
1565
1506
|
const adb = await this.getAdb();
|
|
1566
|
-
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(x, y);
|
|
1507
|
+
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(point.x, point.y);
|
|
1567
1508
|
await adb.shell(`input${this.getDisplayArg()} swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} 150`);
|
|
1568
1509
|
}
|
|
1569
|
-
async
|
|
1510
|
+
async doubleTapPoint(point) {
|
|
1570
1511
|
const adb = await this.getAdb();
|
|
1571
|
-
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(x, y);
|
|
1512
|
+
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(point.x, point.y);
|
|
1572
1513
|
const tapCommand = `input${this.getDisplayArg()} tap ${adjustedX} ${adjustedY}`;
|
|
1573
1514
|
await adb.shell(tapCommand);
|
|
1574
1515
|
await (0, core_utils_namespaceObject.sleep)(50);
|
|
@@ -1577,12 +1518,14 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1577
1518
|
async mouseMove() {
|
|
1578
1519
|
return Promise.resolve();
|
|
1579
1520
|
}
|
|
1580
|
-
async
|
|
1521
|
+
async dragPoint(from, to, duration) {
|
|
1522
|
+
await this.swipePoint(from, to, duration ?? defaultNormalScrollDuration);
|
|
1523
|
+
}
|
|
1524
|
+
async swipePoint(from, to, duration) {
|
|
1581
1525
|
const adb = await this.getAdb();
|
|
1582
1526
|
const { x: fromX, y: fromY } = await this.adjustCoordinates(from.x, from.y);
|
|
1583
1527
|
const { x: toX, y: toY } = await this.adjustCoordinates(to.x, to.y);
|
|
1584
|
-
|
|
1585
|
-
await adb.shell(`input${this.getDisplayArg()} swipe ${fromX} ${fromY} ${toX} ${toY} ${swipeDuration}`);
|
|
1528
|
+
await adb.shell(`input${this.getDisplayArg()} swipe ${fromX} ${fromY} ${toX} ${toY} ${duration}`);
|
|
1586
1529
|
}
|
|
1587
1530
|
async scroll(deltaX, deltaY, duration, warnOnClamp = false, direction) {
|
|
1588
1531
|
if (0 === deltaX && 0 === deltaY) throw new Error('Scroll distance cannot be zero in both directions');
|
|
@@ -1605,11 +1548,14 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1605
1548
|
}
|
|
1606
1549
|
const endX = Math.round(startX - deltaX);
|
|
1607
1550
|
const endY = Math.round(startY - deltaY);
|
|
1608
|
-
const { x: adjustedStartX, y: adjustedStartY } = await this.adjustCoordinates(startX, startY);
|
|
1609
|
-
const { x: adjustedEndX, y: adjustedEndY } = await this.adjustCoordinates(endX, endY);
|
|
1610
|
-
const adb = await this.getAdb();
|
|
1611
1551
|
const swipeDuration = duration ?? defaultNormalScrollDuration;
|
|
1612
|
-
await
|
|
1552
|
+
await this.swipePoint({
|
|
1553
|
+
x: startX,
|
|
1554
|
+
y: startY
|
|
1555
|
+
}, {
|
|
1556
|
+
x: endX,
|
|
1557
|
+
y: endY
|
|
1558
|
+
}, swipeDuration);
|
|
1613
1559
|
}
|
|
1614
1560
|
async destroy() {
|
|
1615
1561
|
if (this.destroyed) return;
|
|
@@ -1657,9 +1603,9 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1657
1603
|
const adb = await this.getAdb();
|
|
1658
1604
|
await adb.shell(`input${this.getDisplayArg()} keyevent 187`);
|
|
1659
1605
|
}
|
|
1660
|
-
async
|
|
1606
|
+
async longPressPoint(point, duration = 2000) {
|
|
1661
1607
|
const adb = await this.getAdb();
|
|
1662
|
-
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(x, y);
|
|
1608
|
+
const { x: adjustedX, y: adjustedY } = await this.adjustCoordinates(point.x, point.y);
|
|
1663
1609
|
await adb.shell(`input${this.getDisplayArg()} swipe ${adjustedX} ${adjustedY} ${adjustedX} ${adjustedY} ${duration}`);
|
|
1664
1610
|
}
|
|
1665
1611
|
async pullDown(startPoint, distance, duration = 800) {
|
|
@@ -1680,10 +1626,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1680
1626
|
await (0, core_utils_namespaceObject.sleep)(200);
|
|
1681
1627
|
}
|
|
1682
1628
|
async pullDrag(from, to, duration) {
|
|
1683
|
-
|
|
1684
|
-
const { x: fromX, y: fromY } = await this.adjustCoordinates(from.x, from.y);
|
|
1685
|
-
const { x: toX, y: toY } = await this.adjustCoordinates(to.x, to.y);
|
|
1686
|
-
await adb.shell(`input${this.getDisplayArg()} swipe ${fromX} ${fromY} ${toX} ${toY} ${duration}`);
|
|
1629
|
+
await this.swipePoint(from, to, duration);
|
|
1687
1630
|
}
|
|
1688
1631
|
async pullUp(startPoint, distance, duration = 600) {
|
|
1689
1632
|
const { width, height } = await this.size();
|
|
@@ -1784,6 +1727,56 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1784
1727
|
device_define_property(this, "interfaceType", 'android');
|
|
1785
1728
|
device_define_property(this, "uri", void 0);
|
|
1786
1729
|
device_define_property(this, "options", void 0);
|
|
1730
|
+
device_define_property(this, "inputPrimitives", {
|
|
1731
|
+
pointer: {
|
|
1732
|
+
tap: (point)=>this.tapPoint(point),
|
|
1733
|
+
doubleClick: (point)=>this.doubleTapPoint(point),
|
|
1734
|
+
longPress: (point, opts)=>this.longPressPoint(point, opts?.duration),
|
|
1735
|
+
dragAndDrop: (from, to)=>this.dragPoint(from, to)
|
|
1736
|
+
},
|
|
1737
|
+
keyboard: {
|
|
1738
|
+
keyboardPress: (keyName)=>this.pressKey(keyName),
|
|
1739
|
+
typeText: async (value, opts)=>{
|
|
1740
|
+
const target = opts?.target;
|
|
1741
|
+
if (target && opts?.replace !== false) await this.clearInput(target);
|
|
1742
|
+
else if (target) await this.tapPoint({
|
|
1743
|
+
x: target.center[0],
|
|
1744
|
+
y: target.center[1]
|
|
1745
|
+
});
|
|
1746
|
+
if (opts?.focusOnly) return;
|
|
1747
|
+
await this.typeText(value, opts);
|
|
1748
|
+
},
|
|
1749
|
+
clearInput: (target)=>this.clearInput(target),
|
|
1750
|
+
cursorMove: async (direction, times = 1)=>{
|
|
1751
|
+
const arrowKey = 'left' === direction ? 'ArrowLeft' : 'ArrowRight';
|
|
1752
|
+
for(let i = 0; i < times; i++)await this.pressKey(arrowKey);
|
|
1753
|
+
}
|
|
1754
|
+
},
|
|
1755
|
+
touch: {
|
|
1756
|
+
swipe: async (start, end, opts)=>{
|
|
1757
|
+
const duration = opts?.duration ?? 300;
|
|
1758
|
+
const repeatCount = opts?.repeat ?? 1;
|
|
1759
|
+
for(let i = 0; i < repeatCount; i++)await this.dragPoint(start, end, duration);
|
|
1760
|
+
},
|
|
1761
|
+
pinch: async (center, opts)=>{
|
|
1762
|
+
const { x: adjCenterX, y: adjCenterY } = await this.adjustCoordinates(Math.round(center.x), Math.round(center.y));
|
|
1763
|
+
const ratio = 0 !== adjCenterX && 0 !== center.x ? adjCenterX / center.x : 1;
|
|
1764
|
+
const adjStartDist = Math.round(opts.startDistance * ratio);
|
|
1765
|
+
const adjEndDist = Math.round(opts.endDistance * ratio);
|
|
1766
|
+
await this.ensureYadb();
|
|
1767
|
+
const adb = await this.getAdb();
|
|
1768
|
+
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}`);
|
|
1769
|
+
}
|
|
1770
|
+
},
|
|
1771
|
+
scroll: {
|
|
1772
|
+
scroll: (param)=>this.performActionScroll(param)
|
|
1773
|
+
},
|
|
1774
|
+
system: {
|
|
1775
|
+
backButton: ()=>this.back(),
|
|
1776
|
+
homeButton: ()=>this.home(),
|
|
1777
|
+
recentAppsButton: ()=>this.recentApps()
|
|
1778
|
+
}
|
|
1779
|
+
});
|
|
1787
1780
|
external_node_assert_default()(deviceId, 'deviceId is required for AndroidDevice');
|
|
1788
1781
|
this.deviceId = deviceId;
|
|
1789
1782
|
this.options = options;
|
|
@@ -1834,37 +1827,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1834
1827
|
description: 'Terminate (force-stop) an Android app by package name',
|
|
1835
1828
|
interfaceAlias: 'terminate',
|
|
1836
1829
|
paramSchema: terminateParamSchema,
|
|
1837
|
-
delayBeforeRunner: 0,
|
|
1838
|
-
delayAfterRunner: 0,
|
|
1839
1830
|
call: async (param)=>{
|
|
1840
1831
|
if (!param.uri || '' === param.uri.trim()) throw new Error('Terminate requires a non-empty uri parameter');
|
|
1841
1832
|
await device.terminate(param.uri);
|
|
1842
1833
|
}
|
|
1843
|
-
}),
|
|
1844
|
-
AndroidBackButton: (0, device_namespaceObject.defineAction)({
|
|
1845
|
-
name: 'AndroidBackButton',
|
|
1846
|
-
description: 'Trigger the system "back" operation on Android devices',
|
|
1847
|
-
delayBeforeRunner: 0,
|
|
1848
|
-
delayAfterRunner: 0,
|
|
1849
|
-
call: async ()=>{
|
|
1850
|
-
await device.back();
|
|
1851
|
-
}
|
|
1852
|
-
}),
|
|
1853
|
-
AndroidHomeButton: (0, device_namespaceObject.defineAction)({
|
|
1854
|
-
name: 'AndroidHomeButton',
|
|
1855
|
-
description: 'Trigger the system "home" operation on Android devices',
|
|
1856
|
-
delayBeforeRunner: 0,
|
|
1857
|
-
delayAfterRunner: 0,
|
|
1858
|
-
call: async ()=>{
|
|
1859
|
-
await device.home();
|
|
1860
|
-
}
|
|
1861
|
-
}),
|
|
1862
|
-
AndroidRecentAppsButton: (0, device_namespaceObject.defineAction)({
|
|
1863
|
-
name: 'AndroidRecentAppsButton',
|
|
1864
|
-
description: 'Trigger the system "recent apps" operation on Android devices',
|
|
1865
|
-
call: async ()=>{
|
|
1866
|
-
await device.recentApps();
|
|
1867
|
-
}
|
|
1868
1834
|
})
|
|
1869
1835
|
});
|
|
1870
1836
|
const debugUtils = (0, logger_.getDebug)('android:utils');
|
|
@@ -2031,7 +1997,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
2031
1997
|
const tools = new AndroidMidsceneTools();
|
|
2032
1998
|
(0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-android', {
|
|
2033
1999
|
stripPrefix: 'android_',
|
|
2034
|
-
version: "1.8.
|
|
2000
|
+
version: "1.8.1",
|
|
2035
2001
|
extraCommands: (0, core_namespaceObject.createReportCliCommands)()
|
|
2036
2002
|
}).catch((e)=>{
|
|
2037
2003
|
process.exit((0, cli_namespaceObject.reportCLIError)(e));
|