新增模块覆盖: 系统层 (14): system, security, print, opengl, renderscript, transition, test, service_notification, service_controls, service_quicksettings, service_wallpaper, service_autofill, service_dreams, service_vr 应用层 (13): app_admin, app_backup, app_job, app_usage, app_role, app_people, appwidget, companion, credentials, mtp, sip, telecom, speech 硬件媒体层 (15): hardware_display, hardware_fingerprint, hardware_usb, hardware_input, media_audiofx, media_browse, media_session, media_tv, media_midi, media_projection, uwb, se, view_autofill, view_textclassifier, view_translation 总计 94 个模块,75,342 行代码
359 lines
11 KiB
Python
359 lines
11 KiB
Python
"""
|
|
Android media.tv 组件 — TvInputManager, TvInputInfo, TvInputService 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
from typing import Any, Callable, Dict, List, Optional
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TvInputManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TvInputManager(Stub):
|
|
"""TvInputManager — 电视输入管理器"""
|
|
|
|
ACTION_VIEW_RECORDING_SCHEDULES = "android.tv.action.VIEW_RECORDING_SCHEDULES"
|
|
ACTION_WATCH_NEXT = "android.tv.action.WATCH_NEXT"
|
|
|
|
TIME_SHIFT_STATUS_AVAILABLE = 0
|
|
TIME_SHIFT_STATUS_UNAVAILABLE = 1
|
|
TIME_SHIFT_STATUS_UNKNOWN = 2
|
|
TIME_SHIFT_STATUS_UNSUPPORTED = 3
|
|
|
|
VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 8
|
|
VIDEO_UNAVAILABLE_REASON_BUFFERING = 3
|
|
VIDEO_UNAVAILABLE_REASON_CAS = 7
|
|
VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE = 5
|
|
VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = 6
|
|
VIDEO_UNAVAILABLE_REASON_PREEMPTED = 4
|
|
VIDEO_UNAVAILABLE_REASON_TUNING = 1
|
|
VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0
|
|
VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# TvInputCallback
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class TvInputCallback(Stub):
|
|
"""TvInputManager.TvInputCallback — 电视输入回调"""
|
|
|
|
def onInputAdded(self, inputId: str):
|
|
pass
|
|
|
|
def onInputRemoved(self, inputId: str):
|
|
pass
|
|
|
|
def onInputChanged(self, inputId: str):
|
|
pass
|
|
|
|
def onInputStateChanged(self, inputId: str, state: int):
|
|
pass
|
|
|
|
def onTvInputInfoUpdated(self, inputInfo: "TvInputInfo"):
|
|
pass
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._inputs: Dict[str, TvInputInfo] = {}
|
|
self._callbacks: Dict[int, TvInputManager.TvInputCallback] = {}
|
|
|
|
def getTvInputList(self) -> List["TvInputInfo"]:
|
|
return list(self._inputs.values())
|
|
|
|
def getTvInputInfo(self, inputId: str) -> Optional["TvInputInfo"]:
|
|
return self._inputs.get(inputId)
|
|
|
|
def getCurrentTvInputInfo(self) -> Optional["TvInputInfo"]:
|
|
for inp in self._inputs.values():
|
|
return inp
|
|
return None
|
|
|
|
def updateTvInputInfo(self, inputInfo: "TvInputInfo"):
|
|
if inputInfo:
|
|
self._inputs[inputInfo.getId()] = inputInfo
|
|
|
|
def registerCallback(self, callback: TvInputCallback, handler: Any = None):
|
|
lid = id(callback)
|
|
self._callbacks[lid] = callback
|
|
|
|
def unregisterCallback(self, callback: TvInputCallback):
|
|
lid = id(callback)
|
|
self._callbacks.pop(lid, None)
|
|
|
|
def createRecordingSession(self, recordingService: str, inputId: str):
|
|
raise AndroidOnlyError("TvInputManager.createRecordingSession() is not available on desktop")
|
|
|
|
def sendTvInputNotifyIntent(self, intent: Any, inputId: str):
|
|
pass
|
|
|
|
def isParentalControlsEnabled(self) -> bool:
|
|
return False
|
|
|
|
def isRatingBlocked(self, rating: str) -> bool:
|
|
return False
|
|
|
|
def getBlockedRatings(self) -> List[str]:
|
|
return []
|
|
|
|
def getAvailableTvInputs(self) -> List[str]:
|
|
return list(self._inputs.keys())
|
|
|
|
def getTvContentRatingSystems(self) -> List[str]:
|
|
return ["US_TV", "US_MOVIE"]
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TvInputInfo
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TvInputInfo(Stub):
|
|
"""TvInputInfo — 电视输入信息"""
|
|
|
|
TYPE_COMPONENT = 1005
|
|
TYPE_COMPOSITE = 1004
|
|
TYPE_HDMI = 1007
|
|
TYPE_OTHER = 1001
|
|
TYPE_SCART = 1003
|
|
TYPE_SVIDEO = 1006
|
|
TYPE_TUNER = 0
|
|
TYPE_DISPLAY_LINK = 1008
|
|
TYPE_VGA = 1002
|
|
|
|
def __init__(self, id: str = "", serviceInfo: Any = None,
|
|
parentId: str = "", type_: int = TYPE_TUNER,
|
|
hdmiDeviceInfo: Any = None,
|
|
isHidden: bool = False, canRecord: bool = False,
|
|
canPauseRecording: bool = False):
|
|
super().__init__()
|
|
self._id = id
|
|
self._service_info = serviceInfo
|
|
self._parent_id = parentId
|
|
self._type = type_
|
|
self._hdmi_device_info = hdmiDeviceInfo
|
|
self._is_hidden = isHidden
|
|
self._can_record = canRecord
|
|
self._can_pause_recording = canPauseRecording
|
|
|
|
def getId(self) -> str:
|
|
return self._id
|
|
|
|
def getServiceInfo(self) -> Any:
|
|
return self._service_info
|
|
|
|
def getParentId(self) -> str:
|
|
return self._parent_id
|
|
|
|
def getType(self) -> int:
|
|
return self._type
|
|
|
|
def getHdmiDeviceInfo(self) -> Any:
|
|
return self._hdmi_device_info
|
|
|
|
def loadIcon(self, context: Any) -> Any:
|
|
return None
|
|
|
|
def loadLogo(self, context: Any) -> Any:
|
|
return None
|
|
|
|
def createIntentForSetupScreen(self) -> Any:
|
|
return None
|
|
|
|
def isHidden(self) -> bool:
|
|
return self._is_hidden
|
|
|
|
def canRecord(self) -> bool:
|
|
return self._can_record
|
|
|
|
def canPauseRecording(self) -> bool:
|
|
return self._can_pause_recording
|
|
|
|
def toString(self) -> str:
|
|
type_names = {
|
|
TvInputInfo.TYPE_TUNER: "TUNER",
|
|
TvInputInfo.TYPE_HDMI: "HDMI",
|
|
TvInputInfo.TYPE_COMPOSITE: "COMPOSITE",
|
|
TvInputInfo.TYPE_COMPONENT: "COMPONENT",
|
|
}
|
|
return f"TvInputInfo(id={self._id}, type={type_names.get(self._type, str(self._type))})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TvInputService
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TvInputService(Stub):
|
|
"""TvInputService — 电视输入服务"""
|
|
|
|
RECORDING_ERROR_RECORDING_LOST = 0
|
|
RECORDING_ERROR_TIMEOUT = 1
|
|
RECORDING_ERROR_OTHER = 2
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# Session
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class Session(Stub):
|
|
"""TvInputService.Session — 电视会话"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._main = False
|
|
self._stream_volume = 1.0
|
|
self._caption_enabled = False
|
|
|
|
def onSetSurface(self, surface: Any) -> bool:
|
|
return True
|
|
|
|
def onSurfaceChanged(self, format: int, width: int, height: int):
|
|
pass
|
|
|
|
def onSurfaceReleased(self):
|
|
pass
|
|
|
|
def onAppPrivateCommand(self, action: str, data: Any):
|
|
pass
|
|
|
|
def onCreateOverlayView(self) -> Any:
|
|
return None
|
|
|
|
def onRelayoutContent(self):
|
|
pass
|
|
|
|
def onSetCaptionEnabled(self, enabled: bool):
|
|
self._caption_enabled = enabled
|
|
|
|
def onSetStreamVolume(self, volume: float):
|
|
self._stream_volume = volume
|
|
|
|
def onTimeShiftSetCurrentPositionRequest(self, positionMs: int):
|
|
pass
|
|
|
|
def notifyTimeShiftStatusChanged(self, status: int):
|
|
pass
|
|
|
|
def scheduleOverlayView(self, view: Any):
|
|
pass
|
|
|
|
def timeShiftPlay(self, uri: str):
|
|
pass
|
|
|
|
def timeShiftPause(self):
|
|
pass
|
|
|
|
def timeShiftResume(self):
|
|
pass
|
|
|
|
def timeShiftSeekTo(self, positionMs: int):
|
|
pass
|
|
|
|
def timeShiftSetPlaybackParams(self, params: Any):
|
|
pass
|
|
|
|
def timeShiftEnablePositionTracking(self, enable: bool):
|
|
pass
|
|
|
|
def notifyVideoAvailable(self):
|
|
pass
|
|
|
|
def notifyVideoUnavailable(self, reason: int):
|
|
pass
|
|
|
|
def notifySessionEvent(self, eventType: str, eventArgs: Any):
|
|
pass
|
|
|
|
def notifyTracksChanged(self, tracks: List[Any]):
|
|
pass
|
|
|
|
def notifyTrackSelected(self, type_: str, trackId: str):
|
|
pass
|
|
|
|
def notifyContentAllowed(self):
|
|
pass
|
|
|
|
def notifyContentBlocked(self, rating: str):
|
|
pass
|
|
|
|
def setMain(self, main: bool):
|
|
self._main = main
|
|
|
|
def setStreamVolume(self, volume: float):
|
|
self._stream_volume = volume
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._sessions: List[TvInputService.Session] = []
|
|
|
|
def onCreateSession(self, inputId: str) -> Session:
|
|
session = TvInputService.Session()
|
|
self._sessions.append(session)
|
|
return session
|
|
|
|
def onSetupFinished(self, inputId: str):
|
|
pass
|
|
|
|
def sessionCreated(self, session: Session):
|
|
pass
|
|
|
|
def notifyHardwareFailed(self, deviceId: int):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# TvRecordingClient / TvRecordingService (stubs)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class TvRecordingClient(Stub):
|
|
"""TvRecordingClient — 电视录制客户端"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def startRecording(self, uri: str):
|
|
pass
|
|
|
|
def stopRecording(self):
|
|
pass
|
|
|
|
def pauseRecording(self):
|
|
pass
|
|
|
|
def resumeRecording(self):
|
|
pass
|
|
|
|
def release(self):
|
|
pass
|
|
|
|
|
|
class TvRecordingService(Stub):
|
|
"""TvRecordingService — 电视录制服务"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def onStartRecording(self, inputId: str, sessionId: str):
|
|
pass
|
|
|
|
def onStopRecording(self, sessionId: str):
|
|
pass
|
|
|
|
def onPauseRecording(self, sessionId: str):
|
|
pass
|
|
|
|
def onResumeRecording(self, sessionId: str):
|
|
pass
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"TvInputManager",
|
|
"TvInputInfo",
|
|
"TvInputService",
|
|
"TvRecordingClient",
|
|
"TvRecordingService",
|
|
] |