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,854 @@
|
||||
"""
|
||||
Android media.session 组件 — MediaSession, MediaController, PlaybackState, MediaMetadata 等
|
||||
方法签名完全对齐 Android SDK
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Any, Callable, Dict, List, Optional, Set, Union
|
||||
|
||||
from .._core import Stub, AndroidOnlyError
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# MediaSession
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class MediaSession(Stub):
|
||||
"""MediaSession — 媒体会话"""
|
||||
|
||||
FLAG_HANDLES_MEDIA_BUTTONS = 1
|
||||
FLAG_HANDLES_TRANSPORT_CONTROLS = 2
|
||||
FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 4
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Callback
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class Callback(Stub):
|
||||
"""MediaSession.Callback — 会话回调"""
|
||||
|
||||
def onPlay(self):
|
||||
pass
|
||||
|
||||
def onPause(self):
|
||||
pass
|
||||
|
||||
def onSkipToNext(self):
|
||||
pass
|
||||
|
||||
def onSkipToPrevious(self):
|
||||
pass
|
||||
|
||||
def onFastForward(self):
|
||||
pass
|
||||
|
||||
def onRewind(self):
|
||||
pass
|
||||
|
||||
def onStop(self):
|
||||
pass
|
||||
|
||||
def onSeekTo(self, pos: int):
|
||||
pass
|
||||
|
||||
def onSetRating(self, rating: "Rating"):
|
||||
pass
|
||||
|
||||
def onSetRepeatMode(self, repeatMode: int):
|
||||
pass
|
||||
|
||||
def onSetShuffleMode(self, shuffleMode: int):
|
||||
pass
|
||||
|
||||
def onCommand(self, command: str, extras: Any, cb: Any):
|
||||
pass
|
||||
|
||||
def onCustomAction(self, action: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onMediaButtonEvent(self, mediaButtonIntent: Any) -> bool:
|
||||
return False
|
||||
|
||||
def onPlayFromMediaId(self, mediaId: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onPlayFromSearch(self, query: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onPlayFromUri(self, uri: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onPrepare(self):
|
||||
pass
|
||||
|
||||
def onPrepareFromMediaId(self, mediaId: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onPrepareFromSearch(self, query: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onPrepareFromUri(self, uri: str, extras: Any):
|
||||
pass
|
||||
|
||||
def __init__(self, context: Any = None, tag: str = "",
|
||||
token: "SessionToken" = None):
|
||||
super().__init__()
|
||||
self._tag = tag
|
||||
self._token = token or SessionToken()
|
||||
self._active = False
|
||||
self._flags = 0
|
||||
self._session_activity: Any = None
|
||||
self._callback: Optional[MediaSession.Callback] = None
|
||||
self._metadata: Optional["MediaMetadata"] = None
|
||||
self._playback_state: Optional["PlaybackState"] = None
|
||||
self._queue: List["QueueItem"] = []
|
||||
self._queue_title: Optional[str] = None
|
||||
self._extras: Any = None
|
||||
self._rating_type = Rating.RATING_NONE
|
||||
self._repeat_mode = PlaybackState.REPEAT_MODE_NONE
|
||||
self._shuffle_mode = PlaybackState.SHUFFLE_MODE_NONE
|
||||
self._captioning_enabled = False
|
||||
self._controllers: List[MediaController] = []
|
||||
|
||||
def setSessionActivity(self, sessionActivity: Any):
|
||||
self._session_activity = sessionActivity
|
||||
|
||||
def sendSessionEvent(self, event: str, extras: Any):
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onSessionEvent(event, extras)
|
||||
|
||||
def release(self):
|
||||
self._active = False
|
||||
self._controllers.clear()
|
||||
|
||||
def getSessionToken(self) -> "SessionToken":
|
||||
return self._token
|
||||
|
||||
def setFlags(self, flags: int):
|
||||
self._flags = flags
|
||||
|
||||
def setPlaybackToLocal(self, volumeProvider: Any = None):
|
||||
pass
|
||||
|
||||
def setPlaybackToRemote(self, volumeProvider: Any):
|
||||
pass
|
||||
|
||||
def setActive(self, active: bool):
|
||||
self._active = active
|
||||
|
||||
def isActive(self) -> bool:
|
||||
return self._active
|
||||
|
||||
def setMediaMetadata(self, metadata: "MediaMetadata"):
|
||||
self._metadata = metadata
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onMetadataChanged(metadata)
|
||||
|
||||
def setPlaybackState(self, state: "PlaybackState"):
|
||||
self._playback_state = state
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onPlaybackStateChanged(state)
|
||||
|
||||
def setQueue(self, queue: List["QueueItem"]):
|
||||
self._queue = queue
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onQueueChanged(queue)
|
||||
|
||||
def setQueueTitle(self, title: str):
|
||||
self._queue_title = title
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onQueueTitleChanged(title)
|
||||
|
||||
def setExtras(self, extras: Any):
|
||||
self._extras = extras
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onExtrasChanged(extras)
|
||||
|
||||
def setMetadata(self, metadata: "MediaMetadata"):
|
||||
self.setMediaMetadata(metadata)
|
||||
|
||||
def setRatingType(self, ratingType: int):
|
||||
self._rating_type = ratingType
|
||||
|
||||
def setRepeatMode(self, repeatMode: int):
|
||||
self._repeat_mode = repeatMode
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onRepeatModeChanged(repeatMode)
|
||||
|
||||
def setShuffleMode(self, shuffleMode: int):
|
||||
self._shuffle_mode = shuffleMode
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onShuffleModeChanged(shuffleMode)
|
||||
|
||||
def setCaptioningEnabled(self, enabled: bool):
|
||||
self._captioning_enabled = enabled
|
||||
for ctrl in self._controllers:
|
||||
ctrl._callback.onCaptioningEnabledChanged(enabled)
|
||||
|
||||
def getController(self) -> "MediaController":
|
||||
ctrl = MediaController(self)
|
||||
self._controllers.append(ctrl)
|
||||
return ctrl
|
||||
|
||||
def getCallerPackageName(self) -> str:
|
||||
return "com.android.systemui"
|
||||
|
||||
def setCallback(self, callback: Callback, handler: Any = None):
|
||||
self._callback = callback
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# MediaController
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class MediaController(Stub):
|
||||
"""MediaController — 媒体控制器"""
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# Callback
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class Callback(Stub):
|
||||
"""MediaController.Callback — 控制器回调"""
|
||||
|
||||
def onSessionReady(self):
|
||||
pass
|
||||
|
||||
def onSessionDestroyed(self):
|
||||
pass
|
||||
|
||||
def onSessionEvent(self, event: str, extras: Any):
|
||||
pass
|
||||
|
||||
def onPlaybackStateChanged(self, state: "PlaybackState"):
|
||||
pass
|
||||
|
||||
def onMetadataChanged(self, metadata: "MediaMetadata"):
|
||||
pass
|
||||
|
||||
def onQueueChanged(self, queue: List["QueueItem"]):
|
||||
pass
|
||||
|
||||
def onQueueTitleChanged(self, title: str):
|
||||
pass
|
||||
|
||||
def onExtrasChanged(self, extras: Any):
|
||||
pass
|
||||
|
||||
def onAudioInfoChanged(self, info: Any):
|
||||
pass
|
||||
|
||||
def onCaptioningEnabledChanged(self, enabled: bool):
|
||||
pass
|
||||
|
||||
def onRepeatModeChanged(self, repeatMode: int):
|
||||
pass
|
||||
|
||||
def onShuffleModeChanged(self, shuffleMode: int):
|
||||
pass
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# TransportControls
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
class TransportControls(Stub):
|
||||
"""MediaController.TransportControls — 传输控制"""
|
||||
|
||||
def __init__(self, session: "MediaSession"):
|
||||
super().__init__()
|
||||
self._session = session
|
||||
|
||||
def play(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPlay()
|
||||
|
||||
def pause(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPause()
|
||||
|
||||
def stop(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onStop()
|
||||
|
||||
def fastForward(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onFastForward()
|
||||
|
||||
def rewind(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onRewind()
|
||||
|
||||
def skipToNext(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onSkipToNext()
|
||||
|
||||
def skipToPrevious(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onSkipToPrevious()
|
||||
|
||||
def seekTo(self, pos: int):
|
||||
if self._session._callback:
|
||||
self._session._callback.onSeekTo(pos)
|
||||
|
||||
def setRating(self, rating: "Rating"):
|
||||
if self._session._callback:
|
||||
self._session._callback.onSetRating(rating)
|
||||
|
||||
def setRepeatMode(self, repeatMode: int):
|
||||
if self._session._callback:
|
||||
self._session._callback.onSetRepeatMode(repeatMode)
|
||||
|
||||
def setShuffleMode(self, shuffleMode: int):
|
||||
if self._session._callback:
|
||||
self._session._callback.onSetShuffleMode(shuffleMode)
|
||||
|
||||
def sendCustomAction(self, action: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onCustomAction(action, extras)
|
||||
|
||||
def playFromMediaId(self, mediaId: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPlayFromMediaId(mediaId, extras)
|
||||
|
||||
def playFromSearch(self, query: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPlayFromSearch(query, extras)
|
||||
|
||||
def playFromUri(self, uri: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPlayFromUri(uri, extras)
|
||||
|
||||
def prepare(self):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPrepare()
|
||||
|
||||
def prepareFromMediaId(self, mediaId: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPrepareFromMediaId(mediaId, extras)
|
||||
|
||||
def prepareFromSearch(self, query: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPrepareFromSearch(query, extras)
|
||||
|
||||
def prepareFromUri(self, uri: str, extras: Any):
|
||||
if self._session._callback:
|
||||
self._session._callback.onPrepareFromUri(uri, extras)
|
||||
|
||||
def __init__(self, session: "MediaSession" = None):
|
||||
super().__init__()
|
||||
self._session = session
|
||||
self._callback = MediaController.Callback()
|
||||
self._transport_controls = MediaController.TransportControls(session)
|
||||
|
||||
def getSessionToken(self) -> "SessionToken":
|
||||
return self._session.getSessionToken() if self._session else SessionToken()
|
||||
|
||||
def getTransportControls(self) -> TransportControls:
|
||||
return self._transport_controls
|
||||
|
||||
def getPlaybackState(self) -> Optional["PlaybackState"]:
|
||||
return self._session._playback_state if self._session else None
|
||||
|
||||
def getMetadata(self) -> Optional["MediaMetadata"]:
|
||||
return self._session._metadata if self._session else None
|
||||
|
||||
def getQueueTitle(self) -> Optional[str]:
|
||||
return self._session._queue_title if self._session else None
|
||||
|
||||
def getQueue(self) -> List["QueueItem"]:
|
||||
return self._session._queue if self._session else []
|
||||
|
||||
def getRepeatMode(self) -> int:
|
||||
return self._session._repeat_mode if self._session else PlaybackState.REPEAT_MODE_NONE
|
||||
|
||||
def getShuffleMode(self) -> int:
|
||||
return self._session._shuffle_mode if self._session else PlaybackState.SHUFFLE_MODE_NONE
|
||||
|
||||
def getRatingType(self) -> int:
|
||||
return self._session._rating_type if self._session else Rating.RATING_NONE
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._session._extras if self._session else None
|
||||
|
||||
def getFlags(self) -> int:
|
||||
return self._session._flags if self._session else 0
|
||||
|
||||
def getPackageName(self) -> str:
|
||||
return self._session.getCallerPackageName() if self._session else ""
|
||||
|
||||
def getSessionActivity(self) -> Any:
|
||||
return self._session._session_activity if self._session else None
|
||||
|
||||
def registerCallback(self, callback: Callback, handler: Any = None):
|
||||
self._callback = callback
|
||||
|
||||
def unregisterCallback(self, callback: Callback):
|
||||
self._callback = MediaController.Callback()
|
||||
|
||||
def sendCommand(self, command: str, extras: Any, cb: Any):
|
||||
if self._session and self._session._callback:
|
||||
self._session._callback.onCommand(command, extras, cb)
|
||||
|
||||
def adjustVolume(self, direction: int, flags: int):
|
||||
pass
|
||||
|
||||
def setVolumeTo(self, value: int, flags: int):
|
||||
pass
|
||||
|
||||
def isSessionReady(self) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# PlaybackState
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class PlaybackState(Stub):
|
||||
"""PlaybackState — 播放状态"""
|
||||
|
||||
STATE_NONE = 0
|
||||
STATE_STOPPED = 1
|
||||
STATE_PAUSED = 2
|
||||
STATE_PLAYING = 3
|
||||
STATE_FAST_FORWARDING = 4
|
||||
STATE_REWINDING = 5
|
||||
STATE_BUFFERING = 6
|
||||
STATE_ERROR = 7
|
||||
STATE_CONNECTING = 8
|
||||
STATE_SKIPPING_TO_PREVIOUS = 9
|
||||
STATE_SKIPPING_TO_NEXT = 10
|
||||
STATE_SKIPPING_TO_QUEUE_ITEM = 11
|
||||
|
||||
ACTION_PLAY = 1 << 0
|
||||
ACTION_PAUSE = 1 << 1
|
||||
ACTION_PLAY_PAUSE = 1 << 2
|
||||
ACTION_STOP = 1 << 3
|
||||
ACTION_SEEK_TO = 1 << 4
|
||||
ACTION_FAST_FORWARD = 1 << 5
|
||||
ACTION_REWIND = 1 << 6
|
||||
ACTION_SKIP_TO_NEXT = 1 << 7
|
||||
ACTION_SKIP_TO_PREVIOUS = 1 << 8
|
||||
ACTION_SET_RATING = 1 << 9
|
||||
ACTION_SET_REPEAT_MODE = 1 << 10
|
||||
ACTION_SET_SHUFFLE_MODE = 1 << 11
|
||||
ACTION_SET_CAPTIONING_ENABLED = 1 << 12
|
||||
ACTION_SKIP_TO_QUEUE_ITEM = 1 << 13
|
||||
ACTION_PLAY_FROM_MEDIA_ID = 1 << 14
|
||||
ACTION_PLAY_FROM_SEARCH = 1 << 15
|
||||
ACTION_PREPARE = 1 << 16
|
||||
ACTION_PREPARE_FROM_MEDIA_ID = 1 << 17
|
||||
ACTION_PREPARE_FROM_SEARCH = 1 << 18
|
||||
ACTION_PREPARE_FROM_URI = 1 << 19
|
||||
ACTION_PLAY_FROM_URI = 1 << 20
|
||||
|
||||
REPEAT_MODE_NONE = 0
|
||||
REPEAT_MODE_ONE = 1
|
||||
REPEAT_MODE_ALL = 2
|
||||
REPEAT_MODE_GROUP = 3
|
||||
|
||||
SHUFFLE_MODE_NONE = 0
|
||||
SHUFFLE_MODE_ALL = 1
|
||||
SHUFFLE_MODE_GROUP = 2
|
||||
|
||||
class Builder(Stub):
|
||||
"""PlaybackState.Builder — 播放状态构建器"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._state = PlaybackState.STATE_NONE
|
||||
self._position = 0
|
||||
self._speed = 1.0
|
||||
self._actions = 0
|
||||
self._custom_actions: List[Any] = []
|
||||
self._active_queue_item_id = -1
|
||||
self._error_message: Optional[str] = None
|
||||
self._extras: Any = None
|
||||
self._buffered_position = 0
|
||||
|
||||
def setState(self, state: int, position: int, speed: float) -> "PlaybackState.Builder":
|
||||
self._state = state
|
||||
self._position = position
|
||||
self._speed = speed
|
||||
return self
|
||||
|
||||
def setActions(self, actions: int) -> "PlaybackState.Builder":
|
||||
self._actions = actions
|
||||
return self
|
||||
|
||||
def setCustomAction(self, action: str, name: str, icon: Any = None) -> "PlaybackState.Builder":
|
||||
self._custom_actions.append((action, name, icon))
|
||||
return self
|
||||
|
||||
def setActiveQueueItemId(self, id: int) -> "PlaybackState.Builder":
|
||||
self._active_queue_item_id = id
|
||||
return self
|
||||
|
||||
def setErrorMessage(self, error: str) -> "PlaybackState.Builder":
|
||||
self._error_message = error
|
||||
return self
|
||||
|
||||
def setExtras(self, extras: Any) -> "PlaybackState.Builder":
|
||||
self._extras = extras
|
||||
return self
|
||||
|
||||
def setBufferedPosition(self, bufferedPosition: int) -> "PlaybackState.Builder":
|
||||
self._buffered_position = bufferedPosition
|
||||
return self
|
||||
|
||||
def setPosition(self, position: int) -> "PlaybackState.Builder":
|
||||
self._position = position
|
||||
return self
|
||||
|
||||
def setSpeed(self, speed: float) -> "PlaybackState.Builder":
|
||||
self._speed = speed
|
||||
return self
|
||||
|
||||
def addCustomAction(self, action: "PlaybackState.CustomAction") -> "PlaybackState.Builder":
|
||||
self._custom_actions.append(action)
|
||||
return self
|
||||
|
||||
def build(self) -> "PlaybackState":
|
||||
ps = PlaybackState()
|
||||
ps._state = self._state
|
||||
ps._position = self._position
|
||||
ps._speed = self._speed
|
||||
ps._actions = self._actions
|
||||
ps._custom_actions = self._custom_actions
|
||||
ps._active_queue_item_id = self._active_queue_item_id
|
||||
ps._error_message = self._error_message
|
||||
ps._extras = self._extras
|
||||
ps._buffered_position = self._buffered_position
|
||||
return ps
|
||||
|
||||
class CustomAction(Stub):
|
||||
"""PlaybackState.CustomAction — 自定义操作"""
|
||||
|
||||
def __init__(self, action: str, name: str, icon: Any = None):
|
||||
super().__init__()
|
||||
self._action = action
|
||||
self._name = name
|
||||
self._icon = icon
|
||||
|
||||
def getAction(self) -> str:
|
||||
return self._action
|
||||
|
||||
def getName(self) -> str:
|
||||
return self._name
|
||||
|
||||
def getIcon(self) -> Any:
|
||||
return self._icon
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._state = PlaybackState.STATE_NONE
|
||||
self._position = 0
|
||||
self._speed = 1.0
|
||||
self._actions = 0
|
||||
self._custom_actions: List[Any] = []
|
||||
self._active_queue_item_id = -1
|
||||
self._error_message: Optional[str] = None
|
||||
self._extras: Any = None
|
||||
self._buffered_position = 0
|
||||
self._last_position_update_time = int(time.time() * 1000)
|
||||
|
||||
def getState(self) -> int:
|
||||
return self._state
|
||||
|
||||
def getPosition(self) -> int:
|
||||
return self._position
|
||||
|
||||
def getPlaybackSpeed(self) -> float:
|
||||
return self._speed
|
||||
|
||||
def getActions(self) -> int:
|
||||
return self._actions
|
||||
|
||||
def getCustomActions(self) -> List[Any]:
|
||||
return self._custom_actions
|
||||
|
||||
def getActiveQueueItemId(self) -> int:
|
||||
return self._active_queue_item_id
|
||||
|
||||
def getErrorMessage(self) -> Optional[str]:
|
||||
return self._error_message
|
||||
|
||||
def getExtras(self) -> Any:
|
||||
return self._extras
|
||||
|
||||
def getBufferedPosition(self) -> int:
|
||||
return self._buffered_position
|
||||
|
||||
def getLastPositionUpdateTime(self) -> int:
|
||||
return self._last_position_update_time
|
||||
|
||||
def toString(self) -> str:
|
||||
state_names = {
|
||||
PlaybackState.STATE_NONE: "NONE",
|
||||
PlaybackState.STATE_STOPPED: "STOPPED",
|
||||
PlaybackState.STATE_PAUSED: "PAUSED",
|
||||
PlaybackState.STATE_PLAYING: "PLAYING",
|
||||
}
|
||||
return f"PlaybackState(state={state_names.get(self._state, str(self._state))}," \
|
||||
f" pos={self._position})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# MediaMetadata
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class MediaMetadata(Stub):
|
||||
"""MediaMetadata — 媒体元数据"""
|
||||
|
||||
METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"
|
||||
METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"
|
||||
METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"
|
||||
METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"
|
||||
METADATA_KEY_ART = "android.media.metadata.ART"
|
||||
METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"
|
||||
METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"
|
||||
METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"
|
||||
METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"
|
||||
METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"
|
||||
METADATA_KEY_DATE = "android.media.metadata.DATE"
|
||||
METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"
|
||||
METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION"
|
||||
METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON"
|
||||
METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI"
|
||||
METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE"
|
||||
METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE"
|
||||
METADATA_KEY_DURATION = "android.media.metadata.DURATION"
|
||||
METADATA_KEY_GENRE = "android.media.metadata.GENRE"
|
||||
METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID"
|
||||
METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"
|
||||
METADATA_KEY_RATING = "android.media.metadata.RATING"
|
||||
METADATA_KEY_TITLE = "android.media.metadata.TITLE"
|
||||
METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"
|
||||
METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"
|
||||
METADATA_KEY_WRITER = "android.media.metadata.WRITER"
|
||||
METADATA_KEY_YEAR = "android.media.metadata.YEAR"
|
||||
|
||||
class Builder(Stub):
|
||||
"""MediaMetadata.Builder — 元数据构建器"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._data: Dict[str, Any] = {}
|
||||
|
||||
def putString(self, key: str, value: str) -> "MediaMetadata.Builder":
|
||||
self._data[key] = value
|
||||
return self
|
||||
|
||||
def putLong(self, key: str, value: int) -> "MediaMetadata.Builder":
|
||||
self._data[key] = value
|
||||
return self
|
||||
|
||||
def putBitmap(self, key: str, value: Any) -> "MediaMetadata.Builder":
|
||||
self._data[key] = value
|
||||
return self
|
||||
|
||||
def putText(self, key: str, value: str) -> "MediaMetadata.Builder":
|
||||
self._data[key] = value
|
||||
return self
|
||||
|
||||
def putRating(self, key: str, value: "Rating") -> "MediaMetadata.Builder":
|
||||
self._data[key] = value
|
||||
return self
|
||||
|
||||
def build(self) -> "MediaMetadata":
|
||||
mm = MediaMetadata()
|
||||
mm._data = dict(self._data)
|
||||
return mm
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._data: Dict[str, Any] = {}
|
||||
|
||||
def getString(self, key: str) -> Optional[str]:
|
||||
v = self._data.get(key)
|
||||
return str(v) if v is not None else None
|
||||
|
||||
def getLong(self, key: str) -> int:
|
||||
v = self._data.get(key, 0)
|
||||
try:
|
||||
return int(v)
|
||||
except (ValueError, TypeError):
|
||||
return 0
|
||||
|
||||
def getBitmap(self, key: str) -> Any:
|
||||
return self._data.get(key)
|
||||
|
||||
def getText(self, key: str) -> Optional[str]:
|
||||
return self.getString(key)
|
||||
|
||||
def getDescription(self) -> "MediaDescription":
|
||||
from .media_browse import MediaDescription
|
||||
builder = MediaDescription.Builder()
|
||||
title = self.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||
if title:
|
||||
builder.setTitle(title)
|
||||
artist = self.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
||||
if artist:
|
||||
builder.setSubtitle(artist)
|
||||
media_id = self.getString(MediaMetadata.METADATA_KEY_MEDIA_ID)
|
||||
if media_id:
|
||||
builder.setMediaId(media_id)
|
||||
return builder.build()
|
||||
|
||||
def getRating(self, key: str) -> Optional["Rating"]:
|
||||
v = self._data.get(key)
|
||||
return v if isinstance(v, Rating) else None
|
||||
|
||||
def getBitmapDescription(self) -> Any:
|
||||
return None
|
||||
|
||||
def containsKey(self, key: str) -> bool:
|
||||
return key in self._data
|
||||
|
||||
def keySet(self) -> Set[str]:
|
||||
return set(self._data.keys())
|
||||
|
||||
def getMediaId(self) -> Optional[str]:
|
||||
return self.getString(MediaMetadata.METADATA_KEY_MEDIA_ID)
|
||||
|
||||
def toString(self) -> str:
|
||||
title = self.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||
return f"MediaMetadata(title={title})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# QueueItem
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class QueueItem(Stub):
|
||||
"""QueueItem — 队列项"""
|
||||
|
||||
def __init__(self, description: "MediaDescription" = None, queueId: int = 0):
|
||||
super().__init__()
|
||||
self._description = description
|
||||
self._queue_id = queueId
|
||||
|
||||
def getDescription(self) -> "MediaDescription":
|
||||
return self._description
|
||||
|
||||
def getQueueId(self) -> int:
|
||||
return self._queue_id
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"QueueItem(id={self._queue_id}, desc={self._description})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# Rating
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class Rating(Stub):
|
||||
"""Rating — 评分"""
|
||||
|
||||
RATING_NONE = 0
|
||||
RATING_HEART = 1
|
||||
RATING_THUMB_UP_DOWN = 2
|
||||
RATING_3_STARS = 3
|
||||
RATING_4_STARS = 4
|
||||
RATING_5_STARS = 5
|
||||
RATING_PERCENTAGE = 6
|
||||
|
||||
def __init__(self, ratingStyle: int = RATING_NONE):
|
||||
super().__init__()
|
||||
self._rating_style = ratingStyle
|
||||
self._rated = False
|
||||
self._heart = False
|
||||
self._thumb_up = False
|
||||
self._star_rating = 0.0
|
||||
self._percent_rating = 0.0
|
||||
|
||||
@staticmethod
|
||||
def newHeartRating(hasHeart: bool) -> "Rating":
|
||||
r = Rating(Rating.RATING_HEART)
|
||||
r._rated = True
|
||||
r._heart = hasHeart
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def newThumbRating(thumbUp: bool) -> "Rating":
|
||||
r = Rating(Rating.RATING_THUMB_UP_DOWN)
|
||||
r._rated = True
|
||||
r._thumb_up = thumbUp
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def newStarRating(starRatingStyle: int, starRating: float) -> "Rating":
|
||||
r = Rating(starRatingStyle)
|
||||
r._rated = True
|
||||
r._star_rating = starRating
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def newPercentageRating(percent: float) -> "Rating":
|
||||
r = Rating(Rating.RATING_PERCENTAGE)
|
||||
r._rated = True
|
||||
r._percent_rating = percent
|
||||
return r
|
||||
|
||||
@staticmethod
|
||||
def newUnratedRating(ratingStyle: int) -> "Rating":
|
||||
return Rating(ratingStyle)
|
||||
|
||||
def isRated(self) -> bool:
|
||||
return self._rated
|
||||
|
||||
def getRatingStyle(self) -> int:
|
||||
return self._rating_style
|
||||
|
||||
def hasHeart(self) -> bool:
|
||||
return self._heart
|
||||
|
||||
def isThumbUp(self) -> bool:
|
||||
return self._thumb_up
|
||||
|
||||
def getStarRating(self) -> float:
|
||||
return self._star_rating
|
||||
|
||||
def getPercentRating(self) -> float:
|
||||
return self._percent_rating
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"Rating(style={self._rating_style}, rated={self._rated})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# SessionToken
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class SessionToken(Stub):
|
||||
"""SessionToken — 会话令牌"""
|
||||
|
||||
TYPE_SESSION = 0
|
||||
|
||||
def __init__(self, type_: int = TYPE_SESSION):
|
||||
super().__init__()
|
||||
self._type = type_
|
||||
self._binder = None
|
||||
|
||||
def getType(self) -> int:
|
||||
return self._type
|
||||
|
||||
def getSessionBinder(self) -> Any:
|
||||
return self._binder
|
||||
|
||||
def toString(self) -> str:
|
||||
return f"SessionToken(type={self._type})"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# __all__
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
__all__ = [
|
||||
"MediaSession",
|
||||
"MediaController",
|
||||
"PlaybackState",
|
||||
"MediaMetadata",
|
||||
"QueueItem",
|
||||
"Rating",
|
||||
"SessionToken",
|
||||
]
|
||||
Reference in new issue
Block a user