fix: Wi-Fi 恢复失败后继续搜索设备 (#66)
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
@@ -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:
|
||||||
|
try:
|
||||||
devices = self._service.restore_saved_device(
|
devices = self._service.restore_saved_device(
|
||||||
self._restore_serial,
|
self._restore_serial,
|
||||||
lambda: self._cancelled,
|
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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -251,6 +251,11 @@ class TaskTableModel(QAbstractTableModel):
|
|||||||
- PDD 包名;
|
- PDD 包名;
|
||||||
- “测试连接”;
|
- “测试连接”;
|
||||||
- 当前设备型号、Android 版本和 PDD 当前状态摘要。
|
- 当前设备型号、Android 版本和 PDD 当前状态摘要。
|
||||||
|
- 点击设备“搜索”时可以先尝试恢复已保存的 Wi-Fi ADB,但单台设备恢复失败
|
||||||
|
不能中断普通设备枚举。表格仍展示 `adb devices -l` 实际找到的 USB 和 Wi-Fi
|
||||||
|
设备,状态文字同时说明恢复失败原因以及“已保存配置仍保留”。
|
||||||
|
- 只有普通设备枚举本身失败时才显示“搜索失败”并保留旧表格;程序不得因为
|
||||||
|
设备暂时离线自动删除已保存配置。
|
||||||
|
|
||||||
### 自动化
|
### 自动化
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user