Files
Android-pyApi/android_pyapi/android/telephony_mbms.py
T
shuiyu1123 a51854455b feat: 大规模扩充至212个模块/175K行代码 — 覆盖android/java/javax/org/dalvik全包
- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等)
- java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等)
- javax/ 4个模块 (net/crypto/security/sql)
- org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http)
- dalvik/ 1个模块 (system)
- ~3053个类/接口,方法签名完全对齐Android SDK
- 桌面跨平台运行 (Windows/macOS/Linux)
- 修复所有导入错误和Python关键字冲突
2026-06-24 14:15:56 +00:00

1180 lines
44 KiB
Python

"""
Android Telephony MBMS 组件 — MbmsDownloadManager, MbmsStreamingManager, DownloadRequest, StreamingService 等
方法签名完全对齐 Android SDK (android.telephony.mbms 包)
"""
from __future__ import annotations
import os
import time
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
from .._core import Stub, AndroidOnlyError
from ..java.lang import RuntimeException
# ═══════════════════════════════════════════════════════════════
# MbmsErrors
# ═══════════════════════════════════════════════════════════════
class MbmsErrors(Stub):
"""MbmsErrors — MBMS 错误代码基类"""
SUCCESS = 0
ERROR_NO_UNIQUE_MIDDLEWARE = 1
ERROR_MIDDLEWARE_NOT_BOUND = 2
ERROR_MIDDLEWARE_LOST = 3
ERROR_MIDDLEWARE_NOT_YET_READY = 4
ERROR_OUT_OF_MEMORY = 5
ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE = 6
ERROR_MIDDLEWARE_PERMANENTLY_UNAVAILABLE = 7
ERROR_MIDDLEWARE_UNABLE_TO_CREATE_SESSION = 8
ERROR_MIDDLEWARE_UNABLE_TO_CREATE_DATA_SESSION = 9
ERROR_MIDDLEWARE_UNABLE_TO_CREATE_DOWNLOAD = 10
ERROR_MIDDLEWARE_UNABLE_TO_CREATE_STREAMING = 11
ERROR_MIDDLEWARE_INTERNAL_ERROR = 12
ERROR_MIDDLEWARE_NOT_SUPPORTED = 13
ERROR_MIDDLEWARE_INVALID_INPUT = 14
ERROR_MIDDLEWARE_INVALID_SERVICE_ID = 15
ERROR_MIDDLEWARE_INVALID_FILE_PATH = 16
ERROR_MIDDLEWARE_DUPLICATE_SERVICE = 17
ERROR_MIDDLEWARE_SERVICE_NOT_FOUND = 18
ERROR_MIDDLEWARE_SERVICE_ALREADY_RUNNING = 19
ERROR_MIDDLEWARE_SERVICE_NOT_RUNNING = 20
ERROR_MIDDLEWARE_INVALID_SAI = 21
ERROR_MIDDLEWARE_INVALID_CELL_ID = 22
ERROR_MIDDLEWARE_UNABLE_TO_FETCH_PREFIX = 23
ERROR_MIDDLEWARE_TEMP_FILE_EXPIRED = 24
ERROR_MIDDLEWARE_FILE_ALREADY_COMPLETE = 25
ERROR_MIDDLEWARE_FILE_ALREADY_IN_PROGRESS = 26
ERROR_MIDDLEWARE_STALE_SERVICE_ANNOUNCEMENT = 27
ERROR_MIDDLEWARE_MISSING_FILE_INFO = 28
ERROR_MIDDLEWARE_NO_EXPIRATION = 29
ERROR_MIDDLEWARE_UNKNOWN_FILE_INFO = 30
ERROR_MIDDLEWARE_UNKNOWN_SIGNAL = 31
ERROR_MIDDLEWARE_INSUFFICIENT_STORAGE = 32
ERROR_MIDDLEWARE_INSUFFICIENT_MEMORY = 33
ERROR_MIDDLEWARE_UNABLE_TO_CLOSE_FILE = 34
ERROR_MIDDLEWARE_UNABLE_TO_OPEN_FILE = 35
ERROR_MIDDLEWARE_IO_ERROR = 36
ERROR_MIDDLEWARE_CONCURRENT_SERVICE_LIMIT = 37
ERROR_MIDDLEWARE_INVALID_DOWNLOAD_ID = 38
class InitializationErrors(Stub):
"""MbmsErrors.InitializationErrors — 初始化错误"""
ERROR_DUPLICATE_INITIALIZE = 101
ERROR_APP_PERMISSIONS_NOT_GRANTED = 102
ERROR_UNABLE_TO_INITIALIZE = 103
ERROR_INTERNAL = 104
ERROR_MIDDLEWARE_NOT_BOUND = 105
class DownloadErrors(Stub):
"""MbmsErrors.DownloadErrors — 下载错误"""
ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 201
ERROR_UNKNOWN_DOWNLOAD_REQUEST = 202
ERROR_DOWNLOAD_NOT_FOUND = 203
ERROR_DOWNLOAD_ALREADY_EXISTS = 204
ERROR_DOWNLOAD_INACTIVE = 205
ERROR_FILE_UNAVAILABLE = 206
ERROR_SERVICE_ID_NOT_DOWNLOAD = 207
ERROR_MALFORMED_FILE_URI = 208
ERROR_STALE_FILE_INFO = 209
ERROR_TEMP_FILE_ROOT_NOT_SET = 210
ERROR_UNKNOWN_FILE_INFO = 211
ERROR_NO_DOWNLOAD_FOR_FILE = 212
class StreamingErrors(Stub):
"""MbmsErrors.StreamingErrors — 流错误"""
ERROR_STREAMING_NOT_ALLOWED = 301
ERROR_STREAMING_SERVICE_NOT_STARTED = 302
ERROR_STREAMING_SERVICE_ALREADY_STARTED = 303
ERROR_STREAMING_SERVICE_NOT_VISIBLE = 304
ERROR_STREAMING_MALFORMED_SERVICE_ANNOUNCEMENT = 305
ERROR_STREAMING_DUPLICATE_SERVICE_ANNOUNCEMENT = 306
ERROR_STREAMING_SERVICE_ANNOUNCEMENT_EXPIRED = 307
ERROR_STREAMING_RADIO_RESOURCE_REJECTED = 308
ERROR_STREAMING_RADIO_RESOURCE_NOT_AVAILABLE = 309
ERROR_STREAMING_INVALID_SAI_LIST = 310
ERROR_STREAMING_UNABLE_TO_UPDATE_SUBFLOW = 311
class NameTypeErrors(Stub):
"""MbmsErrors.NameTypeErrors — 名称类型错误"""
ERROR_NAME_SYSTEM_ERROR = 401
ERROR_NAME_INVALID_FORMAT = 402
ERROR_NAME_UNSUPPORTED_CHARACTER_ENCODING = 403
ERROR_NAME_CONTAINS_INVALID_CHARACTERS = 404
class GeneralErrors(Stub):
"""MbmsErrors.GeneralErrors — 通用错误"""
ERROR_MIDDLEWARE_NOT_BOUND = 501
ERROR_OUT_OF_MEMORY = 502
ERROR_MIDDLEWARE_LOST = 503
ERROR_MIDDLEWARE_NOT_YET_READY = 504
ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE = 505
ERROR_MIDDLEWARE_UNABLE_TO_CREATE_SESSION = 506
# ═══════════════════════════════════════════════════════════════
# DownloadRequest
# ═══════════════════════════════════════════════════════════════
class DownloadRequest(Stub):
"""DownloadRequest — MBMS 下载请求"""
# 下载请求常量
DOWNLOAD_RESULT_SUCCESS = 0
DOWNLOAD_RESULT_ERROR = 1
DOWNLOAD_RESULT_ERROR_MEDIA_NOT_FOUND = 2
DOWNLOAD_RESULT_ERROR_MEDIA_UNAVAILABLE = 3
DOWNLOAD_RESULT_ERROR_MEDIA_FAILED = 4
DOWNLOAD_RESULT_ERROR_SERVICE_UNAVAILABLE = 5
DOWNLOAD_RESULT_ERROR_INSUFFICIENT_STORAGE = 6
DOWNLOAD_RESULT_ERROR_IO_ERROR = 7
DOWNLOAD_RESULT_ERROR_FILE_NOT_FOUND = 8
DOWNLOAD_RESULT_ERROR_OUT_OF_MEMORY = 9
DOWNLOAD_RESULT_ERROR_RADIO_OFF = 10
DOWNLOAD_RESULT_ERROR_INTERRUPTED = 11
DOWNLOAD_RESULT_ERROR_TIMEOUT = 12
DOWNLOAD_RESULT_ERROR_CANCELLED = 13
DOWNLOAD_RESULT_ERROR_DOWNLOAD_NOT_STARTED = 14
# 下载状态
DOWNLOAD_STATUS_INACTIVE = 0
DOWNLOAD_STATUS_ACTIVE = 1
DOWNLOAD_STATUS_PENDING = 2
DOWNLOAD_STATUS_PAUSED = 3
DOWNLOAD_STATUS_COMPLETED = 4
DOWNLOAD_STATUS_CANCELED = 5
DOWNLOAD_STATUS_FAILED = 6
def __init__(self, service_id: str = "", file_uri: str = "",
source: Any = None, destination: Any = None,
app_intent: Any = None):
super().__init__()
self._service_id = service_id
self._file_uri = file_uri
self._source = source
self._destination = destination
self._app_intent = app_intent
self._subscription_id: int = 0
self._sai: List[int] = []
self._app_name: str = ""
self._app_version: str = ""
self._storage_type: int = 0
self._hash: str = ""
self._request_id: int = 0
def getServiceId(self) -> str:
return self._service_id
def getFileUri(self) -> str:
return self._file_uri
def getSource(self) -> Any:
return self._source
def getDestination(self) -> Any:
return self._destination
def getIntent(self) -> Any:
return self._app_intent
def getSubscriptionId(self) -> int:
return self._subscription_id
def setSubscriptionId(self, sub_id: int):
self._subscription_id = sub_id
def getSai(self) -> List[int]:
return list(self._sai)
def setSai(self, sai: List[int]):
self._sai = list(sai)
def getAppName(self) -> str:
return self._app_name
def setAppName(self, name: str):
self._app_name = name
def getAppVersion(self) -> str:
return self._app_version
def setAppVersion(self, version: str):
self._app_version = version
def getStorageType(self) -> int:
return self._storage_type
def setStorageType(self, storage_type: int):
self._storage_type = storage_type
def getHash(self) -> str:
return self._hash
def getRequestId(self) -> int:
return self._request_id
def setRequestId(self, request_id: int):
self._request_id = request_id
def toString(self) -> str:
return f"DownloadRequest(serviceId={self._service_id}, fileUri={self._file_uri})"
class Builder(Stub):
"""DownloadRequest.Builder — 下载请求构建器"""
def __init__(self, service_id: str, file_uri: str):
super().__init__()
self._service_id = service_id
self._file_uri = file_uri
self._source: Any = None
self._destination: Any = None
self._app_intent: Any = None
self._subscription_id: int = 0
self._sai: List[int] = []
self._app_name: str = ""
self._app_version: str = ""
self._storage_type: int = 0
def setServiceId(self, service_id: str) -> DownloadRequest.Builder:
self._service_id = service_id
return self
def setFileUri(self, file_uri: str) -> DownloadRequest.Builder:
self._file_uri = file_uri
return self
def setSource(self, source: Any) -> DownloadRequest.Builder:
self._source = source
return self
def setDestination(self, destination: Any) -> DownloadRequest.Builder:
self._destination = destination
return self
def setIntent(self, intent: Any) -> DownloadRequest.Builder:
self._app_intent = intent
return self
def setSubscriptionId(self, sub_id: int) -> DownloadRequest.Builder:
self._subscription_id = sub_id
return self
def setSai(self, sai: List[int]) -> DownloadRequest.Builder:
self._sai = list(sai)
return self
def setAppName(self, name: str) -> DownloadRequest.Builder:
self._app_name = name
return self
def setAppVersion(self, version: str) -> DownloadRequest.Builder:
self._app_version = version
return self
def setStorageType(self, storage_type: int) -> DownloadRequest.Builder:
self._storage_type = storage_type
return self
def build(self) -> DownloadRequest:
req = DownloadRequest(self._service_id, self._file_uri,
self._source, self._destination,
self._app_intent)
req.setSubscriptionId(self._subscription_id)
req.setSai(self._sai)
req.setAppName(self._app_name)
req.setAppVersion(self._app_version)
req.setStorageType(self._storage_type)
return req
# ═══════════════════════════════════════════════════════════════
# FileInfo
# ═══════════════════════════════════════════════════════════════
class FileInfo(Stub):
"""FileInfo — MBMS 文件信息"""
def __init__(self, uri: str = "", mime_type: str = "",
file_size: int = 0, name: str = ""):
super().__init__()
self._uri = uri
self._mime_type = mime_type
self._file_size = file_size
self._name = name
def getUri(self) -> str:
return self._uri
def getMimeType(self) -> str:
return self._mime_type
def getFileSize(self) -> int:
return self._file_size
def getName(self) -> str:
return self._name
def toString(self) -> str:
return f"FileInfo(uri={self._uri}, mimeType={self._mime_type}, size={self._file_size})"
# ═══════════════════════════════════════════════════════════════
# DownloadStatusListener
# ═══════════════════════════════════════════════════════════════
class DownloadStatusListener(Stub):
"""DownloadStatusListener — MBMS 下载状态监听器"""
def onStatusChanged(self, request: DownloadRequest, info: FileInfo, status: int):
"""下载状态改变回调"""
pass
# ═══════════════════════════════════════════════════════════════
# FileServiceInfo
# ═══════════════════════════════════════════════════════════════
class FileServiceInfo(Stub):
"""FileServiceInfo — MBMS 文件服务信息"""
def __init__(self, service_id: str = "", service_class: str = "",
service_announcement: Any = None):
super().__init__()
self._service_id = service_id
self._service_class = service_class
self._service_announcement = service_announcement
self._sais: List[int] = []
self._cells: List[int] = []
self._files: List[FileInfo] = []
def getServiceId(self) -> str:
return self._service_id
def getServiceClass(self) -> str:
return self._service_class
def getServiceAnnouncement(self) -> Any:
return self._service_announcement
def getSai(self) -> List[int]:
return list(self._sais)
def getCells(self) -> List[int]:
return list(self._cells)
def getFiles(self) -> List[FileInfo]:
return list(self._files)
def toString(self) -> str:
return f"FileServiceInfo(serviceId={self._service_id}, class={self._service_class})"
# ═══════════════════════════════════════════════════════════════
# StreamingService
# ═══════════════════════════════════════════════════════════════
class StreamingService(Stub):
"""StreamingService — MBMS 流媒体服务"""
# 流媒体服务状态
STATE_STOPPED = 0
STATE_STARTED = 1
STATE_STALLED = 2
STATE_PENDING = 3
STATE_ERROR = 4
# 流媒体服务广播标志
BROADCAST_METHOD_UNICAST = 0
BROADCAST_METHOD_MULTICAST = 1
BROADCAST_METHOD_BROADCAST = 2
# 流媒体服务信息
STREAMING_SERVICE_STATE_STOPPED = 0
STREAMING_SERVICE_STATE_STARTED = 1
STREAMING_SERVICE_STATE_STALLED = 2
STREAMING_SERVICE_STATE_PENDING = 3
STREAMING_SERVICE_STATE_ERROR = 4
REASON_NONE = 0
REASON_BY_USER_REQUEST = 1
REASON_BY_MIDDLEWARE = 2
REASON_BY_RADIO_RESOURCE = 3
REASON_BY_OUT_OF_MEMORY = 4
REASON_BY_SIGNAL_LOST = 5
REASON_BY_TEMPORARILY_UNAVAILABLE = 6
REASON_BY_PERMANENTLY_UNAVAILABLE = 7
REASON_BY_SERVICE_SHUTDOWN = 8
REASON_BY_SERVICE_NOT_VISIBLE = 9
REASON_BY_RADIO_NOT_AVAILABLE = 10
def __init__(self, service_id: str = "", service_class: str = ""):
super().__init__()
self._service_id = service_id
self._service_class = service_class
self._state = StreamingService.STATE_STOPPED
self._broadcast_method = StreamingService.BROADCAST_METHOD_MULTICAST
self._callback: Optional[StreamingServiceCallback] = None
self._audio_description: Any = None
self._video_description: Any = None
self._subtitle_descriptions: List[Any] = []
self._estimated_bitrate: int = 0
def getServiceId(self) -> str:
return self._service_id
def getServiceClass(self) -> str:
return self._service_class
def getState(self) -> int:
return self._state
def setState(self, state: int):
self._state = state
def getBroadcastMethod(self) -> int:
return self._broadcast_method
def setBroadcastMethod(self, method: int):
self._broadcast_method = method
def getAudioDescription(self) -> Any:
return self._audio_description
def setAudioDescription(self, desc: Any):
self._audio_description = desc
def getVideoDescription(self) -> Any:
return self._video_description
def setVideoDescription(self, desc: Any):
self._video_description = desc
def getSubtitleDescriptions(self) -> List[Any]:
return list(self._subtitle_descriptions)
def setSubtitleDescriptions(self, descs: List[Any]):
self._subtitle_descriptions = list(descs)
def getEstimatedBitrate(self) -> int:
return self._estimated_bitrate
def setEstimatedBitrate(self, bitrate: int):
self._estimated_bitrate = bitrate
def setCallback(self, callback: StreamingServiceCallback):
self._callback = callback
def getCallback(self) -> Optional[StreamingServiceCallback]:
return self._callback
def start(self):
"""启动流媒体服务"""
self._state = StreamingService.STATE_STARTED
if self._callback:
self._callback.onStreamStateUpdated(self._state,
StreamingService.REASON_BY_USER_REQUEST)
def stop(self):
"""停止流媒体服务"""
self._state = StreamingService.STATE_STOPPED
if self._callback:
self._callback.onStreamStateUpdated(self._state,
StreamingService.REASON_BY_USER_REQUEST)
def close(self):
"""关闭流媒体服务"""
self._state = StreamingService.STATE_STOPPED
self._callback = None
def toString(self) -> str:
return f"StreamingService(serviceId={self._service_id}, state={self._state})"
# ═══════════════════════════════════════════════════════════════
# StreamingServiceCallback
# ═══════════════════════════════════════════════════════════════
class StreamingServiceCallback(Stub):
"""StreamingServiceCallback — MBMS 流媒体服务回调"""
SIGNAL_STRENGTH_UNKNOWN = 0
SIGNAL_STRENGTH_POOR = 1
SIGNAL_STRENGTH_MODERATE = 2
SIGNAL_STRENGTH_GOOD = 3
SIGNAL_STRENGTH_GREAT = 4
def onStreamStateUpdated(self, state: int, reason: int):
"""流状态更新回调"""
pass
def onMediaDescriptionUpdated(self):
"""媒体描述更新回调"""
pass
def onBroadcastSignalStrengthUpdated(self, signal_strength: int):
"""广播信号强度更新回调"""
pass
def onStreamMethodUpdated(self, broadcast_method: int):
"""流方法更新回调"""
pass
def onError(self, error_code: int, message: str = ""):
"""错误回调"""
pass
# ═══════════════════════════════════════════════════════════════
# DownloadProgressListener
# ═══════════════════════════════════════════════════════════════
class DownloadProgressListener(Stub):
"""DownloadProgressListener — MBMS 下载进度监听器"""
def onProgressUpdated(self, request: DownloadRequest, info: FileInfo,
current_bytes: int, total_bytes: int, current_files: int,
total_files: int):
"""下载进度更新回调"""
pass
# ═══════════════════════════════════════════════════════════════
# DownloadRequestListener
# ═══════════════════════════════════════════════════════════════
class DownloadRequestListener(Stub):
"""DownloadRequestListener — MBMS 下载请求监听器"""
def onProgressUpdated(self, request: DownloadRequest, info: FileInfo,
current_bytes: int, total_bytes: int, current_files: int,
total_files: int):
pass
def onDownloadStateChanged(self, request: DownloadRequest, state: int):
pass
# ═══════════════════════════════════════════════════════════════
# MbmsDownloadSession (pre-API 30)
# ═══════════════════════════════════════════════════════════════
class MbmsDownloadSession(Stub):
"""MbmsDownloadSession — MBMS 下载会话 (旧版 API)"""
EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.mbms.extra.MBMS_DOWNLOAD_RESULT"
EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.mbms.extra.MBMS_DOWNLOAD_REQUEST"
EXTRA_MBMS_FILE_INFO = "android.telephony.mbms.extra.MBMS_FILE_INFO"
EXTRA_MBMS_COMPLETED_FILES = "android.telephony.mbms.extra.MBMS_COMPLETED_FILES"
RESULT_SUCCESSFUL_DOWNLOAD = 0
RESULT_EXPIRED_CHARGES = 1
RESULT_FILE_UNAVAILABLE = 2
RESULT_IO_ERROR = 3
RESULT_OUT_OF_STORAGE = 4
RESULT_SERVICE_NOT_DOWNLOAD = 5
RESULT_DOWNLOAD_NOT_STARTED = 6
RESULT_FILE_NOT_FOUND = 7
RESULT_FILE_IN_PROGRESS = 8
RESULT_FILE_ALREADY_DOWNLOADED = 9
RESULT_MALFORMED_URI = 10
RESULT_CANCELLED = 11
RESULT_INTERRUPTED = 12
RESULT_TIMEOUT = 13
RESULT_SERVICE_UNAVAILABLE = 14
RESULT_MEDIA_NOT_FOUND = 15
RESULT_MEDIA_FAILED = 16
RESULT_ERROR_RADIO_OFF = 17
RESULT_ERROR_OUT_OF_MEMORY = 18
_instance_map: Dict[int, MbmsDownloadSession] = {}
def __init__(self, context: Any = None, subscription_id: int = 0,
callback: Any = None):
super().__init__()
self._context = context
self._subscription_id = subscription_id
self._callback = callback
self._middleware_bound = False
self._download_requests: Dict[int, DownloadRequest] = {}
self._file_services: Dict[str, FileServiceInfo] = {}
self._temp_root: str = ""
@staticmethod
def create(context: Any, callback: Any,
subscription_id: int = 0) -> MbmsDownloadSession:
session = MbmsDownloadSession(context, subscription_id, callback)
MbmsDownloadSession._instance_map[subscription_id] = session
return session
def requestUpdate(self, file_service_list: List[FileServiceInfo]):
"""请求更新文件服务列表"""
pass
def download(self, request: DownloadRequest):
"""开始下载"""
request_id = int(time.time() * 1000)
request.setRequestId(request_id)
self._download_requests[request_id] = request
def cancelDownload(self, download_request: DownloadRequest):
"""取消下载"""
rid = download_request.getRequestId()
if rid in self._download_requests:
del self._download_requests[rid]
def getCurrentPendingDownloadRequests(self) -> List[DownloadRequest]:
"""获取当前待处理的下载请求"""
return list(self._download_requests.values())
def getTempFileRoot(self) -> str:
"""获取临时文件根目录"""
return self._temp_root
def setTempFileRoot(self, temp_root: str, storage_type: int):
"""设置临时文件根目录"""
self._temp_root = temp_root
def getMiddlewareVersion(self) -> int:
"""获取中间件版本"""
return 0
def getSubscriptionId(self) -> int:
return self._subscription_id
def close(self):
"""关闭会话"""
self._download_requests.clear()
self._file_services.clear()
@staticmethod
def getDownloadStatus(context: Any, subscription_id: int,
download_request: DownloadRequest) -> int:
return DownloadRequest.DOWNLOAD_STATUS_INACTIVE
def getFileServices(self) -> Dict[str, FileServiceInfo]:
return dict(self._file_services)
def getName(self) -> str:
return "MbmsDownloadSession"
def toString(self) -> str:
return f"MbmsDownloadSession(subId={self._subscription_id})"
# ═══════════════════════════════════════════════════════════════
# MbmsStreamingSession (pre-API 30)
# ═══════════════════════════════════════════════════════════════
class MbmsStreamingSession(Stub):
"""MbmsStreamingSession — MBMS 流媒体会话 (旧版 API)"""
EXTRA_MBMS_STREAMING_SERVICE = "android.telephony.mbms.extra.MBMS_STREAMING_SERVICE"
EXTRA_MBMS_STREAMING_SERVICE_INFO = "android.telephony.mbms.extra.MBMS_STREAMING_SERVICE_INFO"
_instance_map: Dict[int, MbmsStreamingSession] = {}
def __init__(self, context: Any = None, subscription_id: int = 0,
callback: Any = None):
super().__init__()
self._context = context
self._subscription_id = subscription_id
self._callback = callback
self._middleware_bound = False
self._streaming_services: Dict[str, StreamingService] = {}
@staticmethod
def create(context: Any, callback: Any,
subscription_id: int = 0) -> MbmsStreamingSession:
session = MbmsStreamingSession(context, subscription_id, callback)
MbmsStreamingSession._instance_map[subscription_id] = session
return session
def startStreaming(self, service_info: FileServiceInfo,
callback: StreamingServiceCallback) -> StreamingService:
"""开始流媒体"""
service = StreamingService(service_info.getServiceId(),
service_info.getServiceClass())
service.setCallback(callback)
self._streaming_services[service_info.getServiceId()] = service
return service
def stopStreaming(self, streaming_service: StreamingService):
"""停止流媒体"""
sid = streaming_service.getServiceId()
if sid in self._streaming_services:
streaming_service.stop()
del self._streaming_services[sid]
def requestUpdate(self, file_service_list: List[FileServiceInfo]):
"""请求更新服务列表"""
pass
def getCurrentStreamingServices(self) -> List[StreamingService]:
"""获取当前流媒体服务"""
return list(self._streaming_services.values())
def getMiddlewareVersion(self) -> int:
return 0
def getSubscriptionId(self) -> int:
return self._subscription_id
def close(self):
"""关闭会话"""
for service in self._streaming_services.values():
service.close()
self._streaming_services.clear()
def getName(self) -> str:
return "MbmsStreamingSession"
def toString(self) -> str:
return f"MbmsStreamingSession(subId={self._subscription_id})"
# ═══════════════════════════════════════════════════════════════
# MbmsDownloadManager (API 30+)
# ═══════════════════════════════════════════════════════════════
class MbmsDownloadManager(Stub):
"""MbmsDownloadManager — MBMS 下载管理器 (API 30+)"""
EXTRA_MBMS_DOWNLOAD_RESULT = "android.telephony.mbms.extra.MBMS_DOWNLOAD_RESULT"
EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.mbms.extra.MBMS_DOWNLOAD_REQUEST"
EXTRA_MBMS_FILE_INFO = "android.telephony.mbms.extra.MBMS_FILE_INFO"
EXTRA_MBMS_COMPLETED_FILES = "android.telephony.mbms.extra.MBMS_COMPLETED_FILES"
# 下载结果码
DOWNLOAD_RESULT_SUCCESS = 0
DOWNLOAD_RESULT_ERROR = 1
DOWNLOAD_RESULT_ERROR_MEDIA_NOT_FOUND = 2
DOWNLOAD_RESULT_ERROR_MEDIA_UNAVAILABLE = 3
DOWNLOAD_RESULT_ERROR_MEDIA_FAILED = 4
DOWNLOAD_RESULT_ERROR_SERVICE_UNAVAILABLE = 5
DOWNLOAD_RESULT_ERROR_INSUFFICIENT_STORAGE = 6
DOWNLOAD_RESULT_ERROR_IO_ERROR = 7
DOWNLOAD_RESULT_ERROR_FILE_NOT_FOUND = 8
DOWNLOAD_RESULT_ERROR_OUT_OF_MEMORY = 9
DOWNLOAD_RESULT_ERROR_RADIO_OFF = 10
DOWNLOAD_RESULT_ERROR_INTERRUPTED = 11
DOWNLOAD_RESULT_ERROR_TIMEOUT = 12
DOWNLOAD_RESULT_ERROR_CANCELLED = 13
DOWNLOAD_RESULT_ERROR_DOWNLOAD_NOT_STARTED = 14
def __init__(self, context: Any = None):
super().__init__()
self._context = context
self._download_requests: Dict[int, DownloadRequest] = {}
self._file_services: Dict[str, FileServiceInfo] = {}
self._listeners: List[DownloadStatusListener] = []
self._progress_listeners: List[DownloadProgressListener] = []
@staticmethod
def getService(context: Any, sub_id: int = 0) -> Optional[MbmsDownloadManager]:
return MbmsDownloadManager(context)
def addDownloadRequest(self, download_request: DownloadRequest):
"""添加下载请求"""
request_id = len(self._download_requests) + 1
download_request.setRequestId(request_id)
self._download_requests[request_id] = download_request
def removeDownloadRequest(self, download_request: DownloadRequest):
"""移除下载请求"""
rid = download_request.getRequestId()
self._download_requests.pop(rid, None)
def getCurrentDownloadRequests(self) -> List[DownloadRequest]:
"""获取当前所有下载请求"""
return list(self._download_requests.values())
def getPendingDownloadRequests(self) -> List[DownloadRequest]:
"""获取待处理的下载请求"""
return [r for r in self._download_requests.values()
if r.getHash() == ""]
def getCompletedDownloadRequests(self) -> List[DownloadRequest]:
"""获取已完成的下载请求"""
return [r for r in self._download_requests.values()
if r.getHash() != ""]
def addStatusListener(self, listener: DownloadStatusListener):
"""添加状态监听器"""
if listener not in self._listeners:
self._listeners.append(listener)
def removeStatusListener(self, listener: DownloadStatusListener):
"""移除状态监听器"""
self._listeners = [l for l in self._listeners if l is not listener]
def addProgressListener(self, listener: DownloadProgressListener):
"""添加进度监听器"""
if listener not in self._progress_listeners:
self._progress_listeners.append(listener)
def removeProgressListener(self, listener: DownloadProgressListener):
"""移除进度监听器"""
self._progress_listeners = [l for l in self._progress_listeners
if l is not listener]
def getMaxDownloadRequests(self) -> int:
"""获取最大下载请求数"""
return 100
def getFileServices(self) -> Dict[str, FileServiceInfo]:
return dict(self._file_services)
def setTempFileRoot(self, temp_root: str, storage_type: int):
"""设置临时文件根目录"""
pass
def getTempFileRoot(self) -> str:
return ""
def getMiddlewareVersion(self) -> int:
return 0
def close(self):
"""关闭下载管理器"""
self._download_requests.clear()
self._listeners.clear()
self._progress_listeners.clear()
def toString(self) -> str:
return f"MbmsDownloadManager(requests={len(self._download_requests)})"
# ═══════════════════════════════════════════════════════════════
# MbmsStreamingManager (API 30+)
# ═══════════════════════════════════════════════════════════════
class MbmsStreamingManager(Stub):
"""MbmsStreamingManager — MBMS 流媒体管理器 (API 30+)"""
EXTRA_MBMS_STREAMING_SERVICE_INFO = "android.telephony.mbms.extra.MBMS_STREAMING_SERVICE_INFO"
STREAMING_SERVICE_STATE_STOPPED = 0
STREAMING_SERVICE_STATE_STARTED = 1
STREAMING_SERVICE_STATE_STALLED = 2
STREAMING_SERVICE_STATE_PENDING = 3
STREAMING_SERVICE_STATE_ERROR = 4
BROADCAST_METHOD_UNICAST = 0
BROADCAST_METHOD_MULTICAST = 1
BROADCAST_METHOD_BROADCAST = 2
REASON_BY_USER_REQUEST = 1
REASON_BY_MIDDLEWARE = 2
REASON_BY_RADIO_RESOURCE = 3
REASON_BY_OUT_OF_MEMORY = 4
REASON_BY_SIGNAL_LOST = 5
REASON_BY_TEMPORARILY_UNAVAILABLE = 6
REASON_BY_PERMANENTLY_UNAVAILABLE = 7
REASON_BY_SERVICE_SHUTDOWN = 8
REASON_BY_SERVICE_NOT_VISIBLE = 9
REASON_BY_RADIO_NOT_AVAILABLE = 10
def __init__(self, context: Any = None):
super().__init__()
self._context = context
self._streaming_services: Dict[str, StreamingService] = {}
self._service_info_map: Dict[str, FileServiceInfo] = {}
@staticmethod
def getService(context: Any, sub_id: int = 0) -> Optional[MbmsStreamingManager]:
return MbmsStreamingManager(context)
def startStreaming(self, service_info: FileServiceInfo,
callback: StreamingServiceCallback) -> StreamingService:
"""启动流媒体服务"""
service = StreamingService(service_info.getServiceId(),
service_info.getServiceClass())
service.setCallback(callback)
self._streaming_services[service_info.getServiceId()] = service
self._service_info_map[service_info.getServiceId()] = service_info
return service
def stopStreaming(self, streaming_service: StreamingService):
"""停止流媒体服务"""
sid = streaming_service.getServiceId()
if sid in self._streaming_services:
streaming_service.stop()
del self._streaming_services[sid]
def getCurrentStreamingServices(self) -> List[StreamingService]:
return list(self._streaming_services.values())
def getServiceInfoForStreamingService(self, service: StreamingService) -> Optional[FileServiceInfo]:
return self._service_info_map.get(service.getServiceId())
def getMaxStreamingServices(self) -> int:
return 10
def getMiddlewareVersion(self) -> int:
return 0
def close(self):
"""关闭流媒体管理器"""
for service in self._streaming_services.values():
service.close()
self._streaming_services.clear()
self._service_info_map.clear()
def toString(self) -> str:
return f"MbmsStreamingManager(services={len(self._streaming_services)})"
# ═══════════════════════════════════════════════════════════════
# MbmsUtils
# ═══════════════════════════════════════════════════════════════
class MbmsUtils(Stub):
"""MbmsUtils — MBMS 工具类"""
@staticmethod
def getCellBroadcastServiceInfo(context: Any,
service_id: str,
subscription_id: int) -> Optional[FileServiceInfo]:
"""获取小区广播服务信息"""
return None
@staticmethod
def isFileService(service_announcement: Any) -> bool:
"""判断是否为文件服务"""
return True
@staticmethod
def isStreamingService(service_announcement: Any) -> bool:
"""判断是否为流媒体服务"""
return True
@staticmethod
def getServiceClassFromServiceAnnouncement(service_announcement: Any) -> Optional[str]:
"""从服务公告中获取服务类"""
return None
@staticmethod
def getServiceIdFromServiceAnnouncement(service_announcement: Any) -> Optional[str]:
"""从服务公告中获取服务 ID"""
return None
@staticmethod
def getFileInfoFromFileService(service_info: FileServiceInfo) -> List[FileInfo]:
"""从文件服务信息中获取文件信息列表"""
return service_info.getFiles()
@staticmethod
def createDownloadRequest(service_id: str, file_uri: str,
source: Any, destination: Any) -> DownloadRequest:
"""创建下载请求"""
return DownloadRequest(service_id, file_uri, source, destination)
# ═══════════════════════════════════════════════════════════════
# MbmsGroupCallService
# ═══════════════════════════════════════════════════════════════
class MbmsGroupCallService(Stub):
"""MbmsGroupCallService — MBMS 组呼服务"""
REASON_BY_USER_REQUEST = 1
REASON_BY_MIDDLEWARE = 2
REASON_BY_RADIO_RESOURCE = 3
REASON_BY_OUT_OF_MEMORY = 4
REASON_BY_SIGNAL_LOST = 5
REASON_BY_TEMPORARILY_UNAVAILABLE = 6
REASON_BY_PERMANENTLY_UNAVAILABLE = 7
REASON_BY_SERVICE_SHUTDOWN = 8
REASON_BY_SERVICE_NOT_VISIBLE = 9
REASON_BY_RADIO_NOT_AVAILABLE = 10
STATE_STOPPED = 0
STATE_STARTED = 1
STATE_STALLED = 2
STATE_PENDING = 3
STATE_ERROR = 4
def __init__(self, context: Any = None):
super().__init__()
self._context = context
self._group_calls: Dict[str, Any] = {}
@staticmethod
def getService(context: Any, sub_id: int = 0) -> Optional[MbmsGroupCallService]:
return MbmsGroupCallService(context)
def startGroupCall(self, service_id: str, sai_list: List[int],
frequency: int, tmgi: Any, callback: Any):
"""启动组呼"""
pass
def stopGroupCall(self, service_id: str):
"""停止组呼"""
self._group_calls.pop(service_id, None)
def getCurrentGroupCalls(self) -> List[Any]:
return list(self._group_calls.values())
def close(self):
self._group_calls.clear()
def toString(self) -> str:
return f"MbmsGroupCallService(calls={len(self._group_calls)})"
# ═══════════════════════════════════════════════════════════════
# MbmsDownloadSessionCallback
# ═══════════════════════════════════════════════════════════════
class MbmsDownloadSessionCallback(Stub):
"""MbmsDownloadSessionCallback — MBMS 下载会话回调"""
def onError(self, error_code: int, message: str = ""):
pass
def onFileServicesUpdated(self, services: List[FileServiceInfo]):
pass
def onMiddlewareReady(self):
pass
# ═══════════════════════════════════════════════════════════════
# MbmsStreamingSessionCallback
# ═══════════════════════════════════════════════════════════════
class MbmsStreamingSessionCallback(Stub):
"""MbmsStreamingSessionCallback — MBMS 流媒体会话回调"""
def onError(self, error_code: int, message: str = ""):
pass
def onStreamingServicesUpdated(self, services: List[FileServiceInfo]):
pass
def onMiddlewareReady(self):
pass
# ═══════════════════════════════════════════════════════════════
# ServiceAnnouncement
# ═══════════════════════════════════════════════════════════════
class ServiceAnnouncement(Stub):
"""ServiceAnnouncement — MBMS 服务公告"""
def __init__(self, service_id: str = "", service_class: str = "",
announcement_data: bytes = b""):
super().__init__()
self._service_id = service_id
self._service_class = service_class
self._announcement_data = announcement_data
self._sais: List[int] = []
self._cells: List[int] = []
self._expiry_time: int = 0
def getServiceId(self) -> str:
return self._service_id
def getServiceClass(self) -> str:
return self._service_class
def getAnnouncementData(self) -> bytes:
return self._announcement_data
def getSais(self) -> List[int]:
return list(self._sais)
def setSais(self, sais: List[int]):
self._sais = list(sais)
def getCells(self) -> List[int]:
return list(self._cells)
def setCells(self, cells: List[int]):
self._cells = list(cells)
def getExpiryTime(self) -> int:
return self._expiry_time
def setExpiryTime(self, expiry: int):
self._expiry_time = expiry
def toString(self) -> str:
return f"ServiceAnnouncement(serviceId={self._service_id})"
# ═══════════════════════════════════════════════════════════════
# InternalDownloadSession (helper)
# ═══════════════════════════════════════════════════════════════
class InternalDownloadSession(Stub):
"""InternalDownloadSession — 内部下载会话辅助类"""
def __init__(self):
super().__init__()
self._session_id: int = 0
self._active: bool = False
self._downloads: Dict[int, DownloadRequest] = {}
def getSessionId(self) -> int:
return self._session_id
def setSessionId(self, session_id: int):
self._session_id = session_id
def isActive(self) -> bool:
return self._active
def setActive(self, active: bool):
self._active = active
def addDownload(self, request: DownloadRequest):
self._downloads[request.getRequestId()] = request
def removeDownload(self, request_id: int):
self._downloads.pop(request_id, None)
def getDownloads(self) -> List[DownloadRequest]:
return list(self._downloads.values())
def clear(self):
self._downloads.clear()
self._active = False
def toString(self) -> str:
return f"InternalDownloadSession(id={self._session_id}, active={self._active})"
# ═══════════════════════════════════════════════════════════════
# MbmsResourceUtils
# ═══════════════════════════════════════════════════════════════
class MbmsResourceUtils(Stub):
"""MbmsResourceUtils — MBMS 资源工具"""
@staticmethod
def getServiceIdList(services: List[FileServiceInfo]) -> List[str]:
return [s.getServiceId() for s in services]
@staticmethod
def getServiceNameList(services: List[FileServiceInfo]) -> List[str]:
return [s.getServiceClass() for s in services]
@staticmethod
def findServiceById(services: List[FileServiceInfo],
service_id: str) -> Optional[FileServiceInfo]:
for s in services:
if s.getServiceId() == service_id:
return s
return None
@staticmethod
def mergeServiceLists(a: List[FileServiceInfo],
b: List[FileServiceInfo]) -> List[FileServiceInfo]:
merged = {s.getServiceId(): s for s in a}
for s in b:
merged[s.getServiceId()] = s
return list(merged.values())