@@ -6,6 +6,8 @@ import { buildScrollGesturePlan, type ScrollDirection } from '../../core/scroll-
66import { runAndroidAdb , sleep } from './adb.ts' ;
77import { resolveAndroidTextInjector } from './adb-executor.ts' ;
88import { getAndroidKeyboardState , type AndroidKeyboardState } from './device-input-state.ts' ;
9+ import { captureAndroidUiHierarchyXml } from './snapshot.ts' ;
10+ import { androidUiNodes } from './ui-hierarchy.ts' ;
911import {
1012 androidFillFailureDetails ,
1113 androidFillFailureMessage ,
@@ -206,7 +208,7 @@ export async function scrollAndroid(
206208 direction : ScrollDirection ,
207209 options ?: { amount ?: number ; pixels ?: number } ,
208210) : Promise < Record < string , unknown > > {
209- const size = await getAndroidScreenSize ( device ) ;
211+ const size = await getAndroidGestureViewportSize ( device ) ;
210212 const plan = buildScrollGesturePlan ( {
211213 direction,
212214 amount : options ?. amount ,
@@ -290,6 +292,38 @@ export async function getAndroidScreenSize(
290292 return { width : Number ( match [ 1 ] ) , height : Number ( match [ 2 ] ) } ;
291293}
292294
295+ async function getAndroidGestureViewportSize (
296+ device : DeviceInfo ,
297+ ) : Promise < { width : number ; height : number } > {
298+ try {
299+ const xml = await captureAndroidUiHierarchyXml ( device ) ;
300+ const viewport = largestAndroidUiNodeRect ( xml ) ;
301+ if ( viewport ) return viewport ;
302+ } catch ( error ) {
303+ emitDiagnostic ( {
304+ level : 'warn' ,
305+ phase : 'android_gesture_viewport_probe_failed' ,
306+ data : {
307+ error : error instanceof Error ? error . message : String ( error ) ,
308+ } ,
309+ } ) ;
310+ }
311+ return await getAndroidScreenSize ( device ) ;
312+ }
313+
314+ function largestAndroidUiNodeRect ( xml : string ) : { width : number ; height : number } | null {
315+ let largest : { width : number ; height : number ; area : number } | null = null ;
316+ for ( const node of androidUiNodes ( xml ) ) {
317+ const rect = node . rect ;
318+ if ( ! rect || rect . width <= 0 || rect . height <= 0 ) continue ;
319+ const area = rect . width * rect . height ;
320+ if ( ! largest || area > largest . area ) {
321+ largest = { width : rect . x + rect . width , height : rect . y + rect . height , area } ;
322+ }
323+ }
324+ return largest ? { width : largest . width , height : largest . height } : null ;
325+ }
326+
293327const ANDROID_INPUT_TEXT_CHUNK_SIZE = 8 ;
294328
295329async function typeAndroidShell (
0 commit comments