mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-02 14:13:44 +08:00
Fix Bluetooth pairing
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ fi
|
||||
export QCOM_PRIORITY=12
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="19.6.15"
|
||||
export AGNOS_VERSION="19.6.16"
|
||||
fi
|
||||
|
||||
if [ -z "$AGNOS_ACCEPTED_VERSIONS" ]; then
|
||||
|
||||
@@ -38,6 +38,7 @@ class PairingAgent:
|
||||
self._response: tuple[bool, str] | None = None
|
||||
self._generation = 0
|
||||
self._auto_accept_paths: set[str] = set()
|
||||
self._auto_accept_incoming = False
|
||||
|
||||
@property
|
||||
def prompt(self) -> dict[str, Any] | None:
|
||||
@@ -94,9 +95,13 @@ class PairingAgent:
|
||||
else:
|
||||
self._auto_accept_paths.discard(device_path)
|
||||
|
||||
def set_auto_accept_incoming(self, enabled: bool) -> None:
|
||||
with self._condition:
|
||||
self._auto_accept_incoming = enabled
|
||||
|
||||
def auto_accept(self, kind: str, device_path: str) -> bool:
|
||||
with self._condition:
|
||||
return kind in {"confirmation", "authorization"} and device_path in self._auto_accept_paths
|
||||
return kind in {"confirmation", "authorization"} and (self._auto_accept_incoming or device_path in self._auto_accept_paths)
|
||||
|
||||
class BlueZClient:
|
||||
def __init__(self):
|
||||
|
||||
@@ -58,12 +58,21 @@ class BluetoothController:
|
||||
self._radio.start()
|
||||
self._bluez = self._bluez_factory()
|
||||
self._bluez.set_powered(True)
|
||||
self._bluez.agent.set_auto_accept_incoming(self._offroad())
|
||||
try:
|
||||
self._bluez.set_discoverable(True)
|
||||
except Exception as error:
|
||||
cloudlog.warning(f"Bluetooth discoverability setup failed: {error}")
|
||||
return self._bluez
|
||||
|
||||
def initialize(self) -> None:
|
||||
if not self.params.get_bool("BluetoothEnabled"):
|
||||
return
|
||||
try:
|
||||
self._client()
|
||||
except Exception:
|
||||
cloudlog.exception("Bluetooth initialization failed")
|
||||
|
||||
def _reset_client(self) -> None:
|
||||
with self._lock:
|
||||
if self._bluez is not None:
|
||||
@@ -96,6 +105,7 @@ class BluetoothController:
|
||||
try:
|
||||
result.update(self._client().status())
|
||||
result["available"] = True
|
||||
self._bluez.agent.set_auto_accept_incoming(result["offroad"])
|
||||
prompt = result.get("prompt")
|
||||
if prompt is not None and self._pairing_address:
|
||||
prompt["address"] = self._pairing_address
|
||||
@@ -111,9 +121,9 @@ class BluetoothController:
|
||||
if command in OFFROAD_COMMANDS and not self._offroad():
|
||||
raise RuntimeError("Bluetooth settings can only be changed offroad")
|
||||
|
||||
def _pair_worker(self, address: str, device_path: str | None = None) -> None:
|
||||
def _pair_worker(self, address: str) -> None:
|
||||
try:
|
||||
self._client().pair(address, device_path)
|
||||
self._client().pair(address)
|
||||
status = self._client().device_for_address(address)
|
||||
if status.get("audio") and not self.params.get("BluetoothAudioAddress", encoding="utf-8"):
|
||||
self.params.put("BluetoothAudioAddress", address)
|
||||
@@ -189,10 +199,11 @@ class BluetoothController:
|
||||
elif command == "pair":
|
||||
if self._pairing_address:
|
||||
raise RuntimeError("Another Bluetooth device is already pairing")
|
||||
device = self._client().device_for_address(address)
|
||||
self._client().device_for_address(address)
|
||||
self._scan_deadline = 0.0
|
||||
self._pairing_address = address
|
||||
self._pairing_error = ""
|
||||
threading.Thread(target=self._pair_worker, args=(address, device["path"]), daemon=True).start()
|
||||
threading.Thread(target=self._pair_worker, args=(address,), daemon=True).start()
|
||||
elif command == "connect":
|
||||
self._client().connect(address)
|
||||
elif command == "disconnect":
|
||||
@@ -290,6 +301,7 @@ def main() -> None:
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
controller = BluetoothController()
|
||||
threading.Thread(target=controller.initialize, daemon=True).start()
|
||||
threading.Thread(target=controller.maintain_connections, daemon=True).start()
|
||||
try:
|
||||
with BluetoothServer(BLUETOOTH_SOCKET_PATH, controller) as server:
|
||||
|
||||
@@ -39,6 +39,9 @@ class FakeAgent:
|
||||
def __init__(self):
|
||||
self.responses = []
|
||||
|
||||
def set_auto_accept_incoming(self, _enabled):
|
||||
pass
|
||||
|
||||
def respond(self, prompt_id, accepted, value):
|
||||
self.responses.append((prompt_id, accepted, value))
|
||||
return prompt_id == "prompt"
|
||||
@@ -230,6 +233,9 @@ def test_desktop_fake_bluetooth_cannot_activate_on_device(monkeypatch, tmp_path)
|
||||
|
||||
def test_pairing_agent_accept_reject_and_timeout():
|
||||
agent = PairingAgent()
|
||||
agent.set_auto_accept_incoming(True)
|
||||
assert agent.request("confirmation", "/incoming", "123456") == (True, "")
|
||||
agent.set_auto_accept_incoming(False)
|
||||
result = []
|
||||
worker = threading.Thread(target=lambda: result.append(agent.request("confirmation", "/device", "123456", timeout=1.0)))
|
||||
worker.start()
|
||||
@@ -253,6 +259,18 @@ def test_disabled_status_does_not_start_radio_or_bluez():
|
||||
assert radio.starts == 0 and created == []
|
||||
|
||||
|
||||
def test_enabled_initialization_registers_bluetooth_agent_without_ui_poll():
|
||||
params = FakeParams(IsOffroad=True, BluetoothEnabled=True)
|
||||
radio = FakeRadio()
|
||||
created = []
|
||||
controller = BluetoothController(params, lambda: created.append(FakeBlueZ()) or created[-1], radio)
|
||||
|
||||
controller.initialize()
|
||||
|
||||
assert radio.starts == 1 and len(created) == 1
|
||||
assert created[0].powered
|
||||
|
||||
|
||||
def test_power_pair_audio_and_offroad_enforcement():
|
||||
params = FakeParams(IsOffroad=True, BluetoothEnabled=False)
|
||||
radio = FakeRadio()
|
||||
@@ -401,7 +419,7 @@ def test_scan_stops_after_timeout():
|
||||
assert not client.discovering and controller._scan_deadline == 0.0
|
||||
|
||||
|
||||
def test_pair_stops_discovery_before_starting_pair():
|
||||
def test_pair_keeps_discovery_until_pair_starts():
|
||||
params = FakeParams(IsOffroad=True, BluetoothEnabled=True)
|
||||
client = FakeBlueZ()
|
||||
controller = BluetoothController(params, lambda: client, FakeRadio())
|
||||
@@ -412,7 +430,9 @@ def test_pair_stops_discovery_before_starting_pair():
|
||||
while not any(action[0] == "pair" for action in client.actions) and time.monotonic() < deadline:
|
||||
time.sleep(0.01)
|
||||
|
||||
assert client.actions.index(("stop_scan", "")) < client.actions.index(("pair", client.device["address"]))
|
||||
pair_index = client.actions.index(("pair", client.device["address"]))
|
||||
assert client.actions[-1] == ("stop_scan", "")
|
||||
assert pair_index < len(client.actions) - 1
|
||||
|
||||
|
||||
def test_audio_queue_is_nonblocking_and_falls_back():
|
||||
|
||||
@@ -56,30 +56,30 @@
|
||||
},
|
||||
{
|
||||
"name": "boot",
|
||||
"url": "https://files.firestar.link/x/n2jco20tm4oh/boot23.img.xz",
|
||||
"url": "https://files.firestar.link/x/83cmdtzb2sav/boot25.img.xz",
|
||||
"fallback_urls": [
|
||||
"https://files-east.firestar.link/x/rjthk2ij2j8a/boot23.img.xz"
|
||||
"https://files-east.firestar.link/x/o3r7dpay7yj5/boot25.img.xz"
|
||||
],
|
||||
"hash": "e0cae2edf9953ba5b94ffd868d74a9b8ab4fa253625e7120641b49d6e7052586",
|
||||
"hash_raw": "e0cae2edf9953ba5b94ffd868d74a9b8ab4fa253625e7120641b49d6e7052586",
|
||||
"hash": "846d9e41fe0eb3543a01cb9a55a6bb540e4097dd838ada890674b654bd97a49a",
|
||||
"hash_raw": "846d9e41fe0eb3543a01cb9a55a6bb540e4097dd838ada890674b654bd97a49a",
|
||||
"size": 48302080,
|
||||
"sparse": false,
|
||||
"full_check": true,
|
||||
"has_ab": true,
|
||||
"ondevice_hash": "e0cae2edf9953ba5b94ffd868d74a9b8ab4fa253625e7120641b49d6e7052586"
|
||||
"ondevice_hash": "846d9e41fe0eb3543a01cb9a55a6bb540e4097dd838ada890674b654bd97a49a"
|
||||
},
|
||||
{
|
||||
"name": "system",
|
||||
"url": "https://files.firestar.link/x/5y3tzu7fic02/system23.img.xz",
|
||||
"url": "https://files.firestar.link/x/ser56g04xioj/system25.img.xz",
|
||||
"fallback_urls": [
|
||||
"https://files-east.firestar.link/x/nuxu72xr6z2y/system23.img.xz"
|
||||
"https://files-east.firestar.link/x/90fsutnuzy13/system25.img.xz"
|
||||
],
|
||||
"hash": "a896e86181114e32b028dc08a27c16571a9f58a120af50018d0a410323013ce7",
|
||||
"hash_raw": "a896e86181114e32b028dc08a27c16571a9f58a120af50018d0a410323013ce7",
|
||||
"hash": "f81ac06c0634ed0dadd5b4778f3b5052a2779d69669b7e70e21505c951ce6ccc",
|
||||
"hash_raw": "f81ac06c0634ed0dadd5b4778f3b5052a2779d69669b7e70e21505c951ce6ccc",
|
||||
"size": 4718592000,
|
||||
"sparse": false,
|
||||
"full_check": false,
|
||||
"has_ab": true,
|
||||
"ondevice_hash": "a896e86181114e32b028dc08a27c16571a9f58a120af50018d0a410323013ce7"
|
||||
"ondevice_hash": "f81ac06c0634ed0dadd5b4778f3b5052a2779d69669b7e70e21505c951ce6ccc"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user