@midscene/android 1.10.9 → 1.10.10-beta-20260805080137.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.
@@ -111,9 +111,12 @@ export declare class AndroidDevice implements AbstractInterface {
111
111
  interfaceType: InterfaceType;
112
112
  uri: string | undefined;
113
113
  options?: AndroidDeviceOpt;
114
+ private readonly visualActions;
114
115
  readonly inputPrimitives: MobileInputPrimitives;
115
116
  actionSpace(): DeviceAction<any>[];
117
+ private performPullGesture;
116
118
  private performActionScroll;
119
+ private runAdbShellRaw;
117
120
  constructor(deviceId: string, options?: AndroidDeviceOpt);
118
121
  describe(): string;
119
122
  connect(): Promise<ADB>;
@@ -158,13 +161,16 @@ export declare class AndroidDevice implements AbstractInterface {
158
161
  */
159
162
  private resolvePackageName;
160
163
  launch(uri: string): Promise<AndroidDevice>;
164
+ private launchRaw;
161
165
  /**
162
166
  * Terminate (force-stop) an Android app by package name.
163
167
  * Supports app name resolution via setAppNameMapping.
164
168
  * If uri contains "/" (e.g. com.example.app/.MainActivity), only the package part is used.
165
169
  */
166
170
  terminate(uri: string): Promise<void>;
171
+ private terminateRaw;
167
172
  execYadb(keyboardContent: string): Promise<void>;
173
+ private execYadbRaw;
168
174
  getElementsInfo(): Promise<ElementInfo[]>;
169
175
  getElementsNodeTree(): Promise<any>;
170
176
  getUITree(): Promise<UITreeSnapshot>;
@@ -211,16 +217,25 @@ export declare class AndroidDevice implements AbstractInterface {
211
217
  private warnScrollDistanceClamped;
212
218
  screenshotBase64(): Promise<string>;
213
219
  clearInput(element?: ElementInfo): Promise<void>;
220
+ private clearInputRaw;
214
221
  forceScreenshot(path: string): Promise<void>;
215
222
  url(): Promise<string>;
216
223
  scrollUntilTop(startPoint?: Point): Promise<void>;
224
+ private scrollUntilTopRaw;
217
225
  scrollUntilBottom(startPoint?: Point): Promise<void>;
226
+ private scrollUntilBottomRaw;
218
227
  scrollUntilLeft(startPoint?: Point): Promise<void>;
228
+ private scrollUntilLeftRaw;
219
229
  scrollUntilRight(startPoint?: Point): Promise<void>;
230
+ private scrollUntilRightRaw;
220
231
  scrollUp(distance?: number, startPoint?: Point): Promise<void>;
232
+ private scrollUpRaw;
221
233
  scrollDown(distance?: number, startPoint?: Point): Promise<void>;
234
+ private scrollDownRaw;
222
235
  scrollLeft(distance?: number, startPoint?: Point): Promise<void>;
236
+ private scrollLeftRaw;
223
237
  scrollRight(distance?: number, startPoint?: Point): Promise<void>;
238
+ private scrollRightRaw;
224
239
  ensureYadb(): Promise<void>;
225
240
  /**
226
241
  * Check if text contains characters that may cause issues with ADB inputText.
@@ -243,6 +258,7 @@ export declare class AndroidDevice implements AbstractInterface {
243
258
  private dragPoint;
244
259
  private swipePoint;
245
260
  scroll(deltaX: number, deltaY: number, duration?: number, warnOnClamp?: boolean, direction?: ScrollDirection): Promise<void>;
261
+ private scrollRaw;
246
262
  destroy(): Promise<void>;
247
263
  /**
248
264
  * Get the current device-local time as a formatted string.
@@ -251,10 +267,14 @@ export declare class AndroidDevice implements AbstractInterface {
251
267
  */
252
268
  getDeviceLocalTimeString(format?: string): Promise<string>;
253
269
  back(): Promise<void>;
270
+ private backRaw;
254
271
  home(): Promise<void>;
272
+ private homeRaw;
255
273
  recentApps(): Promise<void>;
274
+ private recentAppsRaw;
256
275
  private longPressPoint;
257
276
  pullDown(startPoint?: Point, distance?: number, duration?: number): Promise<void>;
277
+ private pullDownRaw;
258
278
  pullDrag(from: {
259
279
  x: number;
260
280
  y: number;
@@ -262,7 +282,9 @@ export declare class AndroidDevice implements AbstractInterface {
262
282
  x: number;
263
283
  y: number;
264
284
  }, duration: number): Promise<void>;
285
+ private pullDragRaw;
265
286
  pullUp(startPoint?: Point, distance?: number, duration?: number): Promise<void>;
287
+ private pullUpRaw;
266
288
  private getDisplayArg;
267
289
  /**
268
290
  * Send one or more Android keyevent codes via `input -d <id> keyevent`.
@@ -292,6 +314,7 @@ export declare class AndroidDevice implements AbstractInterface {
292
314
  getPhysicalDisplayId(): Promise<string | null>;
293
315
  private resolvePhysicalDisplayId;
294
316
  hideKeyboard(options?: AndroidDeviceInputOpt, timeoutMs?: number): Promise<boolean>;
317
+ private hideKeyboardRaw;
295
318
  }
296
319
 
297
320
  declare type AndroidInitArgs = AgentBehaviorInitArgs & {
@@ -346,6 +369,10 @@ declare interface RawKeyframe {
346
369
  data: Buffer;
347
370
  /** SPS/PPS header active when this frame was produced (needed to decode). */
348
371
  header: Buffer;
372
+ /** Device-monotonic capture timestamp forwarded by scrcpy. */
373
+ ptsUs?: bigint;
374
+ /** Estimated frame age when the packet reached the host. */
375
+ estimatedAgeMs?: number;
349
376
  capturedAt: number;
350
377
  }
351
378
 
@@ -384,6 +411,12 @@ export declare class ScrcpyDeviceAdapter {
384
411
  private resolvedConfig;
385
412
  private lastError;
386
413
  private retryAfter;
414
+ private freshnessRecoveryPending;
415
+ private recoveryPromise;
416
+ private lifecycleGeneration;
417
+ private pendingActionBarrier;
418
+ private keyframeListeners;
419
+ private keyframeUnsubscribers;
387
420
  constructor(deviceId: string, scrcpyConfig: ScrcpyConfig | undefined, resolveAdbServerEndpoint?: ResolveAdbServerEndpoint);
388
421
  isEnabled(): boolean;
389
422
  getStatus(): ScrcpyStatus;
@@ -421,6 +454,21 @@ export declare class ScrcpyDeviceAdapter {
421
454
  subscribeKeyframes(deviceInfo: DevicePhysicalInfo, listener: (frame: RawKeyframe) => void): Promise<() => void>;
422
455
  /** Latest raw keyframe seen on the stream, or null if none yet. */
423
456
  getLatestRawKeyframe(): RawKeyframe | null;
457
+ private attachKeyframeListener;
458
+ private attachKeyframeListeners;
459
+ private markFreshnessRecoveryPending;
460
+ private applyPendingActionBarrier;
461
+ /**
462
+ * Start a new scrcpy epoch only after the independent ADB screenshot has
463
+ * completed, so stream startup does not compete with the fallback capture.
464
+ */
465
+ recoverAfterAdbScreenshot(deviceInfo: DevicePhysicalInfo): void;
466
+ /**
467
+ * Move the scrcpy PTS barrier past a completed input action. Barrier failures
468
+ * must not turn a successfully injected action into an action error; disable
469
+ * the stream and let subsequent captures use the existing ADB fallback.
470
+ */
471
+ markActionBarrier(): Promise<void>;
424
472
  /**
425
473
  * Decode a raw keyframe to a JPEG data URL. Deferred, per-frame-expensive
426
474
  * step (one ffmpeg process per call) — only call on sampled frames.
@@ -460,8 +508,19 @@ declare class ScrcpyScreenshotManager {
460
508
  private keyframeListeners;
461
509
  private lastRawKeyframe;
462
510
  private lastRawKeyframeAt;
511
+ private lastRawKeyframePtsUs;
512
+ private lastRawKeyframeEstimatedAgeMs;
463
513
  private videoResolution;
464
514
  private streamReader;
515
+ private frameFreshnessBarrierPtsUs;
516
+ private frameFreshnessBarrierReason;
517
+ private frameFreshnessBarrierPending;
518
+ private frameFreshnessBarrierGeneration;
519
+ private deviceClockCalibration;
520
+ private lastFramePtsUs;
521
+ private frameFreshnessError;
522
+ private lastFrameFreshnessWarningAt;
523
+ private lastTransportBacklogWarningAt;
465
524
  constructor(adb: Adb, options?: ScrcpyScreenshotOptions);
466
525
  /**
467
526
  * Validate environment prerequisites (ffmpeg, scrcpy-server, etc.)
@@ -505,6 +564,28 @@ declare class ScrcpyScreenshotManager {
505
564
  * at high resolutions where raw chunks may not align with frame boundaries.
506
565
  */
507
566
  private processFrame;
567
+ /**
568
+ * Read the Android uptime clock used by Surface/MediaCodec frame PTS values.
569
+ * The host timestamps bracket the ADB request so frame age can also be
570
+ * estimated on the host wall clock for reports.
571
+ */
572
+ private readDeviceClockCalibration;
573
+ ensureFrameClockCalibration(): Promise<void>;
574
+ /**
575
+ * Invalidate cached frames and require future packets to be captured after a
576
+ * newly sampled point on the device clock after a completed input or
577
+ * platform action.
578
+ */
579
+ setFreshnessBarrier(reason: string): Promise<bigint>;
580
+ private isFrameFresh;
581
+ private estimateFrameAgeUs;
582
+ private isFrameAgeAcceptable;
583
+ private warnFrameFreshness;
584
+ private warnTransportBacklog;
585
+ private estimateFrameTiming;
586
+ private clearFrameCache;
587
+ private monotonicTimeUs;
588
+ private resetFrameFreshnessState;
508
589
  /**
509
590
  * Subscribe to raw keyframes as they arrive from the stream. While at least
510
591
  * one subscriber is active, incoming keyframes keep resetting the idle timer
@@ -516,6 +597,7 @@ declare class ScrcpyScreenshotManager {
516
597
  subscribeKeyframes(listener: (frame: RawKeyframe) => void): () => void;
517
598
  /** Latest raw keyframe seen on the stream, or null if none yet. */
518
599
  getLatestRawKeyframe(): RawKeyframe | null;
600
+ private getCachedKeyframeCandidate;
519
601
  /**
520
602
  * Decode a raw keyframe (from {@link subscribeKeyframes} or
521
603
  * {@link getLatestRawKeyframe}) to a JPEG buffer. This is the deferred,
@@ -523,10 +605,20 @@ declare class ScrcpyScreenshotManager {
523
605
  * sampled frames, never inside a capture loop.
524
606
  */
525
607
  decodeRawKeyframeToJpeg(frame: RawKeyframe): Promise<Buffer>;
608
+ private waitForUsableKeyframe;
609
+ /**
610
+ * Ensure a newly connected stream has a calibrated, temporally fresh frame
611
+ * before it is exposed again after ADB fallback.
612
+ */
613
+ prepareFreshFrame(): Promise<void>;
614
+ private waitForPlanningFrame;
615
+ private closeStaleStreamAndCreateFallbackError;
526
616
  /**
527
617
  * Get screenshot as JPEG.
528
- * Tries to get a fresh frame within a short timeout. If the screen is static
529
- * (no new frames arrive), falls back to the latest cached keyframe.
618
+ * Reuses a frame only when it crossed the active action barrier and its
619
+ * absolute age is within the accepted limit. An over-age candidate arms a
620
+ * planning barrier on demand. If no frame crosses the resulting freshness
621
+ * target in time, close this stream epoch and let the caller use ADB.
530
622
  */
531
623
  getScreenshotJpeg(): Promise<Buffer>;
532
624
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/android",
3
- "version": "1.10.9",
3
+ "version": "1.10.10-beta-20260805080137.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/web-infra-dev/midscene.git",
@@ -41,8 +41,8 @@
41
41
  "@yume-chan/stream-extra": "2.1.0",
42
42
  "appium-adb": "12.12.1",
43
43
  "sharp": "^0.34.3",
44
- "@midscene/core": "1.10.9",
45
- "@midscene/shared": "1.10.9"
44
+ "@midscene/core": "1.10.10-beta-20260805080137.0",
45
+ "@midscene/shared": "1.10.10-beta-20260805080137.0"
46
46
  },
47
47
  "optionalDependencies": {
48
48
  "@ffmpeg-installer/ffmpeg": "^1.1.0"
@@ -56,7 +56,7 @@
56
56
  "undici": "^6.0.0",
57
57
  "vitest": "3.0.5",
58
58
  "zod": "^3.25.1",
59
- "@midscene/playground": "1.10.9"
59
+ "@midscene/playground": "1.10.10-beta-20260805080137.0"
60
60
  },
61
61
  "license": "MIT",
62
62
  "scripts": {