""" Android hardware.radio 组件 — RadioManager, RadioTuner, RadioMetadata 等 方法签名完全对齐 Android SDK """ from __future__ import annotations import threading from typing import Any, Callable, Dict, List, Optional, Set from .._core import Stub, AndroidOnlyError from ..java.lang import RuntimeException IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {}) # ═══════════════════════════════════════════════════════════════ # RadioMetadata # ═══════════════════════════════════════════════════════════════ class RadioMetadata(Stub): """RadioMetadata — 收音机元数据""" METADATA_KEY_ART = 0x00000001 METADATA_KEY_ARTIST = 0x00000002 METADATA_KEY_TITLE = 0x00000003 METADATA_KEY_ALBUM = 0x00000004 METADATA_KEY_GENRE = 0x00000005 METADATA_KEY_CLOCK = 0x00000006 METADATA_KEY_ICON = 0x00000007 METADATA_KEY_RDS_PI = 0x00000008 METADATA_KEY_RDS_PS = 0x00000009 METADATA_KEY_RDS_RT = 0x0000000A METADATA_KEY_DAB_ENSEMBLE_NAME = 0x0000000B METADATA_KEY_DAB_ECC = 0x0000000C METADATA_KEY_DAB_IDENTIFIER = 0x0000000D METADATA_KEY_DAB_SERVICE_NAME = 0x0000000E def __init__(self): super().__init__() self._data: Dict[int, Any] = {} def getString(self, key: int) -> Optional[str]: val = self._data.get(key) return str(val) if val is not None else None def getInt(self, key: int) -> int: return int(self._data.get(key, 0)) def getLong(self, key: int) -> int: return int(self._data.get(key, 0)) def getBitmap(self, key: int) -> Any: return self._data.get(key) def getText(self, key: int) -> Optional[str]: return self.getString(key) def containsKey(self, key: int) -> bool: return key in self._data def keySet(self) -> Set[int]: return set(self._data.keys()) def putString(self, key: int, value: str): self._data[key] = value def putInt(self, key: int, value: int): self._data[key] = value def toString(self) -> str: return f"RadioMetadata{{{len(self._data)} entries}}" # ═══════════════════════════════════════════════════════════════ # RadioManager.ProgramInfo # ═══════════════════════════════════════════════════════════════ class RadioManager: """RadioManager — 收音机管理器(命名空间)""" STATUS_SUCCESS = 0 STATUS_ERROR = -1 STATUS_INVALID_ARGUMENTS = -2 STATUS_INVALID_OPERATION = -3 STATUS_NO_ENTRY = -4 STATUS_PERMISSION_DENIED = -5 STATUS_NOT_SUPPORTED = -6 STATUS_NOT_INITIALIZED = -7 STATUS_BUSY = -8 STATUS_TIMED_OUT = -9 STATUS_DEAD_OBJECT = -10 class RadioManager_ProgramInfo(Stub): """RadioManager.ProgramInfo — 节目信息""" INFO_TYPE_MIN = 0 INFO_TYPE_MAX = 1 def __init__(self): super().__init__() self._metadata = RadioMetadata() self._info_type: int = 0 self._channel: int = 0 self._tuning_frequency: int = 0 self._program_type: int = 0 self._digital: bool = False self._emergency: bool = False self._traffic: bool = False self._music: bool = False self._news: bool = False self._talk: bool = False self._sport: bool = False self._weather: bool = False self._classical: bool = False def getRadioMetadata(self) -> RadioMetadata: return self._metadata def getInfoType(self) -> int: return self._info_type def getChannel(self) -> int: return self._channel def getTuningFrequency(self) -> int: return self._tuning_frequency def getProgramType(self) -> int: return self._program_type def isDigital(self) -> bool: return self._digital def isEmergency(self) -> bool: return self._emergency def isTraffic(self) -> bool: return self._traffic def isMusic(self) -> bool: return self._music def isNews(self) -> bool: return self._news def isTalk(self) -> bool: return self._talk def isSport(self) -> bool: return self._sport def isWeather(self) -> bool: return self._weather def isClassical(self) -> bool: return self._classical def toString(self) -> str: return f"ProgramInfo{{channel={self._channel}, digital={self._digital}}}" RadioManager.ProgramInfo = RadioManager_ProgramInfo # ═══════════════════════════════════════════════════════════════ # RadioManager.ModuleProperties # ═══════════════════════════════════════════════════════════════ class RadioManager_ModuleProperties(Stub): """RadioManager.ModuleProperties — 模块属性""" def __init__(self, id_: int = 0, service_name: str = "radio", class_id: int = 0, implementor: str = "Android-pyApi", hal_version: int = 2, supported_program_types: Optional[List[int]] = None, supported_sound_bands: Optional[List[int]] = None, supported_deemphasis: Optional[List[int]] = None, supported_regions: Optional[List[int]] = None, min_freq: int = 87500, max_freq: int = 108000, freq_step: int = 100): super().__init__() self._id = id_ self._service_name = service_name self._class_id = class_id self._implementor = implementor self._hal_version = hal_version self._supported_program_types = supported_program_types or [0, 1] self._supported_sound_bands = supported_sound_bands or [0] self._supported_deemphasis = supported_deemphasis or [50] self._supported_regions = supported_regions or [0] self._min_freq = min_freq self._max_freq = max_freq self._freq_step = freq_step self._vendor_info: Dict[str, str] = {} self._initialization_complete: bool = True self._bg_scan_available: bool = True self._program_info_available: bool = True self._antenna_connected: bool = True def getId(self) -> int: return self._id def getServiceName(self) -> str: return self._service_name def getClassId(self) -> int: return self._class_id def getImplementor(self) -> str: return self._implementor def getHALVersion(self) -> int: return self._hal_version def getSupportedProgramTypes(self) -> List[int]: return list(self._supported_program_types) def getSupportedSoundBands(self) -> List[int]: return list(self._supported_sound_bands) def getSupportedDeemphasis(self) -> List[int]: return list(self._supported_deemphasis) def getSupportedRegions(self) -> List[int]: return list(self._supported_regions) def getMinTuningFrequency(self) -> int: return self._min_freq def getMaxTuningFrequency(self) -> int: return self._max_freq def getTuningFrequencyStep(self) -> int: return self._freq_step def getVendorInfo(self) -> Dict[str, str]: return dict(self._vendor_info) def isInitializationComplete(self) -> bool: return self._initialization_complete def isBgScanAvailable(self) -> bool: return self._bg_scan_available def isProgramInfoAvailable(self) -> bool: return self._program_info_available def isAntennaConnected(self) -> bool: return self._antenna_connected def toString(self) -> str: return f"ModuleProperties{{id={self._id}, name={self._service_name}}}" RadioManager.ModuleProperties = RadioManager_ModuleProperties # ═══════════════════════════════════════════════════════════════ # RadioTuner # ═══════════════════════════════════════════════════════════════ class RadioTuner(Stub): """RadioTuner — 收音机调谐器""" DIRECTION_DOWN = 0 DIRECTION_UP = 1 def __init__(self): super().__init__() self._frequency: int = 100000 # 100 MHz self._muted: bool = False self._configuration: Optional[Dict[str, Any]] = None def scan(self, direction: int, skipSubChannel: bool = False) -> int: step = 100 if direction == self.DIRECTION_UP else -100 self._frequency += step return RadioManager.STATUS_SUCCESS def step(self, direction: int, skipSubChannel: bool = False) -> int: return self.scan(direction, skipSubChannel) def tune(self, frequency: int, programType: int = -1) -> int: self._frequency = frequency return RadioManager.STATUS_SUCCESS def cancel(self) -> int: return RadioManager.STATUS_SUCCESS def cancelAnnouncement(self) -> int: return RadioManager.STATUS_SUCCESS def getConfiguration(self) -> Optional[Dict[str, Any]]: return self._configuration def setConfiguration(self, configuration: Dict[str, Any]) -> int: self._configuration = dict(configuration) return RadioManager.STATUS_SUCCESS def getMute(self) -> bool: return self._muted def setMute(self, mute: bool) -> int: self._muted = mute return RadioManager.STATUS_SUCCESS def getProgramInformation(self, fullInfo: bool = True) -> Optional[RadioManager.ProgramInfo]: info = RadioManager.ProgramInfo() info._tuning_frequency = self._frequency return info def isAntennaConnected(self) -> bool: return True def hasControl(self) -> bool: return True def getParameters(self, keys: List[str]) -> Dict[str, str]: return {} def setParameters(self, parameters: Dict[str, str]) -> int: return RadioManager.STATUS_SUCCESS def close(self): pass def toString(self) -> str: return f"RadioTuner{{frequency={self._frequency}}}" # ═══════════════════════════════════════════════════════════════ # RadioManager (main class) # ═══════════════════════════════════════════════════════════════ class RadioManager(Stub): """RadioManager — 收音机管理器""" STATUS_SUCCESS = 0 STATUS_ERROR = -1 STATUS_INVALID_ARGUMENTS = -2 STATUS_INVALID_OPERATION = -3 STATUS_NO_ENTRY = -4 STATUS_PERMISSION_DENIED = -5 STATUS_NOT_SUPPORTED = -6 STATUS_NOT_INITIALIZED = -7 STATUS_BUSY = -8 STATUS_TIMED_OUT = -9 STATUS_DEAD_OBJECT = -10 def __init__(self): super().__init__() self._lock = threading.Lock() self._modules: List[RadioManager.ModuleProperties] = [ RadioManager.ModuleProperties(id_=0, service_name="FM Radio"), ] self._tuner: Optional[RadioTuner] = None self._enabled: bool = False self._callbacks: List[Any] = [] def listModules(self, modules: List[Any]) -> int: modules.clear() modules.extend(self._modules) return self.STATUS_SUCCESS def open(self, moduleId: int, tunerCallback: Any) -> Optional[RadioTuner]: self._tuner = RadioTuner() return self._tuner def close(self, tuner: RadioTuner): tuner.close() self._tuner = None def getModuleProperties(self, moduleId: int) -> Optional[RadioManager.ModuleProperties]: for m in self._modules: if m.getId() == moduleId: return m return None def getParameters(self, moduleId: int, keys: List[str]) -> Dict[str, str]: return {} def setParameters(self, moduleId: int, parameters: Dict[str, str]) -> int: return self.STATUS_SUCCESS def isEnabled(self) -> bool: return self._enabled def registerCallback(self, callback: Any, handler: Any = None) -> int: if callback not in self._callbacks: self._callbacks.append(callback) return self.STATUS_SUCCESS def unregisterCallback(self, callback: Any) -> int: if callback in self._callbacks: self._callbacks.remove(callback) return self.STATUS_SUCCESS def registerClient(self, packageName: str, callback: Any) -> int: return self.STATUS_SUCCESS def unregisterClient(self, packageName: str) -> int: return self.STATUS_SUCCESS def toString(self) -> str: return f"RadioManager@{hex(id(self))}" # ═══════════════════════════════════════════════════════════════ # __all__ # ═══════════════════════════════════════════════════════════════ __all__ = [ "RadioManager", "RadioTuner", "RadioMetadata", ]