""" Android Media Transfer Protocol API — MtpDevice, MtpStorageInfo, MtpObjectInfo, MtpConstants 方法签名完全对齐 Android SDK """ import os as _os import sys import time from datetime import datetime from typing import Any, Dict, List, Optional, Set, Tuple, Callable, BinaryIO from .._core import Stub, AndroidOnlyError from ..java.lang import RuntimeException IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {}) __all__ = [ "MtpDevice", "MtpStorageInfo", "MtpObjectInfo", "MtpConstants", "MtpPropertyGroup", "MtpDeviceInfo", "MtpStorage", ] # ═══════════════════════════════════════════════════════════════ # MtpConstants — 50+ 格式常量 # ═══════════════════════════════════════════════════════════════ class MtpConstants(Stub): """MTP 协议常量""" # --- 格式常量 --- FORMAT_UNDEFINED = 0x3000 FORMAT_ASSOCIATION = 0x3001 FORMAT_SCRIPT = 0x3002 FORMAT_EXECUTABLE = 0x3003 FORMAT_TEXT = 0x3004 FORMAT_HTML = 0x3005 FORMAT_DPOF = 0x3006 FORMAT_AIFF = 0x3007 FORMAT_WAV = 0x3008 FORMAT_MP3 = 0x3009 FORMAT_AVI = 0x300A FORMAT_MPEG = 0x300B FORMAT_ASF = 0x300C FORMAT_DEF = 0x300D FORMAT_EXIF_JPEG = 0x3801 FORMAT_TIFF_EP = 0x3802 FORMAT_FLASHPIX = 0x3803 FORMAT_BMP = 0x3804 FORMAT_CIFF = 0x3805 FORMAT_GIF = 0x3807 FORMAT_JFIF = 0x3808 FORMAT_PCD = 0x3809 FORMAT_PICT = 0x380A FORMAT_PNG = 0x380B FORMAT_TIFF = 0x380D FORMAT_TIFF_IT = 0x380E FORMAT_JP2 = 0x380F FORMAT_JPX = 0x3810 FORMAT_XML = 0x3811 FORMAT_FIRMWARE = 0x3802 FORMAT_WMA = 0xB901 FORMAT_WMV = 0xB980 FORMAT_WPL = 0xBA05 FORMAT_FLAC = 0xB906 FORMAT_OGG = 0xB902 FORMAT_AAC = 0xB903 FORMAT_MP4_CONTAINER = 0xB904 FORMAT_MP2 = 0xB905 FORMAT_3GP = 0xB907 FORMAT_3GP_CONTAINER = 0xB908 FORMAT_AVC = 0xB909 FORMAT_HEVC = 0xB90A FORMAT_DNG = 0xB90B FORMAT_ARW = 0xB90C FORMAT_CR2 = 0xB90D FORMAT_RAF = 0xB90E FORMAT_NEF = 0xB90F FORMAT_ORF = 0xB910 FORMAT_RW2 = 0xB911 FORMAT_SRW = 0xB912 # --- 保护状态 --- PROTECTION_STATUS_NONE = 0 PROTECTION_STATUS_READ_ONLY = 0x8001 PROTECTION_STATUS_PROTECTED = 0x8002 # --- 关联类型 --- ASSOCIATION_TYPE_UNDEFINED = 0x0000 ASSOCIATION_TYPE_GENERIC_FOLDER = 0x0001 # --- 属性格式常量 --- PROP_FORMAT_UNDEFINED = 0x0000 PROP_FORMAT_STRING = 0xFFFF PROP_FORMAT_UINT8 = 0x0001 PROP_FORMAT_UINT16 = 0x0002 PROP_FORMAT_UINT32 = 0x0004 PROP_FORMAT_UINT64 = 0x0008 PROP_FORMAT_INT8 = 0x0009 PROP_FORMAT_INT16 = 0x000A PROP_FORMAT_INT32 = 0x000B PROP_FORMAT_INT64 = 0x000C PROP_FORMAT_BOOL = 0x4001 PROP_FORMAT_DATE = 0x4002 # --- 操作码 --- OPERATION_GET_DEVICE_INFO = 0x1001 OPERATION_OPEN_SESSION = 0x1002 OPERATION_CLOSE_SESSION = 0x1003 OPERATION_GET_STORAGE_IDS = 0x1004 OPERATION_GET_STORAGE_INFO = 0x1005 OPERATION_GET_OBJECT_PROP_VALUE = 0x9802 OPERATION_SET_OBJECT_PROP_VALUE = 0x9803 OPERATION_GET_OBJECT_INFO = 0x1007 OPERATION_GET_OBJECT = 0x1009 OPERATION_GET_THUMB = 0x100A OPERATION_DELETE_OBJECT = 0x100B OPERATION_SEND_OBJECT_INFO = 0x100C OPERATION_SEND_OBJECT = 0x100D OPERATION_GET_OBJECT_REFERENCES = 0x1010 OPERATION_SET_OBJECT_REFERENCES = 0x1011 def __init__(self): super().__init__() # ═══════════════════════════════════════════════════════════════ # MtpDevice # ═══════════════════════════════════════════════════════════════ class MtpDevice(Stub): """MtpDevice — MTP 设备 (桌面存根)""" def __init__(self, device: Any = None): super().__init__() self._device = device self._opened = False def open(self) -> bool: """打开 MTP 设备""" raise AndroidOnlyError("MtpDevice.open() 仅在 Android 设备上可用") def close(self): """关闭 MTP 设备""" self._opened = False def getDeviceInfo(self) -> "MtpDeviceInfo": """获取设备信息""" return MtpDeviceInfo() def getDeviceName(self) -> str: """获取设备名称""" return "MTP Device" def getObjectHandles( self, storageId: int, format: int, objectHandle: int ) -> List[int]: """获取对象句柄列表""" return [] def getObjectInfo(self, objectHandle: int) -> Optional["MtpObjectInfo"]: """获取对象信息""" return None def getObject(self, objectHandle: int, dataSize: int) -> Optional[bytes]: """获取对象数据""" return None def getThumbnail(self, objectHandle: int) -> Optional[bytes]: """获取缩略图""" return None def getStorageIds(self) -> List[int]: """获取存储 ID 列表""" return [0x00010001] def getStorageInfo(self, storageId: int) -> "MtpStorageInfo": """获取存储信息""" return MtpStorageInfo() def importFile(self, objectHandle: int, destPath: str) -> bool: """导入文件""" raise AndroidOnlyError("MtpDevice.importFile() 仅在 Android 设备上可用") def deleteObject(self, objectHandle: int) -> bool: """删除对象""" raise AndroidOnlyError("MtpDevice.deleteObject() 仅在 Android 设备上可用") def getParent(self, objectHandle: int) -> int: """获取父对象句柄""" return 0xFFFFFFFF def getObjectReferences(self, objectHandle: int) -> List[int]: """获取对象引用列表""" return [] def setObjectReferences(self, objectHandle: int, references: List[int]) -> bool: """设置对象引用""" raise AndroidOnlyError("MtpDevice.setObjectReferences() 仅在 Android 设备上可用") def sendObject(self, objectHandle: int, data: bytes) -> bool: """发送对象""" raise AndroidOnlyError("MtpDevice.sendObject() 仅在 Android 设备上可用") def sendObjectInfo( self, storageId: int, parent: int, info: "MtpObjectInfo" ) -> int: """发送对象信息""" raise AndroidOnlyError("MtpDevice.sendObjectInfo() 仅在 Android 设备上可用") def toString(self) -> str: return f"MtpDevice(name={self.getDeviceName()})" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return id(self) & 0x7FFFFFFF # ═══════════════════════════════════════════════════════════════ # MtpStorageInfo # ═══════════════════════════════════════════════════════════════ class MtpStorageInfo(Stub): """MtpStorageInfo — MTP 存储信息""" def __init__(self): super().__init__() self._storage_id = 0x00010001 self._max_capacity = 32 * 1024 * 1024 * 1024 # 32GB self._free_space = 16 * 1024 * 1024 * 1024 # 16GB self._description = "Internal Storage" self._volume_identifier = "" def getStorageId(self) -> int: return self._storage_id def getMaxCapacity(self) -> int: return self._max_capacity def getFreeSpace(self) -> int: return self._free_space def getDescription(self) -> str: return self._description def getVolumeIdentifier(self) -> str: return self._volume_identifier def toString(self) -> str: return (f"MtpStorageInfo(id={self._storage_id}, " f"free={self._free_space}B)") def equals(self, other) -> bool: if not isinstance(other, MtpStorageInfo): return False return self._storage_id == other._storage_id def hashCode(self) -> int: return self._storage_id & 0x7FFFFFFF # ═══════════════════════════════════════════════════════════════ # MtpObjectInfo # ═══════════════════════════════════════════════════════════════ class MtpObjectInfo(Stub): """MtpObjectInfo — MTP 对象信息""" def __init__(self): super().__init__() self._object_handle = 0 self._storage_id = 0 self._format = MtpConstants.FORMAT_UNDEFINED self._protection_status = MtpConstants.PROTECTION_STATUS_NONE self._compressed_size = 0 self._thumb_format = MtpConstants.FORMAT_UNDEFINED self._thumb_compressed_size = 0 self._thumb_pix_width = 0 self._thumb_pix_height = 0 self._image_pix_width = 0 self._image_pix_height = 0 self._image_pix_depth = 0 self._parent = 0 self._association_desc = 0 self._association_type = 0 self._sequence_number = 0 self._name = "" self._date_created = 0 self._date_modified = 0 self._keywords = "" def getObjectHandle(self) -> int: return self._object_handle def getStorageId(self) -> int: return self._storage_id def getFormat(self) -> int: return self._format def getProtectionStatus(self) -> int: return self._protection_status def getCompressedSize(self) -> int: return self._compressed_size def getThumbFormat(self) -> int: return self._thumb_format def getThumbCompressedSize(self) -> int: return self._thumb_compressed_size def getThumbPixWidth(self) -> int: return self._thumb_pix_width def getThumbPixHeight(self) -> int: return self._thumb_pix_height def getImagePixWidth(self) -> int: return self._image_pix_width def getImagePixHeight(self) -> int: return self._image_pix_height def getImagePixDepth(self) -> int: return self._image_pix_depth def getParent(self) -> int: return self._parent def getAssociationDesc(self) -> int: return self._association_desc def getAssociationType(self) -> int: return self._association_type def getSequenceNumber(self) -> int: return self._sequence_number def getName(self) -> str: return self._name def getDateCreated(self) -> int: return self._date_created def getDateModified(self) -> int: return self._date_modified def getKeywords(self) -> str: return self._keywords def toString(self) -> str: return f"MtpObjectInfo(name={self._name}, handle={self._object_handle})" def equals(self, other) -> bool: if not isinstance(other, MtpObjectInfo): return False return self._object_handle == other._object_handle def hashCode(self) -> int: return self._object_handle & 0x7FFFFFFF # ═══════════════════════════════════════════════════════════════ # MtpPropertyGroup # ═══════════════════════════════════════════════════════════════ class MtpPropertyGroup(Stub): """MtpPropertyGroup — MTP 属性组""" def __init__(self): super().__init__() self._properties: Dict[int, Any] = {} def getPropertyValue(self, propertyCode: int) -> Optional[Any]: return self._properties.get(propertyCode) def toString(self) -> str: return f"MtpPropertyGroup(properties={len(self._properties)})" def equals(self, other) -> bool: return self is other def hashCode(self) -> int: return id(self) & 0x7FFFFFFF # ═══════════════════════════════════════════════════════════════ # MtpDeviceInfo # ═══════════════════════════════════════════════════════════════ class MtpDeviceInfo(Stub): """MtpDeviceInfo — MTP 设备信息""" def __init__(self): super().__init__() self._manufacturer = "Unknown" self._model = "MTP Device" self._device_version = "1.0" self._serial_number = "00000000" self._operations_supported: List[int] = [] self._events_supported: List[int] = [] self._device_properties_supported: List[int] = [] def getManufacturer(self) -> str: return self._manufacturer def getModel(self) -> str: return self._model def getDeviceVersion(self) -> str: return self._device_version def getSerialNumber(self) -> str: return self._serial_number def getOperationsSupported(self) -> List[int]: return list(self._operations_supported) def getEventsSupported(self) -> List[int]: return list(self._events_supported) def getDevicePropertySupported(self) -> List[int]: return list(self._device_properties_supported) def toString(self) -> str: return f"MtpDeviceInfo(manufacturer={self._manufacturer}, model={self._model})" def equals(self, other) -> bool: if not isinstance(other, MtpDeviceInfo): return False return self._serial_number == other._serial_number def hashCode(self) -> int: return hash(self._serial_number) & 0x7FFFFFFF # ═══════════════════════════════════════════════════════════════ # MtpStorage # ═══════════════════════════════════════════════════════════════ class MtpStorage(Stub): """MtpStorage — MTP 存储""" def __init__(self, storageId: int = 0x00010001, path: str = ""): super().__init__() self._storage_id = storageId self._path = path self._description = "Storage" def getStorageId(self) -> int: return self._storage_id def getPath(self) -> str: return self._path def getDescription(self) -> str: return self._description def toString(self) -> str: return f"MtpStorage(id={self._storage_id}, path={self._path})" def equals(self, other) -> bool: if not isinstance(other, MtpStorage): return False return self._storage_id == other._storage_id def hashCode(self) -> int: return self._storage_id & 0x7FFFFFFF