fix: Wi-Fi 恢复失败后继续搜索设备 (#66)

This commit is contained in:
chengma
2026-08-09 22:18:55 +08:00
parent 8643c37211
commit ff8cdd77c3
4 changed files with 97 additions and 19 deletions
+8
View File
@@ -40,6 +40,14 @@ class AndroidWifiConversionResult:
devices: List[AndroidDevice] devices: List[AndroidDevice]
@dataclass(frozen=True)
class AndroidDeviceSearchResult:
"""一次设备搜索的结果,可同时携带已保存设备恢复警告。"""
devices: List[AndroidDevice]
restore_warning: str = ""
CommandRunner = Callable[[Sequence[str], float], subprocess.CompletedProcess] CommandRunner = Callable[[Sequence[str], float], subprocess.CompletedProcess]
ProgressCallback = Callable[[str], None] ProgressCallback = Callable[[str], None]
Sleeper = Callable[[float], None] Sleeper = Callable[[float], None]
+35 -7
View File
@@ -18,6 +18,7 @@ from PyQt5.QtCore import (
from .android_device_service import ( from .android_device_service import (
AndroidDeviceConversionCancelled, AndroidDeviceConversionCancelled,
AndroidDeviceSearchError, AndroidDeviceSearchError,
AndroidDeviceSearchResult,
AndroidDeviceService, AndroidDeviceService,
PDD_PACKAGE_NAME, PDD_PACKAGE_NAME,
) )
@@ -130,11 +131,18 @@ class AndroidDeviceSearchWorker(QObject):
def run(self) -> None: def run(self) -> None:
try: try:
try: try:
restore_warning = ""
if self._restore_serial: if self._restore_serial:
devices = self._service.restore_saved_device( try:
self._restore_serial, devices = self._service.restore_saved_device(
lambda: self._cancelled, self._restore_serial,
) lambda: self._cancelled,
)
except AndroidDeviceSearchError as exc:
restore_warning = str(exc)
devices = self._service.search(
lambda: self._cancelled
)
else: else:
devices = self._service.search(lambda: self._cancelled) devices = self._service.search(lambda: self._cancelled)
except AndroidDeviceSearchError as exc: except AndroidDeviceSearchError as exc:
@@ -145,7 +153,9 @@ class AndroidDeviceSearchWorker(QObject):
self.failed.emit(str(exc) or "无法搜索 Android 设备") self.failed.emit(str(exc) or "无法搜索 Android 设备")
else: else:
if not self._cancelled: if not self._cancelled:
self.succeeded.emit(devices) self.succeeded.emit(
AndroidDeviceSearchResult(devices, restore_warning)
)
finally: finally:
self.completed.emit() self.completed.emit()
@@ -897,7 +907,7 @@ class SettingsPageEventBinder(QObject):
return AndroidDeviceInfo(serial) if serial else None return AndroidDeviceInfo(serial) if serial else None
@pyqtSlot(object) @pyqtSlot(object)
def _on_search_succeeded(self, devices) -> None: def _on_search_succeeded(self, result: AndroidDeviceSearchResult) -> None:
if self._closing: if self._closing:
return return
@@ -909,7 +919,7 @@ class SettingsPageEventBinder(QObject):
android_version=device.android_version, android_version=device.android_version,
status=device.status, status=device.status,
) )
for device in devices for device in result.devices
] ]
self._page.set_android_devices(rows) self._page.set_android_devices(rows)
saved_device = self._page.deviceTableModel.device_for_serial( saved_device = self._page.deviceTableModel.device_for_serial(
@@ -919,6 +929,24 @@ class SettingsPageEventBinder(QObject):
self._page.deviceTableModel.set_checked_serial( self._page.deviceTableModel.set_checked_serial(
self._saved_android_serial self._saved_android_serial
) )
if result.restore_warning:
action = (
"自动恢复未完成"
if self._search_is_startup_restore
else "搜索完成"
)
found_text = (
f"找到 {len(rows)} 台 Android 设备"
if rows
else "未找到其他 Android 设备"
)
self._page.deviceStatusLabel.setText(
f"{action}:{found_text};已保存设备 "
f"{self._saved_android_serial} 恢复失败:"
f"{result.restore_warning};配置已保留"
)
elif saved_device is not None and saved_device.status == "device":
action = ( action = (
"恢复完成" "恢复完成"
if self._search_is_startup_restore if self._search_is_startup_restore
+49 -12
View File
@@ -556,13 +556,14 @@ class SettingsPageEventTest(unittest.TestCase):
page.eventBinder.shutdown() page.eventBinder.shutdown()
page.deleteLater() page.deleteLater()
def test_manual_wifi_reconnect_failure_keeps_saved_device(self): def test_manual_wifi_reconnect_failure_still_lists_usb_device(self):
wifi_serial = "192.168.0.173:5555" wifi_serial = "192.168.0.173:5555"
self.repository.set(SELECTED_ANDROID_SERIAL_KEY, wifi_serial) self.repository.set(SELECTED_ANDROID_SERIAL_KEY, wifi_serial)
service = SequenceAndroidDeviceService( service = SequenceAndroidDeviceService(
[ [
[AndroidDevice(wifi_serial, "Wi-Fi", "Phone", "14")], [AndroidDevice(wifi_serial, "Wi-Fi", "Phone", "14")],
AndroidDeviceSearchError("目标设备拒绝连接"), AndroidDeviceSearchError("目标设备拒绝连接"),
[AndroidDevice("USB-001", "USB", "Pixel 8", "14")],
] ]
) )
page = SettingsPage( page = SettingsPage(
@@ -574,16 +575,20 @@ class SettingsPageEventTest(unittest.TestCase):
self._wait_until(lambda: page.eventBinder._search_thread is None) self._wait_until(lambda: page.eventBinder._search_thread is None)
page.searchButton.click() page.searchButton.click()
self._wait_until(lambda: service.call_count == 2) self._wait_until(lambda: service.call_count == 3)
self._wait_until(lambda: page.eventBinder._search_thread is None) self._wait_until(lambda: page.eventBinder._search_thread is None)
self.assertEqual( self.assertEqual(
self.repository.get(SELECTED_ANDROID_SERIAL_KEY), self.repository.get(SELECTED_ANDROID_SERIAL_KEY),
wifi_serial, wifi_serial,
) )
self.assertEqual(page.deviceTableModel.checked_serial, wifi_serial) self.assertIsNotNone(
self.assertIn("无法重新连接", page.deviceStatusLabel.text()) page.deviceTableModel.device_for_serial("USB-001")
self.assertIn("已保存配置未更改", page.deviceStatusLabel.text()) )
self.assertEqual(page.deviceTableModel.checked_serial, "")
self.assertIn("找到 1 台 Android 设备", page.deviceStatusLabel.text())
self.assertIn("恢复失败", page.deviceStatusLabel.text())
self.assertIn("配置已保留", page.deviceStatusLabel.text())
page.eventBinder.shutdown() page.eventBinder.shutdown()
page.deleteLater() page.deleteLater()
@@ -591,9 +596,38 @@ class SettingsPageEventTest(unittest.TestCase):
wifi_serial = "192.168.0.173:5555" wifi_serial = "192.168.0.173:5555"
self.repository.set(SELECTED_ANDROID_SERIAL_KEY, wifi_serial) self.repository.set(SELECTED_ANDROID_SERIAL_KEY, wifi_serial)
service = SequenceAndroidDeviceService( service = SequenceAndroidDeviceService(
[AndroidDeviceSearchError("目标设备拒绝连接")] [AndroidDeviceSearchError("目标设备拒绝连接"), []]
) )
page = SettingsPage(
settings_repository=self.repository,
admin_gateway=MockAdminGateway(),
android_device_service=service,
)
self._wait_until(lambda: service.call_count == 2)
self._wait_until(lambda: page.eventBinder._search_thread is None)
self.assertEqual(
self.repository.get(SELECTED_ANDROID_SERIAL_KEY),
wifi_serial,
)
self.assertIn("自动恢复未完成", page.deviceStatusLabel.text())
self.assertIn("未找到其他 Android 设备", page.deviceStatusLabel.text())
self.assertIn("配置已保留", page.deviceStatusLabel.text())
self.assertTrue(page.searchButton.isEnabled())
page.eventBinder.shutdown()
page.deleteLater()
def test_search_failure_after_restore_failure_preserves_previous_rows(self):
wifi_serial = "192.168.0.173:5555"
self.repository.set(SELECTED_ANDROID_SERIAL_KEY, wifi_serial)
service = SequenceAndroidDeviceService(
[
[AndroidDevice(wifi_serial, "Wi-Fi", "Phone", "14")],
AndroidDeviceSearchError("目标设备拒绝连接"),
AndroidDeviceSearchError("adb devices 执行失败"),
]
)
page = SettingsPage( page = SettingsPage(
settings_repository=self.repository, settings_repository=self.repository,
admin_gateway=MockAdminGateway(), admin_gateway=MockAdminGateway(),
@@ -602,13 +636,16 @@ class SettingsPageEventTest(unittest.TestCase):
self._wait_until(lambda: service.call_count == 1) self._wait_until(lambda: service.call_count == 1)
self._wait_until(lambda: page.eventBinder._search_thread is None) self._wait_until(lambda: page.eventBinder._search_thread is None)
self.assertEqual( page.searchButton.click()
self.repository.get(SELECTED_ANDROID_SERIAL_KEY), self._wait_until(lambda: service.call_count == 3)
wifi_serial, self._wait_until(lambda: page.eventBinder._search_thread is None)
self.assertIsNotNone(
page.deviceTableModel.device_for_serial(wifi_serial)
) )
self.assertIn("自动恢复失败", page.deviceStatusLabel.text()) self.assertEqual(page.deviceTableModel.checked_serial, wifi_serial)
self.assertIn("可点击搜索重试", page.deviceStatusLabel.text()) self.assertIn("搜索失败", page.deviceStatusLabel.text())
self.assertTrue(page.searchButton.isEnabled()) self.assertIn("adb devices 执行失败", page.deviceStatusLabel.text())
page.eventBinder.shutdown() page.eventBinder.shutdown()
page.deleteLater() page.deleteLater()
+5
View File
@@ -251,6 +251,11 @@ class TaskTableModel(QAbstractTableModel):
- PDD 包名; - PDD 包名;
- “测试连接”; - “测试连接”;
- 当前设备型号、Android 版本和 PDD 当前状态摘要。 - 当前设备型号、Android 版本和 PDD 当前状态摘要。
- 点击设备“搜索”时可以先尝试恢复已保存的 Wi-Fi ADB,但单台设备恢复失败
不能中断普通设备枚举。表格仍展示 `adb devices -l` 实际找到的 USB 和 Wi-Fi
设备,状态文字同时说明恢复失败原因以及“已保存配置仍保留”。
- 只有普通设备枚举本身失败时才显示“搜索失败”并保留旧表格;程序不得因为
设备暂时离线自动删除已保存配置。
### 自动化 ### 自动化