""" Android DragAndDrop 组件 — DragAndDropPermissions, ClipData, ClipDescription 方法签名完全对齐 Android SDK """ from __future__ import annotations import os from typing import Any, Dict, List, Optional, Set, Tuple, Union from .._core import Stub, AndroidOnlyError # ═══════════════════════════════════════════════════════════════ # MIME 类型常量 # ═══════════════════════════════════════════════════════════════ MIMETYPE_TEXT_PLAIN = "text/plain" MIMETYPE_TEXT_HTML = "text/html" MIMETYPE_TEXT_URILIST = "text/uri-list" MIMETYPE_TEXT_INTENT = "text/vnd.android.intent" MIMETYPE_IMAGE_PNG = "image/png" MIMETYPE_IMAGE_JPEG = "image/jpeg" MIMETYPE_IMAGE_GIF = "image/gif" MIMETYPE_IMAGE_WEBP = "image/webp" MIMETYPE_IMAGE_BMP = "image/bmp" MIMETYPE_VIDEO_MP4 = "video/mp4" MIMETYPE_VIDEO_3GP = "video/3gpp" MIMETYPE_AUDIO_MP3 = "audio/mpeg" MIMETYPE_AUDIO_AAC = "audio/mp4a-latm" MIMETYPE_APPLICATION_PDF = "application/pdf" MIMETYPE_APPLICATION_ZIP = "application/zip" MIMETYPE_APPLICATION_JSON = "application/json" MIMETYPE_APPLICATION_XML = "application/xml" # ═══════════════════════════════════════════════════════════════ # ClipDescription # ═══════════════════════════════════════════════════════════════ class ClipDescription(Stub): """ClipDescription — 剪贴板数据描述""" MIMETYPE_TEXT_PLAIN = MIMETYPE_TEXT_PLAIN MIMETYPE_TEXT_HTML = MIMETYPE_TEXT_HTML MIMETYPE_TEXT_URILIST = MIMETYPE_TEXT_URILIST MIMETYPE_TEXT_INTENT = MIMETYPE_TEXT_INTENT def __init__(self, label: str, mime_types: List[str]): super().__init__() self._label = label self._mime_types: List[str] = list(mime_types) self._extras: Optional[Any] = None self._timestamp: int = 0 @staticmethod def compareMimeTypes(mime_type1: str, mime_type2: str) -> bool: """比较两个 MIME 类型是否匹配""" if mime_type1 == mime_type2: return True if mime_type1 == "*/*" or mime_type2 == "*/*": return True t1 = mime_type1.split("/")[0] if "/" in mime_type1 else "" t2 = mime_type2.split("/")[0] if "/" in mime_type2 else "" if t1 and t1 == t2: if mime_type1.endswith("/*") or mime_type2.endswith("/*"): return True return False def getLabel(self) -> str: return self._label def getMimeType(self, index: int) -> str: if 0 <= index < len(self._mime_types): return self._mime_types[index] return "" def getMimeTypeCount(self) -> int: return len(self._mime_types) def hasMimeType(self, mime_type: str) -> bool: for mt in self._mime_types: if ClipDescription.compareMimeTypes(mt, mime_type): return True return False def filterMimeTypes(self, mime_type: str) -> List[str]: result = [] for mt in self._mime_types: if ClipDescription.compareMimeTypes(mt, mime_type): result.append(mt) return result def setExtras(self, extras: Any) -> None: self._extras = extras def getExtras(self) -> Optional[Any]: return self._extras def getTimestamp(self) -> int: return self._timestamp def setTimestamp(self, ts: int) -> None: self._timestamp = ts def toString(self) -> str: return (f"ClipDescription(label={self._label}, " f"mimeTypes={self._mime_types})") # ═══════════════════════════════════════════════════════════════ # ClipData.Item # ═══════════════════════════════════════════════════════════════ class ClipItem(Stub): """ClipData.Item — 剪贴板数据项""" def __init__(self, text: Optional[str] = None, intent: Optional[Any] = None, uri: Optional[str] = None, html_text: Optional[str] = None): super().__init__() self._text = text self._intent = intent self._uri = uri self._html_text = html_text def getText(self) -> Optional[str]: return self._text def getIntent(self) -> Optional[Any]: return self._intent def getUri(self) -> Optional[str]: return self._uri def getHtmlText(self) -> Optional[str]: return self._html_text def coerceToText(self, context: Any) -> str: if self._text: return self._text if self._uri: return str(self._uri) if self._intent: return str(self._intent) return "" def coerceToHtmlText(self, context: Any) -> Optional[str]: return self._html_text def coerceToStyledText(self, context: Any) -> Optional[str]: return self.coerceToText(context) def toString(self) -> str: return (f"ClipData.Item(text={self._text}, " f"uri={self._uri})") # ═══════════════════════════════════════════════════════════════ # ClipData # ═══════════════════════════════════════════════════════════════ class ClipData(Stub): """ClipData — 剪贴板数据""" Item = ClipItem def __init__(self, description: ClipDescription, item: ClipItem): super().__init__() self._description = description self._items: List[ClipItem] = [item] @staticmethod def newPlainText(label: str, text: str) -> "ClipData": desc = ClipDescription(label, [MIMETYPE_TEXT_PLAIN]) item = ClipItem(text=text) return ClipData(desc, item) @staticmethod def newHtmlText(label: str, text: str, html_text: str) -> "ClipData": desc = ClipDescription(label, [MIMETYPE_TEXT_HTML, MIMETYPE_TEXT_PLAIN]) item = ClipItem(text=text, html_text=html_text) return ClipData(desc, item) @staticmethod def newIntent(label: str, intent: Any) -> "ClipData": desc = ClipDescription(label, [MIMETYPE_TEXT_INTENT]) item = ClipItem(intent=intent) return ClipData(desc, item) @staticmethod def newUri(cr: Any, label: str, uri: str) -> "ClipData": mime_type = MIMETYPE_TEXT_URILIST desc = ClipDescription(label, [mime_type]) item = ClipItem(uri=uri) return ClipData(desc, item) @staticmethod def newRawUri(label: str, uri: str) -> "ClipData": desc = ClipDescription(label, [MIMETYPE_TEXT_URILIST]) item = ClipItem(uri=uri) return ClipData(desc, item) def getDescription(self) -> ClipDescription: return self._description def addItem(self, item: ClipItem) -> None: self._items.append(item) def getItemAt(self, index: int) -> Optional[ClipItem]: if 0 <= index < len(self._items): return self._items[index] return None def getItemCount(self) -> int: return len(self._items) def toString(self) -> str: return (f"ClipData(desc={self._description}, " f"items={len(self._items)})") # ═══════════════════════════════════════════════════════════════ # DragAndDropPermissions # ═══════════════════════════════════════════════════════════════ class DragAndDropPermissions(Stub): """DragAndDropPermissions — 拖放权限""" def __init__(self): super().__init__() self._granted_uris: List[str] = [] self._released = False def release(self) -> None: self._released = True self._granted_uris.clear() def isReleased(self) -> bool: return self._released def getGrantedUris(self) -> List[str]: return list(self._granted_uris) def toString(self) -> str: return (f"DragAndDropPermissions(uris={len(self._granted_uris)}, " f"released={self._released})")