mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-06 20:43:46 +08:00
a531afd02a
Expose pairing readiness and coordinate adapter hand-offs with Android Auto. Show app pairings separately, support individual removal, and improve pairing controls on both comma screens. Add Galaxy companion endpoints and web asset manifests, preserve the plain camera look, and fix headless speed-limit shapes.
72 lines
3.0 KiB
Python
72 lines
3.0 KiB
Python
"""Native settings use Galaxy when Android Auto already owns the Bluetooth adapter."""
|
|
from openpilot.starpilot.bluetooth.owner import AdapterBusyElsewhere, BluetoothOwner, BluetoothRejected, BluetoothUnavailable
|
|
|
|
|
|
class NativeBluetoothOwner(BluetoothOwner):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.galaxy = None
|
|
self.delegated_pairing = False
|
|
self.delegated_scan = False
|
|
|
|
def _galaxy(self, operation, **kwargs):
|
|
if self.galaxy is None:
|
|
from openpilot.starpilot.galaxy_bluetooth.phone_ui import galaxy_call
|
|
self.galaxy = galaxy_call() # Keep the same authenticated session for prompts and polling.
|
|
if operation == 'status':
|
|
status, result = self.galaxy('GET', '/api/bluetooth/status')
|
|
else:
|
|
payload = {'operation': operation}
|
|
for key, value in kwargs.items():
|
|
if key in ('address', 'enabled', 'prompt_id', 'accepted') and value is not None:
|
|
payload['promptId' if key == 'prompt_id' else key] = value
|
|
if operation == 'pairing_response':
|
|
payload['value'] = kwargs.get('value', '')
|
|
status, result = self.galaxy('POST', '/api/bluetooth/action', payload)
|
|
if status == 409:
|
|
raise BluetoothRejected('Bluetooth change was not accepted', code=result.get('code', 'busy'))
|
|
if status != 200 or not isinstance(result.get('devices'), list):
|
|
raise BluetoothUnavailable('Galaxy Bluetooth service is unavailable')
|
|
if operation in ('pair', 'accept_pair'):
|
|
self.delegated_pairing = True
|
|
elif operation == 'cancel_pair':
|
|
self.delegated_pairing = False
|
|
if operation == 'scan':
|
|
self.delegated_scan = True
|
|
elif operation in ('stop_scan', 'pair', 'accept_pair'):
|
|
self.delegated_scan = False
|
|
return result
|
|
|
|
def request(self, operation, *, delegate=True, **kwargs):
|
|
session = kwargs.get('session')
|
|
if session is not None and not self.session_valid(session):
|
|
raise BluetoothRejected('Pairing session expired', code='session_expired')
|
|
if self.galaxy is None:
|
|
try:
|
|
return super().request(operation, **kwargs)
|
|
except AdapterBusyElsewhere:
|
|
if not delegate:
|
|
return super().snapshot(session=session)
|
|
elif not delegate:
|
|
return self.snapshot(session=session)
|
|
return self._galaxy(operation, **kwargs)
|
|
|
|
def snapshot(self, *, session=None):
|
|
if self.galaxy is not None:
|
|
return self._galaxy('status')
|
|
return super().snapshot(session=session)
|
|
|
|
def close(self):
|
|
try:
|
|
if self.galaxy is not None:
|
|
for operation, needed in (('cancel_pair', self.delegated_pairing), ('stop_scan', self.delegated_scan)):
|
|
if needed:
|
|
try:
|
|
self._galaxy(operation)
|
|
except (BluetoothRejected, BluetoothUnavailable, OSError, RuntimeError):
|
|
pass # The daemon also bounds scans and cancels expired pairing sessions.
|
|
finally:
|
|
self.galaxy = None
|
|
self.delegated_pairing = self.delegated_scan = False
|
|
super().close()
|