feat: 新增 42 个 Android API 模块
新增模块覆盖: 系统层 (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 行代码
This commit is contained in:
1 parent
8ad62be068
commit
506f9ac725
43 files changed
+16704
-23
No files matched your search
@@ -0,0 +1,310 @@
|
||||
"""
|
||||
Android media.browse 组件 — MediaBrowser, MediaItem, MediaDescription 等
|
||||
方法签名完全对齐 Android SDK
|
||||
"""
|
||||
|
||||
from typing import Any, Callable, Dict, List, Optional, Set
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# MediaBrowser
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class MediaBrowser(Stub):
|
||||
"""MediaBrowser — 媒体浏览器"""
|
||||
|
||||
EXTRA_PAGE = "android.media.browse.extra.PAGE"
|
||||
EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ConnectionCallback
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class ConnectionCallback(Stub):
|
||||
"""MediaBrowser.ConnectionCallback — 连接回调"""
|
||||
|
||||
def onConnected(self):
|
||||
pass
|
||||
|
||||
def onConnectionSuspended(self):
|
||||
pass
|
||||
|
||||
def onConnectionFailed(self):
|
||||
pass
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# SubscriptionCallback
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class SubscriptionCallback(Stub):
|
||||
"""MediaBrowser.SubscriptionCallback — 订阅回调"""
|
||||
|
||||
def onChildrenLoaded(self, parentId: str, children: List["MediaBrowser.MediaItem"]):
|
||||
pass
|
||||
|
||||
def onError(self, parentId: str):
|
||||
pass
|
||||
|
||||
def onChildrenLoadedWithOptions(self, parentId: str,
|
||||
children: List["MediaBrowser.MediaItem"],
|
||||
options: Any):
|
||||
pass
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ItemCallback
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class ItemCallback(Stub):
|
||||
"""MediaBrowser.ItemCallback — 媒体项回调"""
|
||||
|
||||
def onItemLoaded(self, item: "MediaBrowser.MediaItem"):
|
||||
pass
|
||||
|
||||
def onError(self, mediaId: str):
|
||||
pass
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# MediaItem
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class MediaItem(Stub):
|
||||
"""MediaBrowser.MediaItem — 媒体项"""
|
||||
|
||||
FLAG_BROWSABLE = 1
|
||||
FLAG_PLAYABLE = 2
|
||||
|
||||
def __init__(self, description: "MediaDescription" = None, flags: int = FLAG_PLAYABLE):
|
||||
super().__init__()
|
||||
self._description = description or MediaDescription()
|
||||
self._flags = flags
|
||||
|
||||
def getMediaId(self) -> Optional[str]:
|
||||
return self._description.getMediaId()
|
||||
|
||||
def getDescription(self) -> "MediaDescription":
|
||||
return self._description
|
||||
|
||||
def getFlags(self) -> int:
|
||||
return self._flags
|
||||
|
||||
def isBrowsable(self) -> bool:
|
||||
return bool(self._flags & MediaBrowser.MediaItem.FLAG_BROWSABLE)
|
||||
|
||||
def isPlayable(self) -> bool:
|
||||
return bool(self._flags & MediaBrowser.MediaItem.FLAG_PLAYABLE)
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"MediaItem(mediaId={self.getMediaId()}, flags={self._flags})"
|
||||
|
||||
def __init__(self, context: Any = None, serviceComponent: Any = None,
|
||||
connectionCallback: Optional[ConnectionCallback] = None,
|
||||
rootHints: Any = None):
|
||||
super().__init__()
|
||||
self._connected = False
|
||||
self._service_component = serviceComponent
|
||||
self._root: str = ""
|
||||
self._session_token: Any = None
|
||||
self._connection_callback = connectionCallback
|
||||
self._subscriptions: Dict[str, List[MediaBrowser.SubscriptionCallback]] = {}
|
||||
self._media_tree: Dict[str, List[MediaBrowser.MediaItem]] = {}
|
||||
self._item_cache: Dict[str, MediaBrowser.MediaItem] = {}
|
||||
|
||||
def connect(self):
|
||||
self._connected = True
|
||||
self._root = "__ROOT__"
|
||||
# Build a simple in-memory media tree
|
||||
self._media_tree["__ROOT__"] = [
|
||||
MediaBrowser.MediaItem(
|
||||
MediaDescription.Builder()
|
||||
.setMediaId("__RECENT__")
|
||||
.setTitle("Recently Played")
|
||||
.setSubtitle("Your recently played media")
|
||||
.build(),
|
||||
flags=MediaBrowser.MediaItem.FLAG_BROWSABLE
|
||||
),
|
||||
MediaBrowser.MediaItem(
|
||||
MediaDescription.Builder()
|
||||
.setMediaId("__ALL__")
|
||||
.setTitle("All Music")
|
||||
.setSubtitle("All your music library")
|
||||
.build(),
|
||||
flags=MediaBrowser.MediaItem.FLAG_BROWSABLE
|
||||
),
|
||||
]
|
||||
self._media_tree["__RECENT__"] = [
|
||||
MediaBrowser.MediaItem(
|
||||
MediaDescription.Builder()
|
||||
.setMediaId("song_1")
|
||||
.setTitle("Sample Song 1")
|
||||
.setSubtitle("Artist 1")
|
||||
.build(),
|
||||
flags=MediaBrowser.MediaItem.FLAG_PLAYABLE
|
||||
),
|
||||
]
|
||||
self._item_cache["song_1"] = self._media_tree["__RECENT__"][0]
|
||||
|
||||
if self._connection_callback:
|
||||
self._connection_callback.onConnected()
|
||||
|
||||
def disconnect(self):
|
||||
self._connected = False
|
||||
self._subscriptions.clear()
|
||||
if self._connection_callback:
|
||||
self._connection_callback.onConnectionSuspended()
|
||||
|
||||
def getConnected(self) -> bool:
|
||||
return self._connected
|
||||
|
||||
def getServiceComponent(self) -> Any:
|
||||
return self._service_component
|
||||
|
||||
def getRoot(self) -> str:
|
||||
return self._root
|
||||
|
||||
def isConnected(self) -> bool:
|
||||
return self._connected
|
||||
|
||||
def getSessionToken(self) -> Any:
|
||||
return self._session_token
|
||||
|
||||
def getItem(self, mediaId: str) -> Optional[MediaItem]:
|
||||
return self._item_cache.get(mediaId)
|
||||
|
||||
def subscribe(self, parentId: str, callback: SubscriptionCallback):
|
||||
if parentId not in self._subscriptions:
|
||||
self._subscriptions[parentId] = []
|
||||
self._subscriptions[parentId].append(callback)
|
||||
|
||||
children = self._media_tree.get(parentId, [])
|
||||
if children:
|
||||
callback.onChildrenLoaded(parentId, children)
|
||||
else:
|
||||
callback.onError(parentId)
|
||||
|
||||
def unsubscribe(self, parentId: str, callback: Optional[SubscriptionCallback] = None):
|
||||
if parentId in self._subscriptions:
|
||||
if callback:
|
||||
self._subscriptions[parentId] = [
|
||||
cb for cb in self._subscriptions[parentId]
|
||||
if cb is not callback
|
||||
]
|
||||
if not self._subscriptions[parentId]:
|
||||
del self._subscriptions[parentId]
|
||||
else:
|
||||
del self._subscriptions[parentId]
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# MediaDescription
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class MediaDescription(Stub):
|
||||
"""MediaDescription — 媒体描述"""
|
||||
|
||||
class Builder(Stub):
|
||||
"""MediaDescription.Builder — 媒体描述构建器"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._media_id: Optional[str] = None
|
||||
self._title: Optional[str] = None
|
||||
self._subtitle: Optional[str] = None
|
||||
self._description: Optional[str] = None
|
||||
self._icon_bitmap: Any = None
|
||||
self._icon_uri: Optional[str] = None
|
||||
self._extras: Any = None
|
||||
self._media_uri: Optional[str] = None
|
||||
|
||||
def setMediaId(self, mediaId: str) -> "MediaDescription.Builder":
|
||||
self._media_id = mediaId
|
||||
return self
|
||||
|
||||
def setTitle(self, title: str) -> "MediaDescription.Builder":
|
||||
self._title = title
|
||||
return self
|
||||
|
||||
def setSubtitle(self, subtitle: str) -> "MediaDescription.Builder":
|
||||
self._subtitle = subtitle
|
||||
return self
|
||||
|
||||
def setDescription(self, description: str) -> "MediaDescription.Builder":
|
||||
self._description = description
|
||||
return self
|
||||
|
||||
def setIconBitmap(self, icon: Any) -> "MediaDescription.Builder":
|
||||
self._icon_bitmap = icon
|
||||
return self
|
||||
|
||||
def setIconUri(self, iconUri: str) -> "MediaDescription.Builder":
|
||||
self._icon_uri = iconUri
|
||||
return self
|
||||
|
||||
def setExtras(self, extras: Any) -> "MediaDescription.Builder":
|
||||
self._extras = extras
|
||||
return self
|
||||
|
||||
def setMediaUri(self, mediaUri: str) -> "MediaDescription.Builder":
|
||||
self._media_uri = mediaUri
|
||||
return self
|
||||
|
||||
def build(self) -> "MediaDescription":
|
||||
md = MediaDescription()
|
||||
md._media_id = self._media_id
|
||||
md._title = self._title
|
||||
md._subtitle = self._subtitle
|
||||
md._description = self._description
|
||||
md._icon_bitmap = self._icon_bitmap
|
||||
md._icon_uri = self._icon_uri
|
||||
md._extras = self._extras
|
||||
md._media_uri = self._media_uri
|
||||
return md
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._media_id: Optional[str] = None
|
||||
self._title: Optional[str] = None
|
||||
self._subtitle: Optional[str] = None
|
||||
self._description: Optional[str] = None
|
||||
self._icon_bitmap: Any = None
|
||||
self._icon_uri: Optional[str] = None
|
||||
self._extras: Any = None
|
||||
self._media_uri: Optional[str] = None
|
||||
|
||||
def getMediaId(self) -> Optional[str]:
|
||||
return self._media_id
|
||||
|
||||
def getTitle(self) -> Optional[str]:
|
||||
return self._title
|
||||
|
||||
def getSubtitle(self) -> Optional[str]:
|
||||
return self._subtitle
|
||||
|
||||
def getDescription(self) -> Optional[str]:
|
||||
return self._description
|
||||
|
||||
def getIconBitmap(self) -> Any:
|
||||
return self._icon_bitmap
|
||||
|
||||
def getIconUri(self) -> Optional[str]:
|
||||
return self._icon_uri
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
def getMediaUri(self) -> Optional[str]:
|
||||
return self._media_uri
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"MediaDescription(id={self._media_id}, title={self._title})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# __all__
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
__all__ = [
|
||||
"MediaBrowser",
|
||||
"MediaDescription",
|
||||
]
|
||||
Reference in new issue
Block a user