"""Explicit execution plans for Native134. No device is touched on import. Desktop backend is PyAutoGUI plus injected Unicode paste. Android backend is an injected argv-only ADB runner plus Unicode type callback. Lifecycle callbacks are explicit, so interact/answer/failure cannot silently become task success. """ from __future__ import annotations import re def plan(codec, action, platform, size, *, installed_apps=None): a=codec.adapt_target(action,platform).canonical_action if len(size)!=2 or any(type(d) is not int or d<=0 for d in size): raise ValueError('invalid_screen_size') def pixel(name): return [min(d-1,int(v*d/1000+.5)) for v,d in zip(a[name],size)] name=a['action']; args=[] if name in ('terminate','answer','interact','wait'): field={'terminate':'status','answer':'text','interact':'text','wait':'time'}[name] return [(name,[a[field]])] if name=='type': return [('type_unicode',[a['text']])] if platform=='desktop': if name=='key': return [('hotkey',a['keys'])] if name=='mouse_move': return [('moveTo',pixel('coordinate'))] if name=='left_click_drag': return [('dragTo',pixel('coordinate')+[.5])] if name in ('scroll','hscroll'): before=[('moveTo',pixel('coordinate'))] if 'coordinate' in a else [] return before+[(name,[a['pixels']])] buttons={'left_click':('left',1),'right_click':('right',1),'middle_click':('middle',1), 'double_click':('left',2),'triple_click':('left',3)} button,n=buttons[name] return [('click',pixel('coordinate')+[button,n])] if name=='click': args=['input','tap',*pixel('coordinate')] elif name=='swipe': args=['input','swipe',*pixel('coordinate'),*pixel('coordinate2'),800] elif name=='long_press': args=['input','swipe',*pixel('coordinate'),*pixel('coordinate'),int(a['time']*1000+.5)] elif name=='system_button': args=['input','keyevent',{'Back':4,'Home':3,'Menu':82,'Enter':66}[a['button']]] elif name=='key': key=a['text'].upper() if not key.startswith('KEYCODE_'): key='KEYCODE_'+key if not re.fullmatch(r'KEYCODE_[A-Z0-9_]+',key): raise ValueError('invalid_android_key') args=['input','keyevent',key] elif name=='open': apps=installed_apps or {} package=apps.get(a['text']) if package is None and a['text'] in apps.values(): package=a['text'] if package is None: raise ValueError('app_not_in_verified_installed_mapping') if not re.fullmatch(r'[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)+',package): raise ValueError('invalid_app_package') args=['monkey','-p',package,'-c','android.intent.category.LAUNCHER','1'] else: raise ValueError('unimplemented_action') return [('adb_shell',[str(x) for x in args])] def execute(operations, *, desktop=None, adb_shell=None, type_unicode=None, callbacks=None): """Callers inject existing VM/ADB connections; never build shell strings.""" callbacks=callbacks or {} for name,args in operations: if name in ('terminate','answer','interact','wait'): callbacks[name](*args) elif name=='adb_shell': adb_shell(args) elif name=='type_unicode': type_unicode(*args) elif name=='click': desktop.click(args[0],args[1],button=args[2],clicks=args[3],interval=.1) elif name=='dragTo': desktop.dragTo(args[0],args[1],duration=args[2],button='left') else: getattr(desktop,name)(*args)