diff --git a/Apps/Mobile/Android_Inspector_ZeuZ.py b/Apps/Mobile/Android_Inspector_ZeuZ.py index bd293a78e..fff5008bc 100644 --- a/Apps/Mobile/Android_Inspector_ZeuZ.py +++ b/Apps/Mobile/Android_Inspector_ZeuZ.py @@ -24,8 +24,23 @@ def run_adb_command(command): def capture_ui_dump(): """Capture the current UI hierarchy from the device and take a screenshot.""" - run_adb_command(f"{ADB_PATH} shell uiautomator dump /sdcard/ui.xml") - run_adb_command(f"{ADB_PATH} pull /sdcard/ui.xml {UI_XML_PATH}") + xml_saved = False + appium_driver = None + try: + from Framework.Built_In_Automation.Shared_Resources import BuiltInFunctionSharedResources as Shared_Resources + appium_driver = Shared_Resources.Get_Shared_Variables("appium_driver", log=False) + if appium_driver is not None: + page_src = appium_driver.page_source + with open(UI_XML_PATH, "w") as xml_file: + xml_file.write(page_src) + xml_saved = True + except Exception: + pass + # even if it fails don't try adb if appium driver is available + if not xml_saved and appium_driver is None: + run_adb_command(f"{ADB_PATH} shell uiautomator dump /sdcard/ui.xml") + run_adb_command(f"{ADB_PATH} pull /sdcard/ui.xml {UI_XML_PATH}") + run_adb_command(f"{ADB_PATH} shell screencap -p /sdcard/screen.png") run_adb_command(f"{ADB_PATH} pull /sdcard/screen.png {SCREENSHOT_PATH}") update_treeview() diff --git a/Framework/Built_In_Automation/Mobile/Android/adb_calls/adbOptions.py b/Framework/Built_In_Automation/Mobile/Android/adb_calls/adbOptions.py index 6a623f2ab..5c67edc8b 100644 --- a/Framework/Built_In_Automation/Mobile/Android/adb_calls/adbOptions.py +++ b/Framework/Built_In_Automation/Mobile/Android/adb_calls/adbOptions.py @@ -782,11 +782,38 @@ def check_if_device_is_unlocked(serial=""): "adb %s shell input keyevent 82" % (serial), shell=True, encoding="utf-8" ) # Wakeup device and bring it unlock window time.sleep(1) - output = subprocess.check_output( - "adb %s exec-out uiautomator dump /dev/tty" % serial, - shell=True, - encoding="utf-8", - ) + + try: + from Framework.Built_In_Automation.Shared_Resources import BuiltInFunctionSharedResources as Shared_Resources + + appium_driver = None + if serial and serial.startswith("-s "): + extracted_serial = serial.split("-s ")[1].strip() + appium_details = Shared_Resources.Get_Shared_Variables("appium_details", log=False) + if isinstance(appium_details, dict): + for name, details in appium_details.items(): + stored_serial = details.get("serial") + if stored_serial and (stored_serial == extracted_serial or stored_serial in extracted_serial or extracted_serial in stored_serial): + appium_driver = details.get("driver") + break + + if appium_driver is None and not serial: + appium_driver = Shared_Resources.Get_Shared_Variables("appium_driver", log=False) + + if appium_driver is not None: + output = appium_driver.page_source + else: + output = subprocess.check_output( + "adb %s exec-out uiautomator dump /dev/tty" % serial, + shell=True, + encoding="utf-8", + ) + except Exception: + output = subprocess.check_output( + "adb %s exec-out uiautomator dump /dev/tty" % serial, + shell=True, + encoding="utf-8", + ) if "EMERGENCY" in output or "emergency_call_button" in output: CommonUtil.ExecLog( diff --git a/server/mobile.py b/server/mobile.py index 75aa2a6da..b268e580c 100644 --- a/server/mobile.py +++ b/server/mobile.py @@ -166,12 +166,43 @@ def run_adb_command_bytes(cmd: str, timeout: int = 30) -> bytes: raise RuntimeError(f"ADB command timed out after {timeout}s: {cmd}") +def get_appium_driver_for_serial(device_serial: str | None = None): + """ + Retrieve the specific Appium driver instance for the given Android device serial. + Defaults to the global appium_driver if no serial is provided. + """ + from Framework.Built_In_Automation.Shared_Resources import BuiltInFunctionSharedResources as Shared_Resources + + if not device_serial: + return Shared_Resources.Get_Shared_Variables("appium_driver", log=False) + + appium_details = Shared_Resources.Get_Shared_Variables("appium_details", log=False) + if isinstance(appium_details, dict): + for name, details in appium_details.items(): + stored_serial = details.get("serial") + if stored_serial and (stored_serial == device_serial or stored_serial in device_serial or device_serial in stored_serial): + return details.get("driver") + + return None + + def fetch_xml_and_screenshot(device_serial: str | None = None) -> tuple[str, bytes]: """ Single-function fetch. Primary path uses ONE adb exec-out command to capture UI XML + PNG (base64) in a single stream. Falls back (still inside this function) if markers or outputs are invalid. """ + # Try Appium first + try: + appium_driver = get_appium_driver_for_serial(device_serial) + if appium_driver is not None: + xml = appium_driver.page_source + png = appium_driver.get_screenshot_as_png() + if xml and png: + return xml, png + except Exception: + pass + device_flag = f"-s {device_serial}" if device_serial else "" SPLIT = "__ZEUZ_SPLIT__" @@ -206,6 +237,8 @@ def fetch_xml_and_screenshot(device_serial: str | None = None) -> tuple[str, byt if "