mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-06 20:43:46 +08:00
a82935f326
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: Shane Smiskol <shane@smiskol.com> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: pharmacomaniac <blittle65@gmail.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
106 lines
3.5 KiB
Python
106 lines
3.5 KiB
Python
"""The registered AGNOS radio preference in the global Params namespace.
|
|
|
|
The service uses /data/params/d independently of named application prefixes.
|
|
The key has no manager default: absence must not create or disable the radio."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
import stat
|
|
import tempfile
|
|
|
|
|
|
RADIO_PREFERENCE = Path('/data/params/d/BluetoothEnabled')
|
|
|
|
|
|
class RadioPreference:
|
|
def __init__(self, path: Path = RADIO_PREFERENCE):
|
|
self.path = path
|
|
|
|
@staticmethod
|
|
def _read(path: Path) -> tuple[bytes | None, tuple | None]:
|
|
try:
|
|
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
|
except FileNotFoundError:
|
|
return None, None
|
|
with os.fdopen(fd, 'rb') as stream:
|
|
info = os.fstat(stream.fileno())
|
|
if not stat.S_ISREG(info.st_mode) or info.st_size > 16:
|
|
raise OSError('Invalid Bluetooth enable file')
|
|
value = stream.read(17)
|
|
if len(value) > 16:
|
|
raise OSError('Invalid Bluetooth enable file')
|
|
return value, (info.st_dev, info.st_ino, info.st_mtime_ns, info.st_size)
|
|
|
|
def enabled(self) -> bool:
|
|
value, _ = self._read(self.path)
|
|
return value is not None and value.rstrip(b'\n') == b'1'
|
|
|
|
def begin(self, enabled: bool) -> RadioPreferenceChange:
|
|
return RadioPreferenceChange(self.path, b'1' if enabled else b'0')
|
|
|
|
|
|
class RadioPreferenceChange:
|
|
def __init__(self, path: Path, value: bytes):
|
|
self.path = path
|
|
self.directory = path.parent.resolve(strict=True)
|
|
info = self.directory.stat()
|
|
self.directory_identity = (info.st_dev, info.st_ino)
|
|
self.target = self.directory / path.name
|
|
self.previous, self.previous_identity = RadioPreference._read(self.target)
|
|
self.value = value
|
|
self.owned_identity = None
|
|
|
|
def apply(self) -> None:
|
|
self._write(self.value, self.previous, self.previous_identity)
|
|
self.verify()
|
|
|
|
def current(self, value: bytes | None, identity: tuple | None) -> bool:
|
|
try:
|
|
directory = self.path.parent.resolve(strict=True)
|
|
info = directory.stat()
|
|
return (directory == self.directory and (info.st_dev, info.st_ino) == self.directory_identity and
|
|
RadioPreference._read(self.target) == (value, identity))
|
|
except OSError:
|
|
return False
|
|
|
|
def _write(self, value: bytes, expected: bytes | None, identity: tuple | None) -> None:
|
|
fd, temporary = tempfile.mkstemp(prefix='.bluetooth-enable-', dir=self.directory)
|
|
try:
|
|
with os.fdopen(fd, 'wb') as stream:
|
|
stream.write(value)
|
|
stream.flush()
|
|
os.fsync(stream.fileno())
|
|
info = os.fstat(stream.fileno())
|
|
written_identity = (info.st_dev, info.st_ino, info.st_mtime_ns, info.st_size)
|
|
if not self.current(expected, identity):
|
|
raise OSError('Bluetooth preference changed')
|
|
os.replace(temporary, self.target)
|
|
self.owned_identity = written_identity
|
|
self._sync()
|
|
finally:
|
|
if os.path.exists(temporary):
|
|
os.unlink(temporary)
|
|
|
|
def _sync(self) -> None:
|
|
fd = os.open(self.directory, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
|
|
try:
|
|
os.fsync(fd)
|
|
finally:
|
|
os.close(fd)
|
|
|
|
def verify(self) -> None:
|
|
if not self.current(self.value, self.owned_identity):
|
|
raise OSError('Bluetooth preference changed')
|
|
|
|
def rollback(self) -> bool:
|
|
if not self.current(self.value, self.owned_identity):
|
|
return False
|
|
if self.previous is None:
|
|
self.target.unlink()
|
|
self._sync()
|
|
else:
|
|
self._write(self.previous, self.value, self.owned_identity)
|
|
return True
|