Resolve the previously-open design questions in the android-driver change by researching the appium-uiautomator2-driver docs and Appium 3 release notes: - tap -> mobile: clickGesture - swipe -> mobile: dragGesture (duration_ms converted to speed px/s) - home -> mobile: pressKey (KEYCODE_HOME) - port isolation -> appium:systemPort capability - Appium 3 breaking changes confirmed to not affect this design Updates design.md (Decisions/Risks/Open Questions/Migration Plan) and tasks.md (section 1 and tasks 2.1/2.4/4.1) accordingly.
4.5 KiB
4.5 KiB
1. Appium UiAutomator2 command surface (confirmed via research, see design.md Decisions)
- 1.1 Sanity-check the confirmed mobile commands against whatever
appium-uiautomator2-driverversion is actually resolved in.venvbefore coding:mobile: clickGesture(tap),mobile: dragGesture(swipe/drag),mobile: pressKey(home),appium:systemPort(port isolation capability). Docs referenced (2026-07):github.com/appium/appium-uiautomator2-driverREADME anddocs/android-mobile-gestures.md.
2. Driver implementation
- 2.1 Add
driver/android_driver.pywithAndroidDriverConfig(frozen dataclass):server_url(defaulthttp://127.0.0.1:4723),platform_name(default"Android"),automation_name(default"UiAutomator2"),device_name,udid,system_port(maps to theappium:systemPortcapability),no_reset(defaultTrue),extra_capabilities. - 2.2 Implement
AndroidDriver(Driver).connect()/disconnect()usingappium.webdriver+UiAutomator2Options, building capabilities the same wayWDADriver.connect()does, with the same_require_client()guard andDeviceOfflineErroron connect failure. - 2.3 Implement
screenshot(),tree(),input(),launch(),terminate(),lock(),unlock()using the same cross-platform Appium client methodsWDADriveralready 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():tap(x, y)→execute_script("mobile: clickGesture", {"x": x, "y": y})swipe(start_x, start_y, end_x, end_y, duration_ms)→execute_script("mobile: dragGesture", {"startX": start_x, "startY": start_y, "endX": end_x, "endY": end_y, "speed": speed})wherespeed = distance / (duration_ms / 1000), guarded against zero/near-zero distancehome()→execute_script("mobile: pressKey", {"keycode": 3})(KeyEvent.KEYCODE_HOME)
- 2.5 Wrap every method's underlying exception into
DriverError(DeviceOfflineErrorfor connect failure and for calls made before a client exists), matchingWDADriver's try/except-per-method pattern exactly.
3. Registry wiring
- 3.1 Add
build_android_driver_factorytodriver/registry.py, mirroringbuild_wda_driver_factory's logic for splittingconnection_infointo declaredAndroidDriverConfigfields 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(mockappium.webdriver.Remote, no real device/emulator) covering: connect builds a client with the expected capabilities from a givenAndroidDriverConfig; connect failure raisesDeviceOfflineError; calling any operation beforeconnect()raisesDeviceOfflineError; each operation's underlying exception is wrapped intoDriverError;swipe()'sduration_ms→speedconversion for both a normal case and a zero/near-zero-distance case (must not divide by zero). - 4.2 Add a unit test for
build_android_driver_factorycoveringconnection_infofield extraction andextra_capabilitiesmerging (mirrorbuild_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.pymirroringtests/test_wda_integration.py's structure:@pytest.mark.integration,pytest.skipwhenAPEX_ANDROID_SERVER_URLis unset, optionalAPEX_ANDROID_UDID/APEX_ANDROID_DEVICE_NAME, connects and asserts a non-emptyscreenshot()before disconnecting.
6. Spec and docs
- 6.1 Confirm
openspec/changes/android-driver/specs/driver-registry/spec.md'sdriver_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 --strictand confirm it passes.