""" Android OverlayManager API — OverlayManager, OverlayInfo, OverlayManagerTransaction, OverlayStore 方法签名完全对齐 Android SDK """ from __future__ import annotations import os import time import json import uuid import threading from typing import Any, Dict, List, Optional, Set, Tuple from .._core import Stub, AndroidOnlyError from ..java.lang import RuntimeException IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {}) # ═══════════════════════════════════════════════════════════════ # 常量 # ═══════════════════════════════════════════════════════════════ # CATEGORY_* 常量 CATEGORY_ALL = "android.overlay.category.ALL" CATEGORY_FONT = "android.overlay.category.FONT" CATEGORY_THEME = "android.overlay.category.THEME" CATEGORY_ICON = "android.overlay.category.ICON" CATEGORY_ICON_OVERLAY = "android.overlay.category.ICON_OVERLAY" CATEGORY_SOUND = "android.overlay.category.SOUND" CATEGORY_BOOT_ANIMATION = "android.overlay.category.BOOT_ANIMATION" CATEGORY_WALLPAPER = "android.overlay.category.WALLPAPER" CATEGORY_DYNAMIC = "android.overlay.category.DYNAMIC" CATEGORY_RRO = "android.overlay.category.RRO" CATEGORY_STATIC = "android.overlay.category.STATIC" # STATE_* 常量 STATE_UNKNOWN = 0 STATE_NOT_INSTALLED = 1 STATE_INSTALLED = 2 STATE_ENABLED = 3 STATE_DISABLED = 4 STATE_ENABLEMENT_DISABLED = 5 STATE_ENABLEMENT_ENABLED = 6 STATE_ENABLEMENT_UNKNOWN = 7 STATE_OVERLAY_NOT_FOUND = 8 STATE_OVERLAY_UPGRADING = 9 STATE_OVERLAY_REMOVED = 10 STATE_PACKAGE_INSTALLED = 11 STATE_PACKAGE_UPDATED = 12 STATE_PACKAGE_REMOVED = 13 STATE_TARGET_PACKAGE_CHANGED = 14 STATE_MISSING_TARGET_PACKAGE = 15 STATE_UPGRADE_PENDING = 16 # FLAG_* 常量 FLAG_ENABLE = 0x00000001 FLAG_DISABLE = 0x00000002 FLAG_REMOVE = 0x00000004 FLAG_UPGRADE = 0x00000008 FLAG_INSTALL = 0x00000010 FLAG_IMMUTABLE = 0x00000020 FLAG_SYSTEM = 0x00000040 FLAG_STATIC_OVERLAY = 0x00000080 FLAG_DYNAMIC_OVERLAY = 0x00000100 FLAG_FIRST_TARGET = 0x00000200 FLAG_LAST_TARGET = 0x00000400 FLAG_EXTERNAL = 0x00000800 FLAG_PERSISTENT = 0x00001000 # PRIORITY_ORDER 常量 PRIORITY_ORDER_UNDEFINED = 0 PRIORITY_ORDER_LOWEST = 1 PRIORITY_ORDER_LOW = 2 PRIORITY_ORDER_MEDIUM = 3 PRIORITY_ORDER_HIGH = 4 PRIORITY_ORDER_HIGHEST = 5 # ═══════════════════════════════════════════════════════════════ # OverlayInfo # ═══════════════════════════════════════════════════════════════ class OverlayInfo(Stub): """OverlayInfo — 覆盖层信息""" CATEGORY_ALL = CATEGORY_ALL CATEGORY_FONT = CATEGORY_FONT CATEGORY_THEME = CATEGORY_THEME CATEGORY_ICON = CATEGORY_ICON CATEGORY_ICON_OVERLAY = CATEGORY_ICON_OVERLAY CATEGORY_SOUND = CATEGORY_SOUND CATEGORY_BOOT_ANIMATION = CATEGORY_BOOT_ANIMATION CATEGORY_WALLPAPER = CATEGORY_WALLPAPER CATEGORY_DYNAMIC = CATEGORY_DYNAMIC STATE_UNKNOWN = STATE_UNKNOWN STATE_NOT_INSTALLED = STATE_NOT_INSTALLED STATE_INSTALLED = STATE_INSTALLED STATE_ENABLED = STATE_ENABLED STATE_DISABLED = STATE_DISABLED STATE_ENABLEMENT_DISABLED = STATE_ENABLEMENT_DISABLED STATE_ENABLEMENT_ENABLED = STATE_ENABLEMENT_ENABLED STATE_ENABLEMENT_UNKNOWN = STATE_ENABLEMENT_UNKNOWN STATE_OVERLAY_NOT_FOUND = STATE_OVERLAY_NOT_FOUND STATE_OVERLAY_UPGRADING = STATE_OVERLAY_UPGRADING STATE_PACKAGE_INSTALLED = STATE_PACKAGE_INSTALLED STATE_PACKAGE_UPDATED = STATE_PACKAGE_UPDATED STATE_PACKAGE_REMOVED = STATE_PACKAGE_REMOVED STATE_TARGET_PACKAGE_CHANGED = STATE_TARGET_PACKAGE_CHANGED STATE_UPGRADE_PENDING = STATE_UPGRADE_PENDING def __init__( self, packageName: str = "", targetPackageName: str = "", category: str = CATEGORY_THEME, state: int = STATE_UNKNOWN, ): super().__init__() self._package_name = packageName self._target_package_name = targetPackageName self._category = category self._state = state self._is_enabled = (state == STATE_ENABLED or state == STATE_ENABLEMENT_ENABLED) self._priority = 0 self._is_static = False self._is_upgradable = False self._is_system = False self._version = 0 self._config: Optional[str] = None self._label: Optional[str] = None self._icon: Optional[Any] = None self._fabricated = False self._overlay_path: Optional[str] = None self._target_overlayable_name: Optional[str] = None self._require_all = False self._overlay_category: Optional[str] = category self._base_path: Optional[str] = None self._overlay_id = str(uuid.uuid4()) self._install_time = time.time() self._mod_time = time.time() def getPackageName(self) -> str: return self._package_name def getTargetPackageName(self) -> str: return self._target_package_name def getCategory(self) -> str: return self._category def getState(self) -> int: return self._state def setState(self, state: int) -> None: self._state = state self._is_enabled = (state == STATE_ENABLED) def isEnabled(self) -> bool: return self._is_enabled def getPriority(self) -> int: return self._priority def setPriority(self, priority: int) -> None: self._priority = priority def isStatic(self) -> bool: return self._is_static def isUpgradable(self) -> bool: return self._is_upgradable def isSystem(self) -> bool: return self._is_system def getVersion(self) -> int: return self._version def getLabel(self) -> Optional[str]: return self._label def getIcon(self) -> Optional[Any]: return self._icon def isFabricated(self) -> bool: return self._fabricated def getOverlayPath(self) -> Optional[str]: return self._overlay_path def getTargetOverlayableName(self) -> Optional[str]: return self._target_overlayable_name def getOverlayId(self) -> str: return self._overlay_id def getInstallTime(self) -> float: return self._install_time def getModTime(self) -> float: return self._mod_time def getConfig(self) -> Optional[str]: return self._config def requiresAll(self) -> bool: return self._require_all def toString(self) -> str: return ( f"OverlayInfo(package={self._package_name}, " f"target={self._target_package_name}, " f"category={self._category}, " f"state={self._state})" ) # ═══════════════════════════════════════════════════════════════ # OverlayManagerTransaction # ═══════════════════════════════════════════════════════════════ class OverlayManagerTransaction(Stub): """OverlayManagerTransaction — 覆盖层管理器事务""" TYPE_UNKNOWN = 0 TYPE_SET_ENABLED = 1 TYPE_SET_DISABLED = 2 TYPE_REGISTER = 3 TYPE_UNREGISTER = 4 TYPE_SET_PRIORITY = 5 TYPE_SET_CATEGORY = 6 TYPE_SET_TARGET = 7 TYPE_REMOVE = 8 TYPE_SET_STATE = 9 def __init__(self): super().__init__() self._operations: List[Dict[str, Any]] = [] self._transaction_id = str(uuid.uuid4()) self._created_at = time.time() self._committed = False self._rollback_on_failure = True def setEnabled(self, packageName: str, enabled: bool) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_SET_ENABLED, "packageName": packageName, "enabled": enabled, }) return self def setDisabled(self, packageName: str) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_SET_DISABLED, "packageName": packageName, }) return self def registerOverlay(self, packageName: str) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_REGISTER, "packageName": packageName, }) return self def unregisterOverlay(self, packageName: str) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_UNREGISTER, "packageName": packageName, }) return self def setPriority(self, packageName: str, priority: int) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_SET_PRIORITY, "packageName": packageName, "priority": priority, }) return self def setCategory(self, packageName: str, category: str) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_SET_CATEGORY, "packageName": packageName, "category": category, }) return self def setTarget(self, packageName: str, target: str) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_SET_TARGET, "packageName": packageName, "target": target, }) return self def removeOverlay(self, packageName: str) -> "OverlayManagerTransaction": self._operations.append({ "type": OverlayManagerTransaction.TYPE_REMOVE, "packageName": packageName, }) return self def getOperations(self) -> List[Dict[str, Any]]: return list(self._operations) def getTransactionId(self) -> str: return self._transaction_id def isCommitted(self) -> bool: return self._committed def getOperationCount(self) -> int: return len(self._operations) def toString(self) -> str: return f"OverlayManagerTransaction(ops={len(self._operations)}, committed={self._committed})" # ═══════════════════════════════════════════════════════════════ # OverlayStore # ═══════════════════════════════════════════════════════════════ class OverlayStore(Stub): """OverlayStore — 覆盖层存储""" def __init__(self): super().__init__() self._overlays: Dict[str, OverlayInfo] = {} self._lock = threading.Lock() self._store_path: Optional[str] = None self._max_overlays = 100 self._persist_enabled = False def getOverlay(self, packageName: str) -> Optional[OverlayInfo]: with self._lock: return self._overlays.get(packageName) def getAllOverlays(self) -> List[OverlayInfo]: with self._lock: return list(self._overlays.values()) def getOverlaysForTarget(self, targetPackage: str) -> List[OverlayInfo]: with self._lock: return [ info for info in self._overlays.values() if info.getTargetPackageName() == targetPackage ] def getOverlaysByCategory(self, category: str) -> List[OverlayInfo]: with self._lock: return [ info for info in self._overlays.values() if info.getCategory() == category ] def addOverlay(self, info: OverlayInfo) -> None: with self._lock: self._overlays[info.getPackageName()] = info def removeOverlay(self, packageName: str) -> Optional[OverlayInfo]: with self._lock: return self._overlays.pop(packageName, None) def updateOverlay(self, packageName: str, info: OverlayInfo) -> bool: with self._lock: if packageName in self._overlays: self._overlays[packageName] = info return True return False def contains(self, packageName: str) -> bool: with self._lock: return packageName in self._overlays def getEnabledOverlays(self) -> List[OverlayInfo]: with self._lock: return [info for info in self._overlays.values() if info.isEnabled()] def getDisabledOverlays(self) -> List[OverlayInfo]: with self._lock: return [info for info in self._overlays.values() if not info.isEnabled()] def getStaticOverlays(self) -> List[OverlayInfo]: with self._lock: return [info for info in self._overlays.values() if info.isStatic()] def getOverlayCount(self) -> int: with self._lock: return len(self._overlays) def clear(self) -> None: with self._lock: self._overlays.clear() def toString(self) -> str: with self._lock: return f"OverlayStore(overlays={len(self._overlays)})" # ═══════════════════════════════════════════════════════════════ # OverlayManager # ═══════════════════════════════════════════════════════════════ class OverlayManager(Stub): """OverlayManager — 覆盖层管理器 (桌面存根)""" CATEGORY_ALL = CATEGORY_ALL CATEGORY_FONT = CATEGORY_FONT CATEGORY_THEME = CATEGORY_THEME CATEGORY_ICON = CATEGORY_ICON CATEGORY_SOUND = CATEGORY_SOUND FLAG_ENABLE = FLAG_ENABLE FLAG_DISABLE = FLAG_DISABLE FLAG_REMOVE = FLAG_REMOVE FLAG_UPGRADE = FLAG_UPGRADE FLAG_INSTALL = FLAG_INSTALL FLAG_IMMUTABLE = FLAG_IMMUTABLE FLAG_SYSTEM = FLAG_SYSTEM FLAG_STATIC_OVERLAY = FLAG_STATIC_OVERLAY FLAG_DYNAMIC_OVERLAY = FLAG_DYNAMIC_OVERLAY FLAG_EXTERNAL = FLAG_EXTERNAL FLAG_PERSISTENT = FLAG_PERSISTENT STATE_UNKNOWN = STATE_UNKNOWN STATE_NOT_INSTALLED = STATE_NOT_INSTALLED STATE_INSTALLED = STATE_INSTALLED STATE_ENABLED = STATE_ENABLED STATE_DISABLED = STATE_DISABLED STATE_ENABLEMENT_DISABLED = STATE_ENABLEMENT_DISABLED STATE_ENABLEMENT_ENABLED = STATE_ENABLEMENT_ENABLED STATE_ENABLEMENT_UNKNOWN = STATE_ENABLEMENT_UNKNOWN STATE_OVERLAY_NOT_FOUND = STATE_OVERLAY_NOT_FOUND STATE_OVERLAY_UPGRADING = STATE_OVERLAY_UPGRADING def __init__(self, context: Any = None): super().__init__() self._context = context self._store = OverlayStore() self._lock = threading.Lock() self._transaction_history: List[OverlayManagerTransaction] = [] self._callbacks: Dict[str, List[Callable]] = {} self._is_available = True def getOverlayInfo(self, packageName: str) -> Optional[OverlayInfo]: with self._lock: return self._store.getOverlay(packageName) def getAllOverlays(self) -> List[OverlayInfo]: with self._lock: return self._store.getAllOverlays() def getOverlaysForTarget(self, targetPackage: str) -> List[OverlayInfo]: with self._lock: return self._store.getOverlaysForTarget(targetPackage) def setEnabled(self, packageName: str, enabled: bool, userId: int = 0) -> None: with self._lock: info = self._store.getOverlay(packageName) if info: new_state = STATE_ENABLED if enabled else STATE_DISABLED info.setState(new_state) def setEnabledExclusive( self, packageName: str, withinCategory: bool, userId: int = 0 ) -> None: with self._lock: info = self._store.getOverlay(packageName) if info: info.setState(STATE_ENABLED) category = info.getCategory() for overlay in self._store.getAllOverlays(): if overlay.getPackageName() != packageName: if withinCategory and overlay.getCategory() == category: overlay.setState(STATE_DISABLED) elif not withinCategory: overlay.setState(STATE_DISABLED) def isEnabled(self, packageName: str) -> bool: with self._lock: info = self._store.getOverlay(packageName) return info is not None and info.isEnabled() def commit( self, transaction: OverlayManagerTransaction ) -> None: with self._lock: for op in transaction.getOperations(): op_type = op.get("type") pkg = op.get("packageName", "") if op_type == OverlayManagerTransaction.TYPE_SET_ENABLED: self.setEnabled(pkg, op.get("enabled", True)) elif op_type == OverlayManagerTransaction.TYPE_SET_DISABLED: self.setEnabled(pkg, False) elif op_type == OverlayManagerTransaction.TYPE_REGISTER: info = OverlayInfo(packageName=pkg) self._store.addOverlay(info) elif op_type == OverlayManagerTransaction.TYPE_UNREGISTER: self._store.removeOverlay(pkg) elif op_type == OverlayManagerTransaction.TYPE_SET_PRIORITY: info = self._store.getOverlay(pkg) if info: info.setPriority(op.get("priority", 0)) elif op_type == OverlayManagerTransaction.TYPE_REMOVE: self._store.removeOverlay(pkg) self._transaction_history.append(transaction) def getDefaultOverlayPackages(self) -> List[str]: return [] def getOverlayInfosForTarget(self, targetPackage: str, userId: int = 0) -> List[OverlayInfo]: return self.getOverlaysForTarget(targetPackage) def getOverlayStore(self) -> OverlayStore: return self._store def registerCallback(self, callback: Any) -> None: pass def unregisterCallback(self, callback: Any) -> None: pass def onOverlayChanged(self, packageName: str) -> None: pass def onOverlayStateChanged(self, packageName: str, newState: int) -> None: pass def isUpgradePending(self, packageName: str) -> bool: return False def getCategoryForOverlay(self, packageName: str) -> Optional[str]: with self._lock: info = self._store.getOverlay(packageName) return info.getCategory() if info else None def getPriority(self, packageName: str) -> int: with self._lock: info = self._store.getOverlay(packageName) return info.getPriority() if info else 0 def toString(self) -> str: with self._lock: return ( f"OverlayManager(overlays={self._store.getOverlayCount()}, " f"transactions={len(self._transaction_history)})" )