Files
agentic-mobile-control/openspec/changes/android-driver/tasks.md
T

3.9 KiB

1. Verify Appium UiAutomator2 command surface

  • 1.1 Read the installed Appium-Python-Client UiAutomator2 driver source/docs (appium.options.android.uiautomator2, appium.webdriver extensions) to confirm the exact mobile-command names and parameters for: a tap/click gesture at a coordinate, a coordinate-to-coordinate swipe/drag with duration, and a home-button press. Confirm the exact capability key name for per-session port isolation (UiAutomator2's analog to WDA's wdaLocalPort).

2. Driver implementation

  • 2.1 Add driver/android_driver.py with AndroidDriverConfig (frozen dataclass): server_url (default http://127.0.0.1:4723), platform_name (default "Android"), automation_name (default "UiAutomator2"), device_name, udid, system_port, no_reset (default True), extra_capabilities.
  • 2.2 Implement AndroidDriver(Driver).connect()/disconnect() using appium.webdriver + UiAutomator2Options, building capabilities the same way WDADriver.connect() does, with the same _require_client() guard and DeviceOfflineError on connect failure.
  • 2.3 Implement screenshot(), tree(), input(), launch(), terminate(), lock(), unlock() using the same cross-platform Appium client methods WDADriver already uses (get_screenshot_as_png, page_source, switch_to.active_element.send_keys, activate_app, terminate_app, lock, unlock).
  • 2.4 Implement tap(), swipe(), home() using the mobile-command names/parameters confirmed in task 1.1.
  • 2.5 Wrap every method's underlying exception into DriverError (DeviceOfflineError for connect failure and for calls made before a client exists), matching WDADriver's try/except-per-method pattern exactly.

3. Registry wiring

  • 3.1 Add build_android_driver_factory to driver/registry.py, mirroring build_wda_driver_factory's logic for splitting connection_info into declared AndroidDriverConfig fields vs. extra_capabilities.
  • 3.2 Register SUPPORTED_DRIVER_TYPES["uiautomator2"] = build_android_driver_factory.

4. Unit tests

  • 4.1 Add mocked unit tests for AndroidDriver (mock appium.webdriver.Remote, no real device/emulator) covering: connect builds a client with the expected capabilities from a given AndroidDriverConfig; connect failure raises DeviceOfflineError; calling any operation before connect() raises DeviceOfflineError; each operation's underlying exception is wrapped into DriverError.
  • 4.2 Add a unit test for build_android_driver_factory covering connection_info field extraction and extra_capabilities merging (mirror build_wda_driver_factory's existing test coverage if any exists; if none exists today, note that in the test file rather than silently skipping equivalent WDA coverage).

5. Integration test

  • 5.1 Add tests/test_android_integration.py mirroring tests/test_wda_integration.py's structure: @pytest.mark.integration, pytest.skip when APEX_ANDROID_SERVER_URL is unset, optional APEX_ANDROID_UDID/APEX_ANDROID_DEVICE_NAME, connects and asserts a non-empty screenshot() before disconnecting.

6. Spec and docs

  • 6.1 Confirm openspec/changes/android-driver/specs/driver-registry/spec.md's driver_type="uiautomator2" scenario still matches the shipped registry key and behavior exactly; update the delta if anything changed during implementation (e.g. the system-port capability name).
  • 6.2 Correct docs/MACOS_IPHONE_SETUP.md §1: replace "Android 只是架构上的未来目标,当前 driver/registry.py 没有注册 Android Driver" with an accurate statement that the Android driver is registered, while a full real-device setup guide remains separate follow-up work.

7. Verification

  • 7.1 Run uv run --all-packages pytest -m "not integration" and confirm no regressions.
  • 7.2 Run the project's lint/format checks against the new files and fix any violations.
  • 7.3 Run openspec validate android-driver --strict and confirm it passes.