Files
Android-pyApi/android_pyapi/android/drm.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

1090 lines
37 KiB
Python

"""
Android DRM 组件 — DrmManager, DrmStore, DrmInfo, DrmManagerClient, DrmOutputStream 等
方法签名完全对齐 Android SDK (android.drm 包)
"""
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
# ═══════════════════════════════════════════════════════════════
# DrmStore
# ═══════════════════════════════════════════════════════════════
class DrmStore(Stub):
"""DrmStore — DRM 存储常量"""
# ═══════════════════════════════════════════════════
# DrmStore.Action
# ═══════════════════════════════════════════════════
class Action(Stub):
"""DrmStore.Action — DRM 操作类型"""
PLAY = 1
RINGTONE = 2
TRANSFER = 3
OUTPUT = 4
PREVIEW = 5
EXECUTE = 6
DISPLAY = 7
PRINT = 8
WALLPAPER = 9
RINGTONEOUTGOING = 10
RINGTONECALL = 11
RINGTONESILENT = 12
RINGTONESILENTCALL = 13
RINGTONESILENTOUTGOING = 14
RINGTONESILENTALARM = 15
ALARM = 16
NOTIFICATION = 17
CALENDAR = 18
CLOCK = 19
MAX = 20
@staticmethod
def toString(action: int) -> str:
names = {
DrmStore.Action.PLAY: "PLAY",
DrmStore.Action.RINGTONE: "RINGTONE",
DrmStore.Action.TRANSFER: "TRANSFER",
DrmStore.Action.OUTPUT: "OUTPUT",
DrmStore.Action.PREVIEW: "PREVIEW",
DrmStore.Action.EXECUTE: "EXECUTE",
DrmStore.Action.DISPLAY: "DISPLAY",
DrmStore.Action.PRINT: "PRINT",
DrmStore.Action.WALLPAPER: "WALLPAPER",
DrmStore.Action.ALARM: "ALARM",
DrmStore.Action.NOTIFICATION: "NOTIFICATION",
}
return names.get(action, f"UNKNOWN({action})")
class ActionConstant(Stub):
PLAY = 1
RINGTONE = 2
TRANSFER = 3
OUTPUT = 4
PREVIEW = 5
EXECUTE = 6
DISPLAY = 7
PRINT = 8
WALLPAPER = 9
ALARM = 10
NOTIFICATION = 11
class ActionDescription(Stub):
PLAY_DESCRIPTION = "play"
RINGTONE_DESCRIPTION = "ringtone"
TRANSFER_DESCRIPTION = "transfer"
OUTPUT_DESCRIPTION = "output"
PREVIEW_DESCRIPTION = "preview"
EXECUTE_DESCRIPTION = "execute"
DISPLAY_DESCRIPTION = "display"
PRINT_DESCRIPTION = "print"
WALLPAPER_DESCRIPTION = "wallpaper"
ALARM_DESCRIPTION = "alarm"
NOTIFICATION_DESCRIPTION = "notification"
# ═══════════════════════════════════════════════════
# DrmStore.ConstraintsColumns
# ═══════════════════════════════════════════════════
class ConstraintsColumns(Stub):
"""DrmStore.ConstraintsColumns — DRM 约束列"""
MAX_REPEAT_COUNT = "max_repeat_count"
REMAINING_REPEAT_COUNT = "remaining_repeat_count"
LICENSE_START_TIME = "license_start_time"
LICENSE_EXPIRY_TIME = "license_expiry_time"
AVAILABLE_PERIOD = "available_period"
EXTENDED_METADATA = "extended_metadata"
LICENSE_AVAILABLE_TIME = "license_available_time"
LICENSE_AVAILABLE_PERIOD = "license_available_period"
LICENSE_USE_COUNT = "license_use_count"
LICENSE_USE_LIMIT = "license_use_limit"
LICENSE_RIGHTS = "license_rights"
LICENSE_RIGHTS_INFO = "license_rights_info"
LICENSE_CATEGORY = "license_category"
LICENSE_VERSION = "license_version"
# ═══════════════════════════════════════════════════
# DrmStore.DrmObjectType
# ═══════════════════════════════════════════════════
class DrmObjectType(Stub):
"""DrmStore.DrmObjectType — DRM 对象类型"""
UNKNOWN = 0
CONTENT = 1
RIGHTS_OBJECT = 2
TRIGGER_OBJECT = 3
# ═══════════════════════════════════════════════════
# DrmStore.PlaybackCtrl
# ═══════════════════════════════════════════════════
class PlaybackCtrl(Stub):
"""DrmStore.PlaybackCtrl — 播放控制"""
START = 0
STOP = 1
PAUSE = 2
RESUME = 3
# ═══════════════════════════════════════════════════
# DrmStore.RightsStatus
# ═══════════════════════════════════════════════════
class RightsStatus(Stub):
"""DrmStore.RightsStatus — 权限状态"""
RIGHTS_VALID = 0
RIGHTS_INVALID = 1
RIGHTS_EXPIRED = 2
RIGHTS_NOT_ACQUIRED = 3
RIGHTS_PROTECTED = 4
RIGHTS_UNPROTECTED = 5
RIGHTS_NOT_INSTALLED = 6
RIGHTS_INSTALLED = 7
RIGHTS_META = 8
RIGHTS_COPYRIGHT = 9
RIGHTS_COPYRIGHT_EXPIRED = 10
RIGHTS_NOT_COPYRIGHT = 11
RIGHTS_SECURE = 12
RIGHTS_NOT_SECURE = 13
RIGHTS_UNLIMITED = 14
RIGHTS_LIMITED = 15
# ═══════════════════════════════════════════════════
# DrmStore.DrmMethod
# ═══════════════════════════════════════════════════
class DrmMethod(Stub):
"""DrmStore.DrmMethod — DRM 方法"""
METHOD_UNKNOWN = 0
METHOD_FL = 1
METHOD_NONE = 2
METHOD_FLD = 3
METHOD_SD = 4
METHOD_SD_PRELOAD = 5
METHOD_SD_DOWNLOAD = 6
METHOD_FLD_FOREGROUND = 7
METHOD_FLD_BACKGROUND = 8
# ═══════════════════════════════════════════════════
# DrmStore.DrmStatus
# ═══════════════════════════════════════════════════
class DrmStatus(Stub):
"""DrmStore.DrmStatus — DRM 状态"""
STATUS_OK = 0
STATUS_ERROR = 1
STATUS_WAITING = 2
STATUS_CANCELLED = 3
STATUS_REJECTED = 4
STATUS_NOT_SUPPORTED = 5
STATUS_NO_RIGHTS = 6
STATUS_NO_PERMISSION = 7
STATUS_PENDING = 8
STATUS_PROCESSING = 9
STATUS_COMPLETED = 10
STATUS_FAILED = 11
STATUS_INTERRUPTED = 12
STATUS_TIMEOUT = 13
STATUS_NO_MEMORY = 14
STATUS_SERVICE_NOT_FOUND = 15
STATUS_SERVICE_NOT_AVAILABLE = 16
STATUS_INVALID_ARGUMENT = 17
STATUS_ILLEGAL_STATE = 18
STATUS_NETWORK_ERROR = 19
STATUS_STORAGE_ERROR = 20
STATUS_SECURITY_ERROR = 21
STATUS_LICENSE_EXPIRED = 22
STATUS_LICENSE_NOT_FOUND = 23
STATUS_LICENSE_NOT_AVAILABLE = 24
DRM_METHOD_FL = 1
DRM_METHOD_NONE = 2
DRM_METHOD_UNKNOWN = 0
EXTENSION_NONE = "none"
EXTENSION_FL = ".fl"
EXTENSION_DCF = ".dcf"
EXTENSION_DM = ".dm"
EXTENSION_ODF = ".odf"
EXTENSION_SDCF = ".sdcf"
EXTENSION_FLD = ".fld"
# ═══════════════════════════════════════════════════════════════
# DrmInfo
# ═══════════════════════════════════════════════════════════════
class DrmInfo(Stub):
"""DrmInfo — DRM 信息"""
def __init__(self, mime_type: str = "", data: bytes = b""):
super().__init__()
self._mime_type = mime_type
self._data = data
self._attributes: Dict[str, str] = {}
self._info_type: int = 0
self._content_type: str = ""
self._content_uri: str = ""
self._content_data: bytes = b""
self._is_valid: bool = True
self._metadata: Dict[str, str] = {}
def getMimeType(self) -> str:
return self._mime_type
def setMimeType(self, mime_type: str):
self._mime_type = mime_type
def getData(self) -> bytes:
return self._data
def setData(self, data: bytes):
self._data = data
def get(self, key: str) -> Optional[str]:
return self._attributes.get(key)
def put(self, key: str, value: str):
self._attributes[key] = value
def getAttributes(self) -> Dict[str, str]:
return dict(self._attributes)
def getInfoType(self) -> int:
return self._info_type
def setInfoType(self, type_: int):
self._info_type = type_
def getContentType(self) -> str:
return self._content_type
def setContentType(self, type_: str):
self._content_type = type_
def getContentUri(self) -> str:
return self._content_uri
def setContentUri(self, uri: str):
self._content_uri = uri
def getContentData(self) -> bytes:
return self._content_data
def setContentData(self, data: bytes):
self._content_data = data
def isValid(self) -> bool:
return self._is_valid
def setValid(self, valid: bool):
self._is_valid = valid
def getMetadata(self) -> Dict[str, str]:
return dict(self._metadata)
def setMetadata(self, metadata: Dict[str, str]):
self._metadata = dict(metadata)
def toString(self) -> str:
return f"DrmInfo(mime={self._mime_type}, type={self._info_type})"
# ═══════════════════════════════════════════════════════════════
# DrmInfoRequest
# ═══════════════════════════════════════════════════════════════
class DrmInfoRequest(Stub):
"""DrmInfoRequest — DRM 信息请求"""
TYPE_REGISTRATION_INFO = 1
TYPE_UNREGISTRATION_INFO = 2
TYPE_RIGHTS_ACQUISITION_INFO = 3
TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4
TYPE_MERGE_INFO = 5
TYPE_REMOVE_INFO = 6
TYPE_ACCOUNT_INFO = 7
TYPE_ACCOUNT_REGISTRATION_INFO = 8
TYPE_ACCOUNT_UNREGISTRATION_INFO = 9
TYPE_ACCOUNT_UPDATE_INFO = 10
TYPE_ADAPTER_INFO = 11
TYPE_ADAPTER_CONFIG_INFO = 12
TYPE_ADAPTER_REGISTRATION_INFO = 13
TYPE_METADATA_INFO = 14
def __init__(self, info_type: int = TYPE_REGISTRATION_INFO,
mime_type: str = ""):
super().__init__()
self._info_type = info_type
self._mime_type = mime_type
self._attributes: Dict[str, str] = {}
def getInfoType(self) -> int:
return self._info_type
def getMimeType(self) -> str:
return self._mime_type
def get(self, key: str) -> Optional[str]:
return self._attributes.get(key)
def put(self, key: str, value: str):
self._attributes[key] = value
def getAttributes(self) -> Dict[str, str]:
return dict(self._attributes)
def toString(self) -> str:
return f"DrmInfoRequest(type={self._info_type}, mime={self._mime_type})"
# ═══════════════════════════════════════════════════════════════
# DrmInfoResponse
# ═══════════════════════════════════════════════════════════════
class DrmInfoResponse(Stub):
"""DrmInfoResponse — DRM 信息响应"""
def __init__(self):
super().__init__()
self._info: Optional[DrmInfo] = None
self._status: int = 0
self._error_message: str = ""
self._request: Optional[DrmInfoRequest] = None
self._response_data: bytes = b""
self._timestamp: int = 0
def getInfo(self) -> Optional[DrmInfo]:
return self._info
def setInfo(self, info: DrmInfo):
self._info = info
def getStatus(self) -> int:
return self._status
def setStatus(self, status: int):
self._status = status
def getErrorMessage(self) -> str:
return self._error_message
def setErrorMessage(self, msg: str):
self._error_message = msg
def getRequest(self) -> Optional[DrmInfoRequest]:
return self._request
def setRequest(self, request: DrmInfoRequest):
self._request = request
def getResponseData(self) -> bytes:
return self._response_data
def setResponseData(self, data: bytes):
self._response_data = data
def getTimestamp(self) -> int:
return self._timestamp
def setTimestamp(self, ts: int):
self._timestamp = ts
def isSuccessful(self) -> bool:
return self._status == DrmStore.DrmStatus.STATUS_OK
def toString(self) -> str:
return f"DrmInfoResponse(status={self._status})"
# ═══════════════════════════════════════════════════════════════
# DrmConvertedStatus
# ═══════════════════════════════════════════════════════════════
class DrmConvertedStatus(Stub):
"""DrmConvertedStatus — DRM 转换状态"""
STATUS_OK = 0
STATUS_ERROR = 1
STATUS_INPUT_DATA_ERROR = 2
STATUS_OPERATION_NOT_SUPPORTED = 3
STATUS_INTERNAL_ERROR = 4
STATUS_INVALID_DATA = 5
STATUS_NO_RIGHTS = 6
STATUS_ENCRYPTION_ERROR = 7
def __init__(self, status_code: int = STATUS_OK,
converted_data: bytes = b"",
mime_type: str = ""):
super().__init__()
self._status_code = status_code
self._converted_data = converted_data
self._mime_type = mime_type
self._converted_file_path: str = ""
self._original_file_path: str = ""
self._conversion_time: int = 0
def getStatusCode(self) -> int:
return self._status_code
def setStatusCode(self, code: int):
self._status_code = code
def getConvertedData(self) -> bytes:
return self._converted_data
def setConvertedData(self, data: bytes):
self._converted_data = data
def getMimeType(self) -> str:
return self._mime_type
def setMimeType(self, mime_type: str):
self._mime_type = mime_type
def getConvertedFilePath(self) -> str:
return self._converted_file_path
def setConvertedFilePath(self, path: str):
self._converted_file_path = path
def getOriginalFilePath(self) -> str:
return self._original_file_path
def setOriginalFilePath(self, path: str):
self._original_file_path = path
def isSuccessful(self) -> bool:
return self._status_code == DrmConvertedStatus.STATUS_OK
def toString(self) -> str:
return f"DrmConvertedStatus(status={self._status_code})"
# ═══════════════════════════════════════════════════════════════
# DrmEvent
# ═══════════════════════════════════════════════════════════════
class DrmEvent(Stub):
"""DrmEvent — DRM 事件"""
TYPE_ALL_RIGHTS_REMOVED = 1001
TYPE_DRM_INFO_PROCESSED = 1002
TYPE_RIGHTS_INSTALLED = 1003
TYPE_RIGHTS_REMOVED = 1004
TYPE_RIGHTS_EXPIRED = 1005
TYPE_RIGHTS_ACQUISITION_STARTED = 1006
TYPE_RIGHTS_ACQUISITION_FINISHED = 1007
TYPE_RIGHTS_ACQUISITION_PROGRESS = 1008
TYPE_RIGHTS_ACQUISITION_FAILED = 1009
TYPE_META_DATA_AVAILABLE = 1010
TYPE_META_DATA_UPDATED = 1011
TYPE_META_DATA_REMOVED = 1012
TYPE_ACCOUNT_ALREADY_REGISTERED = 1013
TYPE_ACCOUNT_REGISTERED = 1014
TYPE_ACCOUNT_UNREGISTERED = 1015
def __init__(self, unique_id: int = 0, type_: int = 0,
message: str = ""):
super().__init__()
self._unique_id = unique_id
self._type = type_
self._message = message
self._attributes: Dict[str, Any] = {}
self._timestamp: int = int(time.time() * 1000)
def getUniqueId(self) -> int:
return self._unique_id
def getType(self) -> int:
return self._type
def getMessage(self) -> str:
return self._message
def getTimestamp(self) -> int:
return self._timestamp
def getAttribute(self, key: str) -> Optional[Any]:
return self._attributes.get(key)
def getAttributes(self) -> Dict[str, Any]:
return dict(self._attributes)
def setAttribute(self, key: str, value: Any):
self._attributes[key] = value
def toString(self) -> str:
return f"DrmEvent(type={self._type}, msg={self._message})"
# ═══════════════════════════════════════════════════════════════
# DrmErrorEvent
# ═══════════════════════════════════════════════════════════════
class DrmErrorEvent(DrmEvent):
"""DrmErrorEvent — DRM 错误事件"""
TYPE_RIGHTS_NOT_INSTALLED = 2001
TYPE_RIGHTS_ACQUISITION_FAILED = 2002
TYPE_RIGHTS_NOT_ACQUIRED = 2003
TYPE_PROCESS_DRM_INFO_FAILED = 2004
TYPE_REMOVE_ALL_RIGHTS_FAILED = 2005
TYPE_ACQUIRE_RIGHTS_FAILED = 2006
TYPE_SIGNATURE_MISMATCH = 2007
TYPE_INVALID_DRM_INFO = 2008
TYPE_CERTIFICATE_REVOKED = 2009
TYPE_LICENSE_EXPIRED = 2010
TYPE_LICENSE_NOT_FOUND = 2011
TYPE_SECURITY_VIOLATION = 2012
TYPE_NETWORK_ERROR = 2013
def __init__(self, unique_id: int = 0, type_: int = 0,
message: str = ""):
super().__init__(unique_id, type_, message)
self._error_code: int = 0
self._recoverable: bool = False
self._stack_trace: str = ""
def getErrorCode(self) -> int:
return self._error_code
def setErrorCode(self, code: int):
self._error_code = code
def isRecoverable(self) -> bool:
return self._recoverable
def setRecoverable(self, recoverable: bool):
self._recoverable = recoverable
def getStackTrace(self) -> str:
return self._stack_trace
def setStackTrace(self, trace: str):
self._stack_trace = trace
# ═══════════════════════════════════════════════════════════════
# DrmInfoEvent
# ═══════════════════════════════════════════════════════════════
class DrmInfoEvent(DrmEvent):
"""DrmInfoEvent — DRM 信息事件"""
TYPE_ACCOUNT_ALREADY_REGISTERED = 3001
TYPE_ACCOUNT_REGISTERED = 3002
TYPE_ACCOUNT_UNREGISTERED = 3003
TYPE_ACCOUNT_REGISTRATION_COMPLETED = 3004
TYPE_ACCOUNT_REGISTRATION_FAILED = 3005
TYPE_ACCOUNT_UNREGISTRATION_COMPLETED = 3006
TYPE_ACCOUNT_UNREGISTRATION_FAILED = 3007
TYPE_ADAPTER_REGISTRATION_COMPLETED = 3008
TYPE_ADAPTER_REGISTRATION_FAILED = 3009
TYPE_METADATA_RETRIEVED = 3010
TYPE_METADATA_RETRIEVAL_FAILED = 3011
TYPE_RIGHTS_ACQUISITION_PROGRESS = 3012
TYPE_RIGHTS_ACQUISITION_COMPLETED = 3013
TYPE_RIGHTS_ACQUISITION_FAILED = 3014
def __init__(self, unique_id: int = 0, type_: int = 0,
message: str = ""):
super().__init__(unique_id, type_, message)
self._data: Any = None
self._info_request: Optional[DrmInfoRequest] = None
def getData(self) -> Any:
return self._data
def setData(self, data: Any):
self._data = data
def getInfoRequest(self) -> Optional[DrmInfoRequest]:
return self._info_request
def setInfoRequest(self, request: DrmInfoRequest):
self._info_request = request
# ═══════════════════════════════════════════════════════════════
# DrmManagerClient
# ═══════════════════════════════════════════════════════════════
class DrmManagerClient(Stub):
"""DrmManagerClient — DRM 管理器客户端"""
ERROR_NONE = 0
ERROR_UNKNOWN = -1
ERROR_NOT_INITIALIZED = -2
ERROR_NOT_SUPPORTED = -3
ERROR_INVALID_ARGUMENT = -4
ERROR_PERMISSION_DENIED = -5
ERROR_SERVICE_NOT_FOUND = -6
ERROR_SERVICE_NOT_AVAILABLE = -7
ERROR_NETWORK = -8
ERROR_STORAGE = -9
ERROR_IO = -10
ERROR_INVALID_DRM_INFO = -11
ERROR_RIGHTS_NOT_ACQUIRED = -12
ERROR_RIGHTS_EXPIRED = -13
ERROR_NO_RIGHTS = -14
ERROR_INTERNAL = -99
class OnErrorListener(Stub):
"""DrmManagerClient.OnErrorListener — 错误监听器"""
def onError(self, client: DrmManagerClient, event: DrmErrorEvent):
pass
class OnInfoListener(Stub):
"""DrmManagerClient.OnInfoListener — 信息监听器"""
def onInfo(self, client: DrmManagerClient, event: DrmInfoEvent):
pass
class OnEventListener(Stub):
"""DrmManagerClient.OnEventListener — 事件监听器"""
def onEvent(self, client: DrmManagerClient, event: DrmEvent):
pass
def __init__(self, context: Any = None):
super().__init__()
self._context = context
self._unique_id: int = id(self)
self._is_initialized: bool = True
self._error_listeners: List[DrmManagerClient.OnErrorListener] = []
self._info_listeners: List[DrmManagerClient.OnInfoListener] = []
self._event_listeners: List[DrmManagerClient.OnEventListener] = []
def acquireRights(self, drm_info_request: DrmInfoRequest) -> DrmInfoResponse:
"""获取权限"""
response = DrmInfoResponse()
response.setRequest(drm_info_request)
response.setStatus(DrmStore.DrmStatus.STATUS_OK)
return response
def processDrmInfo(self, drm_info: DrmInfo) -> DrmInfoResponse:
"""处理 DRM 信息"""
response = DrmInfoResponse()
response.setInfo(drm_info)
response.setStatus(DrmStore.DrmStatus.STATUS_OK)
return response
def getDrmInfo(self, drm_info_request: DrmInfoRequest) -> Optional[DrmInfo]:
"""获取 DRM 信息"""
drm_info = DrmInfo(drm_info_request.getMimeType())
drm_info.setInfoType(drm_info_request.getInfoType())
return drm_info
def getConstraints(self, path: str, action: int) -> Dict[str, Any]:
"""获取约束"""
return {}
def getMetadata(self, path: str) -> Dict[str, str]:
"""获取元数据"""
return {}
def canHandle(self, path: str, mime_type: str) -> bool:
"""检查能否处理"""
return True
def removeAllListener(self):
"""移除所有监听器"""
self._error_listeners.clear()
self._info_listeners.clear()
self._event_listeners.clear()
def removeListener(self, listener: Any):
"""移除监听器"""
if listener in self._error_listeners:
self._error_listeners.remove(listener)
if listener in self._info_listeners:
self._info_listeners.remove(listener)
if listener in self._event_listeners:
self._event_listeners.remove(listener)
def setOnErrorListener(self, listener: OnErrorListener):
self._error_listeners.append(listener)
def setOnInfoListener(self, listener: OnInfoListener):
self._info_listeners.append(listener)
def setOnEventListener(self, listener: OnEventListener):
self._event_listeners.append(listener)
def getUniqueId(self) -> int:
return self._unique_id
def release(self):
"""释放客户端"""
self._is_initialized = False
self.removeAllListener()
def isInitialized(self) -> bool:
return self._is_initialized
def toString(self) -> str:
return f"DrmManagerClient(id={self._unique_id})"
# ═══════════════════════════════════════════════════════════════
# DrmOutputStream
# ═══════════════════════════════════════════════════════════════
class DrmOutputStream(Stub):
"""DrmOutputStream — DRM 输出流"""
def __init__(self, file_path: str = ""):
super().__init__()
self._file_path = file_path
self._is_open: bool = False
self._is_finished: bool = False
self._buffer: bytes = b""
self._bytes_written: int = 0
self._mime_type: str = ""
self._drm_info: Optional[DrmInfo] = None
def open(self) -> bool:
"""打开输出流"""
self._is_open = True
return True
def write(self, data: bytes) -> int:
"""写入数据"""
if not self._is_open:
return -1
self._buffer += data
self._bytes_written += len(data)
return len(data)
def close(self):
"""关闭输出流"""
if self._is_open:
self._is_open = False
self._is_finished = True
def finish(self):
"""完成写入"""
self._is_finished = True
def getFilePath(self) -> str:
return self._file_path
def setFilePath(self, path: str):
self._file_path = path
def isOpen(self) -> bool:
return self._is_open
def isFinished(self) -> bool:
return self._is_finished
def getBytesWritten(self) -> int:
return self._bytes_written
def getBuffer(self) -> bytes:
return self._buffer
def getMimeType(self) -> str:
return self._mime_type
def setMimeType(self, mime_type: str):
self._mime_type = mime_type
def toString(self) -> str:
return f"DrmOutputStream(path={self._file_path}, written={self._bytes_written})"
# ═══════════════════════════════════════════════════════════════
# DrmRights
# ═══════════════════════════════════════════════════════════════
class DrmRights(Stub):
"""DrmRights — DRM 权限"""
def __init__(self, rights_data: bytes = b"", mime_type: str = "",
account_id: str = "", subscription_id: str = ""):
super().__init__()
self._rights_data = rights_data
self._mime_type = mime_type
self._account_id = account_id
self._subscription_id = subscription_id
self._is_valid: bool = True
self._expiry_time: int = 0
self._issued_time: int = int(time.time() * 1000)
def getData(self) -> bytes:
return self._rights_data
def setData(self, data: bytes):
self._rights_data = data
def getMimeType(self) -> str:
return self._mime_type
def setMimeType(self, mime_type: str):
self._mime_type = mime_type
def getAccountId(self) -> str:
return self._account_id
def setAccountId(self, account_id: str):
self._account_id = account_id
def getSubscriptionId(self) -> str:
return self._subscription_id
def setSubscriptionId(self, sub_id: str):
self._subscription_id = sub_id
def isValid(self) -> bool:
return self._is_valid and (self._expiry_time == 0 or
self._expiry_time > int(time.time() * 1000))
def setValid(self, valid: bool):
self._is_valid = valid
def getExpiryTime(self) -> int:
return self._expiry_time
def setExpiryTime(self, expiry_ms: int):
self._expiry_time = expiry_ms
def getIssuedTime(self) -> int:
return self._issued_time
def isExpired(self) -> bool:
if self._expiry_time == 0:
return False
return self._expiry_time < int(time.time() * 1000)
def toString(self) -> str:
return f"DrmRights(mime={self._mime_type}, valid={self._is_valid})"
# ═══════════════════════════════════════════════════════════════
# DrmSupportInfo
# ═══════════════════════════════════════════════════════════════
class DrmSupportInfo(Stub):
"""DrmSupportInfo — DRM 支持信息"""
def __init__(self):
super().__init__()
self._mime_types: Set[str] = set()
self._file_suffixes: Set[str] = set()
self._descriptions: List[str] = []
self._plug_in_id: str = ""
self._vendor_name: str = ""
self._plugin_version: str = ""
self._is_available: bool = True
def addMimeType(self, mime_type: str):
self._mime_types.add(mime_type)
def addFileSuffix(self, file_suffix: str):
self._file_suffixes.add(file_suffix)
def addDescription(self, description: str):
self._descriptions.append(description)
def getMimeTypes(self) -> Set[str]:
return set(self._mime_types)
def getFileSuffixes(self) -> Set[str]:
return set(self._file_suffixes)
def getDescriptions(self) -> List[str]:
return list(self._descriptions)
def isSupportedMimeType(self, mime_type: str) -> bool:
return mime_type in self._mime_types
def isSupportedFileSuffix(self, suffix: str) -> bool:
return suffix in self._file_suffixes
def getPlugInId(self) -> str:
return self._plug_in_id
def setPlugInId(self, plugin_id: str):
self._plug_in_id = plugin_id
def getVendorName(self) -> str:
return self._vendor_name
def setVendorName(self, name: str):
self._vendor_name = name
def getPluginVersion(self) -> str:
return self._plugin_version
def setPluginVersion(self, version: str):
self._plugin_version = version
def isAvailable(self) -> bool:
return self._is_available
def setAvailable(self, available: bool):
self._is_available = available
def toString(self) -> str:
return f"DrmSupportInfo(mimeTypes={len(self._mime_types)}, suffixes={len(self._file_suffixes)})"
# ═══════════════════════════════════════════════════════════════
# DrmUtils
# ═══════════════════════════════════════════════════════════════
class DrmUtils(Stub):
"""DrmUtils — DRM 工具类"""
EXTENSION_DCF = ".dcf"
EXTENSION_FL = ".fl"
EXTENSION_DM = ".dm"
EXTENSION_ODF = ".odf"
EXTENSION_SDCF = ".sdcf"
EXTENSION_FLD = ".fld"
EXTENSION_HTML = ".html"
EXTENSION_XHTML = ".xhtml"
EXTENSION_XML = ".xml"
MIME_TYPE_DCF = "application/vnd.oma.drm.content"
MIME_TYPE_FL = "application/vnd.oma.drm.message"
MIME_TYPE_DM = "application/vnd.oma.drm.message"
MIME_TYPE_ODF = "application/vnd.oma.drm.content"
MIME_TYPE_SDCF = "application/vnd.oma.drm.content"
MIME_TYPE_UNKNOWN = "application/octet-stream"
@staticmethod
def getOriginalMimeType(context: Any, file_path: str) -> str:
"""获取原始 MIME 类型"""
return DrmUtils.MIME_TYPE_UNKNOWN
@staticmethod
def getOriginalFileSuffix(context: Any, file_path: str) -> str:
"""获取原始文件后缀"""
_, ext = os.path.splitext(file_path) if hasattr(os.path, 'splitext') else (file_path, "")
return ext
@staticmethod
def isDrmFile(file_path: str) -> bool:
"""检查是否为 DRM 文件"""
if not file_path:
return False
suffix = os.path.splitext(file_path)[1].lower() if hasattr(os.path, 'splitext') else ""
drm_extensions = {DrmUtils.EXTENSION_DCF, DrmUtils.EXTENSION_FL,
DrmUtils.EXTENSION_DM, DrmUtils.EXTENSION_ODF,
DrmUtils.EXTENSION_SDCF, DrmUtils.EXTENSION_FLD}
return suffix in drm_extensions
@staticmethod
def isDrmMimeType(mime_type: str) -> bool:
"""检查是否为 DRM MIME 类型"""
drm_mime_types = {DrmUtils.MIME_TYPE_DCF, DrmUtils.MIME_TYPE_FL,
DrmUtils.MIME_TYPE_DM, DrmUtils.MIME_TYPE_ODF,
DrmUtils.MIME_TYPE_SDCF}
return mime_type in drm_mime_types
@staticmethod
def getDrmFileType(file_path: str) -> int:
"""获取 DRM 文件类型"""
if not DrmUtils.isDrmFile(file_path):
return DrmStore.DrmObjectType.UNKNOWN
return DrmStore.DrmObjectType.CONTENT
@staticmethod
def getSupportedMimeTypes() -> Set[str]:
"""获取支持的 MIME 类型"""
return {DrmUtils.MIME_TYPE_DCF, DrmUtils.MIME_TYPE_FL,
DrmUtils.MIME_TYPE_DM, DrmUtils.MIME_TYPE_ODF,
DrmUtils.MIME_TYPE_SDCF}
@staticmethod
def convertToDrmFile(input_path: str, output_path: str,
mime_type: str) -> DrmConvertedStatus:
"""转换为 DRM 文件"""
with open(input_path, "rb") as f:
data = f.read()
status = DrmConvertedStatus(DrmConvertedStatus.STATUS_OK, data, mime_type)
status.setOriginalFilePath(input_path)
status.setConvertedFilePath(output_path)
return status
# ═══════════════════════════════════════════════════════════════
# DrmManager (高层管理器)
# ═══════════════════════════════════════════════════════════════
class DrmManager(Stub):
"""DrmManager — DRM 管理器"""
def __init__(self, context: Any = None):
super().__init__()
self._context = context
self._clients: Dict[int, DrmManagerClient] = {}
self._is_available: bool = True
self._support_infos: List[DrmSupportInfo] = []
@staticmethod
def getInstance(context: Any) -> DrmManager:
return DrmManager(context)
def getDrmManagerClient(self) -> DrmManagerClient:
client = DrmManagerClient(self._context)
client_id = client.getUniqueId()
self._clients[client_id] = client
return client
def releaseDrmManagerClient(self, client: DrmManagerClient):
client_id = client.getUniqueId()
if client_id in self._clients:
client.release()
del self._clients[client_id]
def isAvailable(self) -> bool:
return self._is_available
def setAvailable(self, available: bool):
self._is_available = available
def getSupportInfos(self) -> List[DrmSupportInfo]:
return list(self._support_infos)
def addSupportInfo(self, info: DrmSupportInfo):
self._support_infos.append(info)
def removeSupportInfo(self, info: DrmSupportInfo):
self._support_infos = [i for i in self._support_infos if i is not info]
def canHandle(self, path: str, mime_type: str) -> bool:
for client in self._clients.values():
if client.canHandle(path, mime_type):
return True
return False
def getAvailableClients(self) -> List[DrmManagerClient]:
return [c for c in self._clients.values() if c.isInitialized()]
def release(self):
for client in list(self._clients.values()):
client.release()
self._clients.clear()
self._support_infos.clear()
def toString(self) -> str:
return f"DrmManager(clients={len(self._clients)}, available={self._is_available})"