""" Android View 扩展组件 — ViewOutlineProvider, ViewPropertyAnimator, ViewStructure 等 方法签名完全对齐 Android SDK """ from __future__ import annotations import math import time import weakref import threading from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union from .._core import Stub, AndroidOnlyError from ..java.lang import RuntimeException from .view import KeyEvent as _BaseKeyEvent # ═══════════════════════════════════════════════════════════════ # ViewOutlineProvider # ═══════════════════════════════════════════════════════════════ class ViewOutlineProvider(Stub): """ViewOutlineProvider — 视图轮廓提供者""" BACKGROUND = None BOUNDS = None PADDED_BOUNDS = None def __init__(self): super().__init__() def getOutline(self, view: Any, outline: Any) -> None: """获取视图轮廓""" pass ViewOutlineProvider.BACKGROUND = ViewOutlineProvider() ViewOutlineProvider.BOUNDS = ViewOutlineProvider() ViewOutlineProvider.PADDED_BOUNDS = ViewOutlineProvider() class Outline(Stub): """Outline — 轮廓描述""" MODE_CONVEX_PATH = 2 MODE_EMPTY = 0 MODE_ROUND_RECT = 1 def __init__(self): super().__init__() self._alpha: float = 1.0 self._mode: int = self.MODE_EMPTY self._rect: Tuple[float, float, float, float] = (0, 0, 0, 0) self._radius: float = 0.0 def setAlpha(self, alpha: float) -> None: self._alpha = max(0.0, min(1.0, alpha)) def getAlpha(self) -> float: return self._alpha def setEmpty(self) -> None: self._mode = self.MODE_EMPTY def isEmpty(self) -> bool: return self._mode == self.MODE_EMPTY def setRoundRect(self, left: float, top: float, right: float, bottom: float, radius: float) -> None: self._mode = self.MODE_ROUND_RECT self._rect = (left, top, right, bottom) self._radius = radius def setOval(self, left: float, top: float, right: float, bottom: float) -> None: self._mode = self.MODE_ROUND_RECT self._rect = (left, top, right, bottom) self._radius = min(right - left, bottom - top) / 2.0 def setConvexPath(self, path: Any) -> None: self._mode = self.MODE_CONVEX_PATH def getRect(self) -> Optional[Tuple[float, float, float, float]]: if self._mode == self.MODE_EMPTY: return None return self._rect def getRadius(self) -> float: return self._radius def canClip(self) -> bool: return self._mode in (self.MODE_ROUND_RECT, self.MODE_CONVEX_PATH) def toString(self) -> str: return (f"Outline(mode={self._mode}, alpha={self._alpha}, " f"radius={self._radius})") # ═══════════════════════════════════════════════════════════════ # ViewPropertyAnimator # ═══════════════════════════════════════════════════════════════ class ViewPropertyAnimator(Stub): """ViewPropertyAnimator — 视图属性动画器""" def __init__(self, view: Any = None): super().__init__() self._view = weakref.ref(view) if view is not None else None self._duration: int = 300 self._start_delay: int = 0 self._interpolator: Optional[Any] = None self._listener: Optional[Callable] = None self._translation_x: Optional[float] = None self._translation_y: Optional[float] = None self._translation_z: Optional[float] = None self._scale_x: Optional[float] = None self._scale_y: Optional[float] = None self._rotation: Optional[float] = None self._rotation_x: Optional[float] = None self._rotation_y: Optional[float] = None self._alpha: Optional[float] = None self._x: Optional[float] = None self._y: Optional[float] = None self._width: Optional[int] = None self._height: Optional[int] = None self._running = False def translationX(self, value: float) -> "ViewPropertyAnimator": self._translation_x = value return self def translationY(self, value: float) -> "ViewPropertyAnimator": self._translation_y = value return self def translationZ(self, value: float) -> "ViewPropertyAnimator": self._translation_z = value return self def rotation(self, value: float) -> "ViewPropertyAnimator": self._rotation = value return self def rotationX(self, value: float) -> "ViewPropertyAnimator": self._rotation_x = value return self def rotationY(self, value: float) -> "ViewPropertyAnimator": self._rotation_y = value return self def scaleX(self, value: float) -> "ViewPropertyAnimator": self._scale_x = value return self def scaleY(self, value: float) -> "ViewPropertyAnimator": self._scale_y = value return self def alpha(self, value: float) -> "ViewPropertyAnimator": self._alpha = max(0.0, min(1.0, value)) return self def x(self, value: float) -> "ViewPropertyAnimator": self._x = value return self def y(self, value: float) -> "ViewPropertyAnimator": self._y = value return self def width(self, value: int) -> "ViewPropertyAnimator": self._width = value return self def height(self, value: int) -> "ViewPropertyAnimator": self._height = value return self def setDuration(self, duration: int) -> "ViewPropertyAnimator": self._duration = max(0, duration) return self def getDuration(self) -> int: return self._duration def setStartDelay(self, delay: int) -> "ViewPropertyAnimator": self._start_delay = max(0, delay) return self def getStartDelay(self) -> int: return self._start_delay def setInterpolator(self, interpolator: Any) -> "ViewPropertyAnimator": self._interpolator = interpolator return self def setListener(self, listener: Optional[Callable]) -> "ViewPropertyAnimator": self._listener = listener return self def withEndAction(self, action: Callable) -> "ViewPropertyAnimator": self._end_action = action return self def withStartAction(self, action: Callable) -> "ViewPropertyAnimator": self._start_action = action return self def start(self) -> None: if self._running: return self._running = True if self._start_action: self._start_action() if self._listener: self._listener.onAnimationStart(self) if self._alpha is not None and self._view: v = self._view() if v: v.setAlpha(self._alpha) if self._listener: self._listener.onAnimationEnd(self) if self._end_action: self._end_action() def cancel(self) -> None: self._running = False if self._listener: self._listener.onAnimationCancel(self) def isRunning(self) -> bool: return self._running def toString(self) -> str: return (f"ViewPropertyAnimator(duration={self._duration}, " f"running={self._running})") # ═══════════════════════════════════════════════════════════════ # ViewStructure # ═══════════════════════════════════════════════════════════════ class ViewStructure(Stub): """ViewStructure — 视图结构(用于 Assist/autofill)""" def __init__(self): super().__init__() self._text: Optional[str] = None self._hint: Optional[str] = None self._className: Optional[str] = None self._contentDescription: Optional[str] = None self._id: Optional[int] = None self._id_package: Optional[str] = None self._id_type: Optional[str] = None self._id_entry: Optional[str] = None self._web_domain: Optional[str] = None self._input_type: int = 0 self._alpha: float = 1.0 self._elevation: float = 0.0 self._width: int = 0 self._height: int = 0 self._left: int = 0 self._top: int = 0 self._scroll_x: int = 0 self._scroll_y: int = 0 self._children: List[ViewStructure] = [] self._html_info: Optional[Any] = None self._data_set: Optional[Any] = None def setText(self, text: str) -> None: self._text = text def getText(self) -> Optional[str]: return self._text def setHint(self, hint: str) -> None: self._hint = hint def getHint(self) -> Optional[str]: return self._hint def setClassName(self, class_name: str) -> None: self._className = class_name def getClassName(self) -> Optional[str]: return self._className def setContentDescription(self, desc: str) -> None: self._contentDescription = desc def getContentDescription(self) -> Optional[str]: return self._contentDescription def setId(self, id_val: int, package: str, type_name: str, entry: str) -> None: self._id = id_val self._id_package = package self._id_type = type_name self._id_entry = entry def getAutoFillId(self) -> Optional[int]: return self._id def setWebDomain(self, domain: str) -> None: self._web_domain = domain def getWebDomain(self) -> Optional[str]: return self._web_domain def setInputType(self, input_type: int) -> None: self._input_type = input_type def getInputType(self) -> int: return self._input_type def setAlpha(self, alpha: float) -> None: self._alpha = max(0.0, min(1.0, alpha)) def getAlpha(self) -> float: return self._alpha def setElevation(self, elevation: float) -> None: self._elevation = elevation def getElevation(self) -> float: return self._elevation def setDimensions(self, width: int, height: int) -> None: self._width = width self._height = height def setDimens(self, left: int, top: int, scroll_x: int, scroll_y: int) -> None: self._left = left self._top = top self._scroll_x = scroll_x self._scroll_y = scroll_y def getWidth(self) -> int: return self._width def getHeight(self) -> int: return self._height def getLeft(self) -> int: return self._left def getTop(self) -> int: return self._top def addChild(self, num: int) -> ViewStructure: for _ in range(num): child = ViewStructure() self._children.append(child) return self._children[0] if self._children else ViewStructure() def getChildCount(self) -> int: return len(self._children) def getChildAt(self, index: int) -> Optional[ViewStructure]: if 0 <= index < len(self._children): return self._children[index] return None def setAutofillHints(self, hints: List[str]) -> None: pass def setAutofillType(self, type_val: int) -> None: pass def setAutofillValue(self, value: Any) -> None: pass def setDataIsSensitive(self, sensitive: bool) -> None: pass def toString(self) -> str: return (f"ViewStructure(class={self._className}, " f"children={len(self._children)})") # ═══════════════════════════════════════════════════════════════ # ViewTreeObserver # ═══════════════════════════════════════════════════════════════ class ViewTreeObserver(Stub): """ViewTreeObserver — 视图树观察者""" def __init__(self): super().__init__() self._global_layout_listeners: List[Callable] = [] self._global_focus_listeners: List[Callable] = [] self._pre_draw_listeners: List[Callable] = [] self._scroll_listeners: List[Callable] = [] self._touch_mode_listeners: List[Callable] = [] self._window_focus_listeners: List[Callable] = [] self._window_attach_listeners: List[Callable] = [] self._draw_listeners: List[Callable] = [] self._lock = threading.Lock() def addOnGlobalLayoutListener(self, listener: Callable) -> None: with self._lock: if listener not in self._global_layout_listeners: self._global_layout_listeners.append(listener) def removeOnGlobalLayoutListener(self, listener: Callable) -> None: with self._lock: if listener in self._global_layout_listeners: self._global_layout_listeners.remove(listener) def addOnGlobalFocusChangeListener(self, listener: Callable) -> None: with self._lock: if listener not in self._global_focus_listeners: self._global_focus_listeners.append(listener) def removeOnGlobalFocusChangeListener(self, listener: Callable) -> None: with self._lock: if listener in self._global_focus_listeners: self._global_focus_listeners.remove(listener) def addOnPreDrawListener(self, listener: Callable) -> None: with self._lock: if listener not in self._pre_draw_listeners: self._pre_draw_listeners.append(listener) def removeOnPreDrawListener(self, listener: Callable) -> None: with self._lock: if listener in self._pre_draw_listeners: self._pre_draw_listeners.remove(listener) def addOnScrollChangedListener(self, listener: Callable) -> None: with self._lock: if listener not in self._scroll_listeners: self._scroll_listeners.append(listener) def removeOnScrollChangedListener(self, listener: Callable) -> None: with self._lock: if listener in self._scroll_listeners: self._scroll_listeners.remove(listener) def addOnTouchModeChangeListener(self, listener: Callable) -> None: with self._lock: if listener not in self._touch_mode_listeners: self._touch_mode_listeners.append(listener) def removeOnTouchModeChangeListener(self, listener: Callable) -> None: with self._lock: if listener in self._touch_mode_listeners: self._touch_mode_listeners.remove(listener) def addOnWindowFocusChangeListener(self, listener: Callable) -> None: with self._lock: if listener not in self._window_focus_listeners: self._window_focus_listeners.append(listener) def removeOnWindowFocusChangeListener(self, listener: Callable) -> None: with self._lock: if listener in self._window_focus_listeners: self._window_focus_listeners.remove(listener) def addOnWindowAttachListener(self, listener: Callable) -> None: with self._lock: if listener not in self._window_attach_listeners: self._window_attach_listeners.append(listener) def removeOnWindowAttachListener(self, listener: Callable) -> None: with self._lock: if listener in self._window_attach_listeners: self._window_attach_listeners.remove(listener) def addOnDrawListener(self, listener: Callable) -> None: with self._lock: if listener not in self._draw_listeners: self._draw_listeners.append(listener) def removeOnDrawListener(self, listener: Callable) -> None: with self._lock: if listener in self._draw_listeners: self._draw_listeners.remove(listener) def dispatchOnGlobalLayout(self) -> None: with self._lock: listeners = list(self._global_layout_listeners) for listener in listeners: listener() def isAlive(self) -> bool: return True def toString(self) -> str: return (f"ViewTreeObserver(layoutListeners={len(self._global_layout_listeners)}, " f"preDrawListeners={len(self._pre_draw_listeners)})") # ═══════════════════════════════════════════════════════════════ # ViewDebug # ═══════════════════════════════════════════════════════════════ class ViewDebug(Stub): """ViewDebug — 视图调试工具""" TRACE_HIERARCHY = 0 TRACE_CAPTURE = 1 @staticmethod def dump(view: Any, out: Any) -> None: pass @staticmethod def dumpCapturedView(view: Any, out: Any, prefix: str) -> None: pass @staticmethod def trace(view: Any, type_val: int, out: Any) -> None: pass @staticmethod def startRecyclerTracing() -> None: pass @staticmethod def stopRecyclerTracing() -> None: pass class RecyclerTraceable(Stub): def getTraceInfo(self) -> str: return "" # ═══════════════════════════════════════════════════════════════ # ViewConfiguration # ═══════════════════════════════════════════════════════════════ class ViewConfiguration(Stub): """ViewConfiguration — 视图配置""" def __init__(self): super().__init__() self._scaled_touch_slop: int = 8 self._scaled_double_tap_slop: int = 100 self._scaled_edge_slop: int = 12 self._scaled_fading_edge_length: int = 12 self._scaled_minimum_fling_velocity: int = 50 self._scaled_maximum_fling_velocity: int = 4000 self._scaled_scroll_bar_size: int = 10 self._scaled_over_scroll_distance: int = 0 self._scaled_paging_touch_slop: int = 16 self._scaled_drawing_cache_size: int = 480 @staticmethod def get(context: Any) -> "ViewConfiguration": return ViewConfiguration() def getScaledTouchSlop(self) -> int: return self._scaled_touch_slop def getScaledDoubleTapSlop(self) -> int: return self._scaled_double_tap_slop def getScaledEdgeSlop(self) -> int: return self._scaled_edge_slop def getScaledFadingEdgeLength(self) -> int: return self._scaled_fading_edge_length def getScaledMinimumFlingVelocity(self) -> int: return self._scaled_minimum_fling_velocity def getScaledMaximumFlingVelocity(self) -> int: return self._scaled_maximum_fling_velocity def getScaledScrollBarSize(self) -> int: return self._scaled_scroll_bar_size def getScaledOverScrollDistance(self) -> int: return self._scaled_over_scroll_distance def getScaledPagingTouchSlop(self) -> int: return self._scaled_paging_touch_slop def getScaledDrawingCacheSize(self) -> int: return self._scaled_drawing_cache_size @staticmethod def getLongPressTimeout() -> int: return 500 @staticmethod def getTapTimeout() -> int: return 100 @staticmethod def getDoubleTapTimeout() -> int: return 300 @staticmethod def getKeyRepeatTimeout() -> int: return 400 @staticmethod def getKeyRepeatDelay() -> int: return 50 @staticmethod def getScrollDefaultDelay() -> int: return 40 @staticmethod def getScrollFriction() -> float: return 0.015 def toString(self) -> str: return "ViewConfiguration()" # ═══════════════════════════════════════════════════════════════ # ViewParent (扩展) # ═══════════════════════════════════════════════════════════════ class ViewParent(Stub): """ViewParent — 视图父容器接口扩展""" def requestLayout(self) -> None: pass def isLayoutRequested(self) -> bool: return False def requestTransparentRegion(self, child: Any) -> None: pass def invalidateChild(self, child: Any, r: Any) -> None: pass def invalidateChildInParent(self, location: Any, r: Any) -> Optional[Any]: return None def getParent(self) -> Optional["ViewParent"]: return None def requestChildFocus(self, child: Any, focused: Any) -> None: pass def recomputeViewAttributes(self, child: Any) -> None: pass def clearChildFocus(self, child: Any) -> None: pass def getChildVisibleRect(self, child: Any, r: Any, offset: Any) -> bool: return True def createSnapshot(self, out: Any, child: Any) -> None: pass def onStartTemporaryDetach(self) -> None: pass def onFinishTemporaryDetach(self) -> None: pass def bringChildToFront(self, child: Any) -> None: pass def focusSearch(self, child: Any, direction: int) -> Optional[Any]: return None def focusableViewAvailable(self, v: Any) -> None: pass def showContextMenuForChild(self, original_view: Any) -> bool: return False def actionModeStartingForChild(self, original_view: Any) -> Optional[Any]: return None def requestSendAccessibilityEvent(self, child: Any, event: Any) -> bool: return True def childHasTransientStateChanged(self, child: Any, has_state: bool) -> None: pass def requestChildRectangleOnScreen(self, child: Any, rectangle: Any, immediate: bool) -> bool: return True def canResolveLayoutDirection(self) -> bool: return True def isLayoutDirectionResolved(self) -> bool: return True def getLayoutDirection(self) -> int: return 0 def toString(self) -> str: return "ViewParent()" # ═══════════════════════════════════════════════════════════════ # ViewGroup (扩展) # ═══════════════════════════════════════════════════════════════ class ViewGroup(Stub): """ViewGroup — 视图组扩展""" CLIP_TO_PADDING_MASK = 0 FOCUS_AFTER = 1 FOCUS_BEFORE = 2 FOCUS_BLOCK = 3 LAYOUT_MODE_CLIP_BOUNDS = 0 LAYOUT_MODE_OPTICAL_BOUNDS = 1 PERSISTENT_NO_CACHE = 0 PERSISTENT_ANIMATION_CACHE = 1 PERSISTENT_SCROLLING_CACHE = 2 PERSISTENT_ALL_CACHES = 3 class LayoutParams(Stub): """ViewGroup.LayoutParams — 布局参数""" FILL_PARENT = -1 MATCH_PARENT = -1 WRAP_CONTENT = -2 def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT): super().__init__() self.width = width self.height = height def resolveLayoutDirection(self, layout_direction: int) -> None: pass def toString(self) -> str: return f"LayoutParams({self.width}x{self.height})" class MarginLayoutParams(LayoutParams): """ViewGroup.MarginLayoutParams — 带边距的布局参数""" def __init__(self, width: int = -2, height: int = -2): super().__init__(width, height) self.leftMargin: int = 0 self.topMargin: int = 0 self.rightMargin: int = 0 self.bottomMargin: int = 0 self.marginStart: int = 0 self.marginEnd: int = 0 def setMargins(self, left: int, top: int, right: int, bottom: int) -> None: self.leftMargin = left self.topMargin = top self.rightMargin = right self.bottomMargin = bottom def getMarginLeft(self) -> int: return self.leftMargin def getMarginTop(self) -> int: return self.topMargin def getMarginRight(self) -> int: return self.rightMargin def getMarginBottom(self) -> int: return self.bottomMargin def setMarginStart(self, start: int) -> None: self.marginStart = start def setMarginEnd(self, end: int) -> None: self.marginEnd = end def getMarginStart(self) -> int: return self.marginStart def getMarginEnd(self) -> int: return self.marginEnd def toString(self) -> str: return (f"MarginLayoutParams({self.width}x{self.height}, " f"margins=({self.leftMargin},{self.topMargin}," f"{self.rightMargin},{self.bottomMargin}))") def __init__(self): super().__init__() self._children: List[Any] = [] self._clip_children = True self._clip_to_padding = True self._layout_mode = self.LAYOUT_MODE_CLIP_BOUNDS self._persistent_caching = self.PERSISTENT_NO_CACHE self._touch_mode = False self._motion_event_splitting = True self._transient_child: Optional[Any] = None self._add_stateset_focus = False self._child_drawable_state: Optional[Any] = None def addView(self, child: Any, index: int = -1) -> None: if index < 0 or index >= len(self._children): self._children.append(child) else: self._children.insert(index, child) def removeView(self, child: Any) -> None: if child in self._children: self._children.remove(child) def removeViewAt(self, index: int) -> None: if 0 <= index < len(self._children): self._children.pop(index) def removeAllViews(self) -> None: self._children.clear() def getChildCount(self) -> int: return len(self._children) def getChildAt(self, index: int) -> Optional[Any]: if 0 <= index < len(self._children): return self._children[index] return None def indexOfChild(self, child: Any) -> int: try: return self._children.index(child) except ValueError: return -1 def bringChildToFront(self, child: Any) -> None: if child in self._children: self._children.remove(child) self._children.append(child) def setClipChildren(self, clip: bool) -> None: self._clip_children = clip def getClipChildren(self) -> bool: return self._clip_children def setClipToPadding(self, clip: bool) -> None: self._clip_to_padding = clip def getClipToPadding(self) -> bool: return self._clip_to_padding def setLayoutMode(self, mode: int) -> None: self._layout_mode = mode def getLayoutMode(self) -> int: return self._layout_mode def setPersistentDrawingCache(self, cache: int) -> None: self._persistent_caching = cache def getPersistentDrawingCache(self) -> int: return self._persistent_caching def setAddStatesFromChildren(self, add: bool) -> None: self._add_stateset_focus = add def addStatesFromChildren(self) -> bool: return self._add_stateset_focus def setMotionEventSplittingEnabled(self, split: bool) -> None: self._motion_event_splitting = split def isMotionEventSplittingEnabled(self) -> bool: return self._motion_event_splitting def setTouchMode(self, touch: bool) -> None: self._touch_mode = touch def isTouchMode(self) -> bool: return self._touch_mode def onLayout(self, changed: bool, l: int, t: int, r: int, b: int) -> None: pass def onInterceptTouchEvent(self, ev: Any) -> bool: return False def requestDisallowInterceptTouchEvent(self, disallow: bool) -> None: pass def getChildDrawingOrder(self, child_count: int, i: int) -> int: return i def setChildrenDrawingOrderEnabled(self, enabled: bool) -> None: pass def isChildrenDrawingOrderEnabled(self) -> bool: return False def toString(self) -> str: return f"ViewGroup(children={len(self._children)})" class ViewGroupOverlay(Stub): """ViewGroupOverlay — 视图组覆盖层""" def __init__(self, host: Any = None): super().__init__() self._host = host self._drawables: List[Any] = [] def add(self, drawable: Any) -> None: if drawable not in self._drawables: self._drawables.append(drawable) def remove(self, drawable: Any) -> None: if drawable in self._drawables: self._drawables.remove(drawable) def clear(self) -> None: self._drawables.clear() def toString(self) -> str: return f"ViewGroupOverlay(size={len(self._drawables)})" class ViewOverlay(Stub): """ViewOverlay — 视图覆盖层""" def __init__(self, host: Any = None): super().__init__() self._host = host self._drawables: List[Any] = [] def add(self, drawable: Any) -> None: if drawable not in self._drawables: self._drawables.append(drawable) def remove(self, drawable: Any) -> None: if drawable in self._drawables: self._drawables.remove(drawable) def clear(self) -> None: self._drawables.clear() def getHost(self) -> Optional[Any]: return self._host def toString(self) -> str: return f"ViewOverlay(size={len(self._drawables)})" # ═══════════════════════════════════════════════════════════════ # WindowInsets / DisplayCutout / Display # ═══════════════════════════════════════════════════════════════ class WindowInsets(Stub): """WindowInsets — 窗口插入区域""" def __init__(self): super().__init__() self._system_window_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._stable_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._display_cutout_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._mandatory_system_gesture_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._tappable_element_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._system_gesture_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._consume_stable = False self._consume_system_windows = False self._display_cutout: Optional[DisplayCutout] = None self._rounded_corners: List[Any] = [] self._privacy_indicators: Optional[Tuple[int, int, int, int]] = None def getSystemWindowInsetLeft(self) -> int: return self._system_window_insets[0] def getSystemWindowInsetTop(self) -> int: return self._system_window_insets[1] def getSystemWindowInsetRight(self) -> int: return self._system_window_insets[2] def getSystemWindowInsetBottom(self) -> int: return self._system_window_insets[3] def getSystemWindowInsets(self) -> Tuple[int, int, int, int]: return self._system_window_insets def getStableInsetLeft(self) -> int: return self._stable_insets[0] def getStableInsetTop(self) -> int: return self._stable_insets[1] def getStableInsetRight(self) -> int: return self._stable_insets[2] def getStableInsetBottom(self) -> int: return self._stable_insets[3] def getDisplayCutout(self) -> Optional[DisplayCutout]: return self._display_cutout def getDisplayCutoutInsets(self) -> Tuple[int, int, int, int]: return self._display_cutout_insets def getMandatorySystemGestureInsets(self) -> Tuple[int, int, int, int]: return self._mandatory_system_gesture_insets def getTappableElementInsets(self) -> Tuple[int, int, int, int]: return self._tappable_element_insets def getSystemGestureInsets(self) -> Tuple[int, int, int, int]: return self._system_gesture_insets def consumeSystemWindowInsets(self) -> WindowInsets: insets = WindowInsets() insets._system_window_insets = (0, 0, 0, 0) return insets def consumeStableInsets(self) -> WindowInsets: insets = WindowInsets() insets._stable_insets = (0, 0, 0, 0) return insets def isConsumed(self) -> bool: return self._consume_system_windows def hasInsets(self) -> bool: return (max(self._system_window_insets) > 0 or max(self._stable_insets) > 0) def hasSystemWindowInsets(self) -> bool: return max(self._system_window_insets) > 0 def hasStableInsets(self) -> bool: return max(self._stable_insets) > 0 def hasDisplayCutout(self) -> bool: return self._display_cutout is not None def toString(self) -> str: return (f"WindowInsets(sys={self._system_window_insets}, " f"stable={self._stable_insets})") class DisplayCutout(Stub): """DisplayCutout — 屏幕缺口信息""" def __init__(self): super().__init__() self._safe_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) self._bound_left: Optional[Any] = None self._bound_top: Optional[Any] = None self._bound_right: Optional[Any] = None self._bound_bottom: Optional[Any] = None self._waterfall_insets: Tuple[int, int, int, int] = (0, 0, 0, 0) def getSafeInsetLeft(self) -> int: return self._safe_insets[0] def getSafeInsetTop(self) -> int: return self._safe_insets[1] def getSafeInsetRight(self) -> int: return self._safe_insets[2] def getSafeInsetBottom(self) -> int: return self._safe_insets[3] def getBoundingRectLeft(self) -> Optional[Any]: return self._bound_left def getBoundingRectTop(self) -> Optional[Any]: return self._bound_top def getBoundingRectRight(self) -> Optional[Any]: return self._bound_right def getBoundingRectBottom(self) -> Optional[Any]: return self._bound_bottom def getWaterfallInsets(self) -> Tuple[int, int, int, int]: return self._waterfall_insets def toString(self) -> str: return f"DisplayCutout(safe={self._safe_insets})" class Display(Stub): """Display — 屏幕显示信息""" DEFAULT_DISPLAY = 0 FLAG_PRESENTATION = 1 FLAG_SECURE = 2 FLAG_SUPPORTS_PROTECTED_BUFFERS = 4 STATE_OFF = 0 STATE_ON = 1 STATE_DOZE = 2 STATE_DOZE_SUSPEND = 3 STATE_SUSPENDED = 4 STATE_UNKNOWN = -1 def __init__(self, display_id: int = DEFAULT_DISPLAY): super().__init__() self._display_id = display_id self._width: int = 1080 self._height: int = 1920 self._refresh_rate: float = 60.0 self._rotation: int = 0 self._state: int = STATE_ON self._name: str = "Internal Display" self._flags: int = 0 self._density: float = 2.0 self._dpi_x: float = 480.0 self._dpi_y: float = 480.0 self._app_width: int = 1080 self._app_height: int = 1920 self._smallest_width: int = 1080 self._largest_width: int = 1920 self._hdr_capabilities: Optional[Any] = None self._mode: Optional[Any] = None self._supported_modes: List[Any] = [] def getDisplayId(self) -> int: return self._display_id def getName(self) -> str: return self._name def getFlags(self) -> int: return self._flags def getHeight(self) -> int: return self._height def getWidth(self) -> int: return self._width def getRotation(self) -> int: return self._rotation def getState(self) -> int: return self._state def getRefreshRate(self) -> float: return self._refresh_rate def getDensity(self) -> float: return self._density def getDpiX(self) -> float: return self._dpi_x def getDpiY(self) -> float: return self._dpi_y def getAppWidth(self) -> int: return self._app_width def getAppHeight(self) -> int: return self._app_height def getSmallestWidth(self) -> int: return self._smallest_width def getLargestWidth(self) -> int: return self._largest_width def getSupportedModes(self) -> List[Any]: return list(self._supported_modes) def getMode(self) -> Optional[Any]: return self._mode def isHdr(self) -> bool: return False def getHdrCapabilities(self) -> Optional[Any]: return self._hdr_capabilities def isValid(self) -> bool: return True def toString(self) -> str: return (f"Display(id={self._display_id}, " f"{self._width}x{self._height}, " f"rotation={self._rotation})") # ═══════════════════════════════════════════════════════════════ # DragEvent / GestureDetector / KeyEvent / KeyCharacterMap # ═══════════════════════════════════════════════════════════════ DRAG_EVENT_ACTION_DRAG_STARTED = 1 DRAG_EVENT_ACTION_DRAG_ENTERED = 2 DRAG_EVENT_ACTION_DRAG_LOCATION = 3 DRAG_EVENT_ACTION_DRAG_EXITED = 4 DRAG_EVENT_ACTION_DROP = 5 DRAG_EVENT_ACTION_DRAG_ENDED = 6 GESTURE_STATE_NONE = 0 GESTURE_STATE_STARTED = 1 GESTURE_STATE_IN_PROGRESS = 2 GESTURE_STATE_FINISHED = 3 ACTION_DOWN = 0 ACTION_UP = 1 ACTION_MOVE = 2 ACTION_CANCEL = 3 ACTION_OUTSIDE = 4 ACTION_POINTER_DOWN = 5 ACTION_POINTER_UP = 6 ACTION_HOVER_ENTER = 7 ACTION_HOVER_EXIT = 8 ACTION_HOVER_MOVE = 9 ACTION_SCROLL = 10 ACTION_POINTER_INDEX_MASK = 0xFF00 ACTION_POINTER_INDEX_SHIFT = 8 META_ALT_MASK = 2 META_ALT_LEFT_ON = 16 META_ALT_RIGHT_ON = 32 META_ALT_ON = 2 META_CTRL_MASK = 4096 META_CTRL_LEFT_ON = 8192 META_CTRL_RIGHT_ON = 16384 META_CTRL_ON = 4096 META_FUNCTION_ON = 8 META_META_MASK = 65536 META_META_LEFT_ON = 131072 META_META_RIGHT_ON = 262144 META_META_ON = 65536 META_SHIFT_MASK = 1 META_SHIFT_LEFT_ON = 64 META_SHIFT_RIGHT_ON = 128 META_SHIFT_ON = 1 META_SYM_ON = 4 META_CAPS_LOCK_ON = 1048576 META_NUM_LOCK_ON = 2097152 META_SCROLL_LOCK_ON = 4194304 KEYCODE_UNKNOWN = 0 KEYCODE_SOFT_LEFT = 1 KEYCODE_SOFT_RIGHT = 2 KEYCODE_HOME = 3 KEYCODE_BACK = 4 KEYCODE_CALL = 5 KEYCODE_ENDCALL = 6 KEYCODE_0 = 7 KEYCODE_1 = 8 KEYCODE_2 = 9 KEYCODE_3 = 10 KEYCODE_4 = 11 KEYCODE_5 = 12 KEYCODE_6 = 13 KEYCODE_7 = 14 KEYCODE_8 = 15 KEYCODE_9 = 16 KEYCODE_STAR = 17 KEYCODE_POUND = 18 KEYCODE_DPAD_UP = 19 KEYCODE_DPAD_DOWN = 20 KEYCODE_DPAD_LEFT = 21 KEYCODE_DPAD_RIGHT = 22 KEYCODE_DPAD_CENTER = 23 KEYCODE_VOLUME_UP = 24 KEYCODE_VOLUME_DOWN = 25 KEYCODE_POWER = 26 KEYCODE_CAMERA = 27 KEYCODE_CLEAR = 28 KEYCODE_A = 29 KEYCODE_B = 30 KEYCODE_C = 31 KEYCODE_D = 32 KEYCODE_E = 33 KEYCODE_F = 34 KEYCODE_G = 35 KEYCODE_H = 36 KEYCODE_I = 37 KEYCODE_J = 38 KEYCODE_K = 39 KEYCODE_L = 40 KEYCODE_M = 41 KEYCODE_N = 42 KEYCODE_O = 43 KEYCODE_P = 44 KEYCODE_Q = 45 KEYCODE_R = 46 KEYCODE_S = 47 KEYCODE_T = 48 KEYCODE_U = 49 KEYCODE_V = 50 KEYCODE_W = 51 KEYCODE_X = 52 KEYCODE_Y = 53 KEYCODE_Z = 54 KEYCODE_COMMA = 55 KEYCODE_PERIOD = 56 KEYCODE_ALT_LEFT = 57 KEYCODE_ALT_RIGHT = 58 KEYCODE_SHIFT_LEFT = 59 KEYCODE_SHIFT_RIGHT = 60 KEYCODE_TAB = 61 KEYCODE_SPACE = 62 KEYCODE_SYM = 63 KEYCODE_EXPLORER = 64 KEYCODE_ENVELOPE = 65 KEYCODE_ENTER = 66 KEYCODE_DEL = 67 KEYCODE_GRAVE = 68 KEYCODE_MINUS = 69 KEYCODE_EQUALS = 70 KEYCODE_LEFT_BRACKET = 71 KEYCODE_RIGHT_BRACKET = 72 KEYCODE_BACKSLASH = 73 KEYCODE_SEMICOLON = 74 KEYCODE_APOSTROPHE = 75 KEYCODE_SLASH = 76 KEYCODE_AT = 77 KEYCODE_NUM = 78 KEYCODE_HEADSETHOOK = 79 KEYCODE_FOCUS = 80 KEYCODE_PLUS = 81 KEYCODE_MENU = 82 KEYCODE_NOTIFICATION = 83 KEYCODE_SEARCH = 84 KEYCODE_MEDIA_PLAY_PAUSE = 85 KEYCODE_MEDIA_STOP = 86 KEYCODE_MEDIA_NEXT = 87 KEYCODE_MEDIA_PREVIOUS = 88 KEYCODE_MEDIA_REWIND = 89 KEYCODE_MEDIA_FAST_FORWARD = 90 KEYCODE_MUTE = 91 KEYCODE_PAGE_UP = 92 KEYCODE_PAGE_DOWN = 93 KEYCODE_PICTSYMBOLS = 94 KEYCODE_SWITCH_CHARSET = 95 KEYCODE_BUTTON_A = 96 KEYCODE_BUTTON_B = 97 KEYCODE_BUTTON_C = 98 KEYCODE_BUTTON_X = 99 KEYCODE_BUTTON_Y = 100 KEYCODE_BUTTON_Z = 101 KEYCODE_BUTTON_L1 = 102 KEYCODE_BUTTON_R1 = 103 KEYCODE_BUTTON_L2 = 104 KEYCODE_BUTTON_R2 = 105 KEYCODE_BUTTON_THUMBL = 106 KEYCODE_BUTTON_THUMBR = 107 KEYCODE_BUTTON_START = 108 KEYCODE_BUTTON_SELECT = 109 KEYCODE_BUTTON_MODE = 110 KEYCODE_ESCAPE = 111 KEYCODE_FORWARD_DEL = 112 KEYCODE_CTRL_LEFT = 113 KEYCODE_CTRL_RIGHT = 114 KEYCODE_CAPS_LOCK = 115 KEYCODE_SCROLL_LOCK = 116 KEYCODE_META_LEFT = 117 KEYCODE_META_RIGHT = 118 KEYCODE_FUNCTION = 119 KEYCODE_SYSRQ = 120 KEYCODE_BREAK = 121 KEYCODE_MOVE_HOME = 122 KEYCODE_MOVE_END = 123 KEYCODE_INSERT = 124 KEYCODE_FORWARD = 125 KEYCODE_MEDIA_PLAY = 126 KEYCODE_MEDIA_PAUSE = 127 KEYCODE_MEDIA_CLOSE = 128 KEYCODE_MEDIA_EJECT = 129 KEYCODE_MEDIA_RECORD = 130 KEYCODE_F1 = 131 KEYCODE_F2 = 132 KEYCODE_F3 = 133 KEYCODE_F4 = 134 KEYCODE_F5 = 135 KEYCODE_F6 = 136 KEYCODE_F7 = 137 KEYCODE_F8 = 138 KEYCODE_F9 = 139 KEYCODE_F10 = 140 KEYCODE_F11 = 141 KEYCODE_F12 = 142 KEYCODE_NUM_LOCK = 143 KEYCODE_NUMPAD_0 = 144 KEYCODE_NUMPAD_1 = 145 KEYCODE_NUMPAD_2 = 146 KEYCODE_NUMPAD_3 = 147 KEYCODE_NUMPAD_4 = 148 KEYCODE_NUMPAD_5 = 149 KEYCODE_NUMPAD_6 = 150 KEYCODE_NUMPAD_7 = 151 KEYCODE_NUMPAD_8 = 152 KEYCODE_NUMPAD_9 = 153 KEYCODE_NUMPAD_DIVIDE = 154 KEYCODE_NUMPAD_MULTIPLY = 155 KEYCODE_NUMPAD_SUBTRACT = 156 KEYCODE_NUMPAD_ADD = 157 KEYCODE_NUMPAD_DOT = 158 KEYCODE_NUMPAD_COMMA = 159 KEYCODE_NUMPAD_ENTER = 160 KEYCODE_NUMPAD_EQUALS = 161 KEYCODE_NUMPAD_LEFT_PAREN = 162 KEYCODE_NUMPAD_RIGHT_PAREN = 163 KEYCODE_VOLUME_MUTE = 164 KEYCODE_INFO = 165 KEYCODE_CHANNEL_UP = 166 KEYCODE_CHANNEL_DOWN = 167 KEYCODE_ZOOM_IN = 168 KEYCODE_ZOOM_OUT = 169 WINDOW_INSETS_TYPE_SYSTEM_BARS = 0 WINDOW_INSETS_TYPE_STATUS_BARS = 1 WINDOW_INSETS_TYPE_NAVIGATION_BARS = 2 WINDOW_INSETS_TYPE_CAPTION_BAR = 3 WINDOW_INSETS_TYPE_IME = 4 WINDOW_INSETS_TYPE_TAPPABLE_ELEMENT = 5 WINDOW_INSETS_TYPE_MANDATORY_SYSTEM_GESTURES = 6 WINDOW_INSETS_TYPE_SYSTEM_GESTURES = 7 WINDOW_INSETS_TYPE_DISPLAY_CUTOUT = 8 WINDOW_INSETS_TYPE_WATERFALL = 9 WINDOW_INSETS_TYPE_PRIVACY_INDICATORS = 10 WINDOW_INSETS_ANIMATION_TYPE_NONE = 0 WINDOW_INSETS_ANIMATION_TYPE_ALPHA = 1 WINDOW_INSETS_ANIMATION_TYPE_TRANSLATION = 2 WINDOW_INSETS_ANIMATION_TYPE_ALPHA_AND_TRANSLATION = 3 class DragEvent(Stub): """DragEvent — 拖放事件""" ACTION_DRAG_STARTED = DRAG_EVENT_ACTION_DRAG_STARTED ACTION_DRAG_ENTERED = DRAG_EVENT_ACTION_DRAG_ENTERED ACTION_DRAG_LOCATION = DRAG_EVENT_ACTION_DRAG_LOCATION ACTION_DRAG_EXITED = DRAG_EVENT_ACTION_DRAG_EXITED ACTION_DROP = DRAG_EVENT_ACTION_DROP ACTION_DRAG_ENDED = DRAG_EVENT_ACTION_DRAG_ENDED def __init__(self, action: int = 0): super().__init__() self._action = action self._x: float = 0.0 self._y: float = 0.0 self._clip_data: Optional[Any] = None self._result: Optional[Any] = None self._local_state: Optional[Any] = None self._drag_surface: Optional[Any] = None def getAction(self) -> int: return self._action def getX(self) -> float: return self._x def getY(self) -> float: return self._y def getClipData(self) -> Optional[Any]: return self._clip_data def getResult(self) -> Optional[Any]: return self._result def getLocalState(self) -> Optional[Any]: return self._local_state def toString(self) -> str: actions = {1: "DRAG_STARTED", 2: "DRAG_ENTERED", 3: "DRAG_LOCATION", 4: "DRAG_EXITED", 5: "DROP", 6: "DRAG_ENDED"} return f"DragEvent(action={actions.get(self._action, 'UNKNOWN')})" class GestureDetector(Stub): """GestureDetector — 手势检测器""" class SimpleOnGestureListener(Stub): """GestureDetector.SimpleOnGestureListener — 简单手势监听器""" def onDown(self, e: Any) -> bool: return False def onShowPress(self, e: Any) -> None: pass def onSingleTapUp(self, e: Any) -> bool: return False def onSingleTapConfirmed(self, e: Any) -> bool: return False def onDoubleTap(self, e: Any) -> bool: return False def onDoubleTapEvent(self, e: Any) -> bool: return False def onLongPress(self, e: Any) -> None: pass def onScroll(self, e1: Any, e2: Any, distance_x: float, distance_y: float) -> bool: return False def onFling(self, e1: Any, e2: Any, velocity_x: float, velocity_y: float) -> bool: return False def onContextClick(self, e: Any) -> bool: return False class OnGestureListener(Stub): def onDown(self, e: Any) -> bool: return False def onShowPress(self, e: Any) -> None: pass def onSingleTapUp(self, e: Any) -> bool: return False def onScroll(self, e1: Any, e2: Any, dx: float, dy: float) -> bool: return False def onLongPress(self, e: Any) -> None: pass def onFling(self, e1: Any, e2: Any, vx: float, vy: float) -> bool: return False class OnDoubleTapListener(Stub): def onSingleTapConfirmed(self, e: Any) -> bool: return False def onDoubleTap(self, e: Any) -> bool: return False def onDoubleTapEvent(self, e: Any) -> bool: return False def onContextClick(self, e: Any) -> bool: return False def __init__(self, context: Any = None, listener: Optional[Any] = None): super().__init__() self._listener = listener self._double_tap_listener: Optional[Any] = None self._is_double_tapping = False self._touch_slop: int = 8 self._double_tap_slop: int = 100 self._double_tap_timeout: int = 300 self._longpress_timeout: int = 500 self._last_tap_x: float = 0 self._last_tap_y: float = 0 self._last_tap_time: int = 0 def setOnDoubleTapListener(self, listener: Optional[Any]) -> None: self._double_tap_listener = listener def setContextClickListener(self, listener: Optional[Any]) -> None: pass def setIsLongpressEnabled(self, enabled: bool) -> None: pass def isLongpressEnabled(self) -> bool: return True def onTouchEvent(self, ev: Any) -> bool: return True def toString(self) -> str: return f"GestureDetector(listener={'yes' if self._listener else 'no'})" class KeyEvent(_BaseKeyEvent): """KeyEvent — 按键事件 (扩展版,继承 view.KeyEvent 的所有常量)""" ACTION_DOWN = 0 ACTION_UP = 1 ACTION_MULTIPLE = 2 FLAG_WOKE_HERE = 1 FLAG_SOFT_KEYBOARD = 2 FLAG_KEEP_TOUCH_MODE = 4 FLAG_FROM_SYSTEM = 8 FLAG_EDITOR_ACTION = 16 FLAG_CANCELED = 32 FLAG_VIRTUAL_HARD_KEY = 64 FLAG_LONG_PRESS = 128 FLAG_CANCELED_LONG_PRESS = 256 FLAG_TRACKING = 512 FLAG_FALLBACK = 1024 def __init__(self, action: int = ACTION_DOWN, code: int = KEYCODE_UNKNOWN): super().__init__() self._action = action self._code = code self._repeat: int = 0 self._meta_state: int = 0 self._device_id: int = 0 self._scan_code: int = 0 self._flags: int = 0 self._down_time: int = 0 self._event_time: int = 0 self._display_id: int = 0 def getAction(self) -> int: return self._action def getKeyCode(self) -> int: return self._code def getRepeatCount(self) -> int: return self._repeat def getMetaState(self) -> int: return self._meta_state def getDeviceId(self) -> int: return self._device_id def getScanCode(self) -> int: return self._scan_code def getFlags(self) -> int: return self._flags def getDownTime(self) -> int: return self._down_time def getEventTime(self) -> int: return self._event_time def getDisplayId(self) -> int: return self._display_id def isLongPress(self) -> bool: return bool(self._flags & self.FLAG_LONG_PRESS) def isCanceled(self) -> bool: return bool(self._flags & self.FLAG_CANCELED) @staticmethod def isModifierKey(key_code: int) -> bool: return key_code in (KEYCODE_ALT_LEFT, KEYCODE_ALT_RIGHT, KEYCODE_SHIFT_LEFT, KEYCODE_SHIFT_RIGHT, KEYCODE_CTRL_LEFT, KEYCODE_CTRL_RIGHT, KEYCODE_META_LEFT, KEYCODE_META_RIGHT, KEYCODE_SYM, KEYCODE_FUNCTION) @staticmethod def keyCodeFromString(symbolic_name: str) -> int: mapping = { "KEYCODE_A": KEYCODE_A, "KEYCODE_B": KEYCODE_B, "KEYCODE_C": KEYCODE_C, "KEYCODE_D": KEYCODE_D, "KEYCODE_E": KEYCODE_E, "KEYCODE_F": KEYCODE_F, "KEYCODE_G": KEYCODE_G, "KEYCODE_H": KEYCODE_H, "KEYCODE_I": KEYCODE_I, "KEYCODE_J": KEYCODE_J, "KEYCODE_K": KEYCODE_K, "KEYCODE_L": KEYCODE_L, "KEYCODE_M": KEYCODE_M, "KEYCODE_N": KEYCODE_N, "KEYCODE_O": KEYCODE_O, "KEYCODE_P": KEYCODE_P, "KEYCODE_Q": KEYCODE_Q, "KEYCODE_R": KEYCODE_R, "KEYCODE_S": KEYCODE_S, "KEYCODE_T": KEYCODE_T, "KEYCODE_U": KEYCODE_U, "KEYCODE_V": KEYCODE_V, "KEYCODE_W": KEYCODE_W, "KEYCODE_X": KEYCODE_X, "KEYCODE_Y": KEYCODE_Y, "KEYCODE_Z": KEYCODE_Z, "KEYCODE_0": KEYCODE_0, "KEYCODE_1": KEYCODE_1, "KEYCODE_2": KEYCODE_2, "KEYCODE_3": KEYCODE_3, "KEYCODE_4": KEYCODE_4, "KEYCODE_5": KEYCODE_5, "KEYCODE_6": KEYCODE_6, "KEYCODE_7": KEYCODE_7, "KEYCODE_8": KEYCODE_8, "KEYCODE_9": KEYCODE_9, "KEYCODE_HOME": KEYCODE_HOME, "KEYCODE_BACK": KEYCODE_BACK, "KEYCODE_MENU": KEYCODE_MENU, "KEYCODE_SEARCH": KEYCODE_SEARCH, "KEYCODE_ENTER": KEYCODE_ENTER, "KEYCODE_DEL": KEYCODE_DEL, "KEYCODE_SPACE": KEYCODE_SPACE, "KEYCODE_TAB": KEYCODE_TAB, } return mapping.get(symbolic_name, KEYCODE_UNKNOWN) @staticmethod def keyCodeToString(key_code: int) -> str: reverse = {v: k for k, v in { "KEYCODE_A": KEYCODE_A, "KEYCODE_B": KEYCODE_B, "KEYCODE_HOME": KEYCODE_HOME, "KEYCODE_BACK": KEYCODE_BACK, }.items()} return reverse.get(key_code, f"KEYCODE_{key_code}") def toString(self) -> str: return (f"KeyEvent(action={self._action}, code={self._code}, " f"repeat={self._repeat})") class KeyCharacterMap(Stub): """KeyCharacterMap — 按键字符映射""" ALPHA = 0 FULL = 1 NUMERIC = 2 PREDICTIVE = 3 SPECIAL_FUNCTION = 4 VIRTUAL = 5 BUILT_IN_KEYBOARD = 0 NUMERIC_MODIFIER_MASK = 1 MODIFIER_BEHAVIOR_CHORDED = 0 MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED = 1 def __init__(self): super().__init__() def get(self, key_code: int, meta_state: int) -> int: return 0 def getNumber(self, key_code: int) -> int: if KEYCODE_0 <= key_code <= KEYCODE_9: return ord("0") + (key_code - KEYCODE_0) return 0 def getMatch(self, key_code: int, chars: List[int], meta_state: int = 0) -> int: return 0 def getDisplayLabel(self, key_code: int) -> int: return key_code def getKeyboardType(self) -> int: return self.QWERTY @staticmethod def deviceHasKey(key_code: int) -> bool: return True @staticmethod def deviceHasKeys(key_codes: List[int]) -> List[bool]: return [True] * len(key_codes) def toString(self) -> str: return "KeyCharacterMap()" class KeyDispatcherState(Stub): """KeyDispatcherState — 按键调度状态""" def __init__(self): super().__init__() self._state: Dict[int, Any] = {} def reset(self) -> None: self._state.clear() def startTracking(self, event: KeyEvent, target: Any) -> None: key = event.getKeyCode() self._state[key] = {"target": target, "started": True} def isTracking(self, event: KeyEvent) -> bool: key = event.getKeyCode() return key in self._state and self._state[key].get("started", False) def performedLongPress(self, event: KeyEvent) -> None: key = event.getKeyCode() if key in self._state: self._state[key]["longpress"] = True def handleUpEvent(self, event: KeyEvent) -> bool: key = event.getKeyCode() if key in self._state: del self._state[key] return True return False def toString(self) -> str: return f"KeyDispatcherState(tracking={len(self._state)})" # ═══════════════════════════════════════════════════════════════ # LayoutInflater / Menu / MenuItem / SubMenu / ContextMenu # ═══════════════════════════════════════════════════════════════ class LayoutInflater(Stub): """LayoutInflater — 布局填充器""" def __init__(self, context: Any = None): super().__init__() self._context = context @staticmethod def from_context(context: Any) -> "LayoutInflater": return LayoutInflater(context) def inflate(self, resource: Any, root: Any, attach_to_root: bool = False) -> Optional[Any]: return None def getContext(self) -> Optional[Any]: return self._context def cloneInContext(self, new_context: Any) -> "LayoutInflater": return LayoutInflater(new_context) def setFactory(self, factory: Any) -> None: pass def getFactory(self) -> Optional[Any]: return None def setFactory2(self, factory: Any) -> None: pass def getFactory2(self) -> Optional[Any]: return None def setFilters(self, filters: List[Any]) -> None: pass def toString(self) -> str: return f"LayoutInflater(context={self._context})" class Menu(Stub): """Menu — 菜单接口""" FIRST = 1 NONE = 0 CATEGORY_MASK = 0xFFFF CATEGORY_SHIFT = 16 FLAG_PERFORM_NO_CLOSE = 1 FLAG_ALWAYS_PERFORM_CLOSE = 2 USER_MASK = 0x0000FFFF USER_SHIFT = 0 CATEGORY_CONTAINER = 0x00010000 CATEGORY_SYSTEM = 0x00020000 CATEGORY_SECONDARY = 0x00030000 CATEGORY_ALTERNATIVE = 0x00040000 CATEGORY_APP = 0x00100000 def add(self, title: str) -> "MenuItem": return MenuItem(self, 0, 0, 0, title) def add(self, group_id: int, item_id: int, order: int, title: str) -> "MenuItem": return MenuItem(self, group_id, item_id, order, title) def addIntentOptions(self, group_id: int, item_id: int, order: int, caller: Any, specific: Any, intent: Any, flags: int, out_specific_items: List[Any]) -> int: return 0 def addSubMenu(self, title: str) -> "SubMenu": return SubMenu(self) def addSubMenu(self, group_id: int, item_id: int, order: int, title: str) -> "SubMenu": return SubMenu(self) def clear(self) -> None: pass def removeGroup(self, group_id: int) -> None: pass def removeItem(self, id_val: int) -> None: pass def setGroupCheckable(self, group: int, checkable: bool, exclusive: bool) -> None: pass def setGroupEnabled(self, group: int, enabled: bool) -> None: pass def setGroupVisible(self, group: int, visible: bool) -> None: pass def findItem(self, id_val: int) -> Optional["MenuItem"]: return None def size(self) -> int: return 0 def getItem(self, index: int) -> "MenuItem": return MenuItem(self, 0, 0, 0, "") def close(self) -> None: pass def performIdentifierAction(self, id_val: int, flags: int) -> bool: return True def performShortcut(self, key_code: int, event: Any, flags: int) -> bool: return True def isShortcutKey(self, key_code: int, event: Any) -> bool: return False def hasVisibleItems(self) -> bool: return False def onMenuAction(self, id_val: int) -> bool: return True def toString(self) -> str: return "Menu()" class MenuItem(Stub): """MenuItem — 菜单项""" SHOW_AS_ACTION_ALWAYS = 2 SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8 SHOW_AS_ACTION_IF_ROOM = 1 SHOW_AS_ACTION_NEVER = 0 SHOW_AS_ACTION_WITH_TEXT = 4 def __init__(self, menu: Menu = None, group_id: int = 0, item_id: int = 0, order: int = 0, title: str = ""): super().__init__() self._menu = menu self._item_id = item_id self._group_id = group_id self._order = order self._title = title self._title_condensed: Optional[str] = None self._icon: Optional[Any] = None self._intent: Optional[Any] = None self._checked = False self._checkable = False self._visible = True self._enabled = True self._action_view: Optional[Any] = None self._on_click: Optional[Callable] = None self._show_as_action = 0 def getItemId(self) -> int: return self._item_id def getGroupId(self) -> int: return self._group_id def getOrder(self) -> int: return self._order def getTitle(self) -> str: return self._title def setTitle(self, title: str) -> "MenuItem": self._title = title return self def getTitleCondensed(self) -> Optional[str]: return self._title_condensed def setTitleCondensed(self, title: str) -> "MenuItem": self._title_condensed = title return self def getIcon(self) -> Optional[Any]: return self._icon def setIcon(self, icon: Any) -> "MenuItem": self._icon = icon return self def getIntent(self) -> Optional[Any]: return self._intent def setIntent(self, intent: Any) -> "MenuItem": self._intent = intent return self def isChecked(self) -> bool: return self._checked def setChecked(self, checked: bool) -> "MenuItem": self._checked = checked return self def isCheckable(self) -> bool: return self._checkable def setCheckable(self, checkable: bool) -> "MenuItem": self._checkable = checkable return self def isVisible(self) -> bool: return self._visible def setVisible(self, visible: bool) -> "MenuItem": self._visible = visible return self def isEnabled(self) -> bool: return self._enabled def setEnabled(self, enabled: bool) -> "MenuItem": self._enabled = enabled return self def setOnMenuItemClickListener(self, click: Callable) -> "MenuItem": self._on_click = click return self def getOnMenuItemClickListener(self) -> Optional[Callable]: return self._on_click def setActionView(self, view: Any) -> "MenuItem": self._action_view = view return self def setActionView(self, layout_res_id: int) -> "MenuItem": return self def getActionView(self) -> Optional[Any]: return self._action_view def setShowAsAction(self, action_enum: int) -> None: self._show_as_action = action_enum def getShowAsAction(self) -> int: return self._show_as_action def expandActionView(self) -> bool: return True def collapseActionView(self) -> bool: return True def isActionViewExpanded(self) -> bool: return False def setOnActionExpandListener(self, listener: Any) -> "MenuItem": return self def hasSubMenu(self) -> bool: return False def getSubMenu(self) -> Optional["SubMenu"]: return None def toString(self) -> str: return f"MenuItem(id={self._item_id}, title={self._title})" class SubMenu(Menu): """SubMenu — 子菜单""" def __init__(self, parent: Optional[Menu] = None): super().__init__() self._parent = parent def setHeaderTitle(self, title: str) -> "SubMenu": return self def setHeaderIcon(self, icon: Any) -> "SubMenu": return self def setHeaderView(self, view: Any) -> "SubMenu": return self def clearHeader(self) -> None: pass def setIcon(self, icon: Any) -> "SubMenu": return self def getItem(self) -> MenuItem: return MenuItem(self, 0, 0, 0, "") def toString(self) -> str: return "SubMenu()" class ContextMenu(Menu): """ContextMenu — 上下文菜单""" class ContextMenuInfo(Stub): """ContextMenu.ContextMenuInfo — 上下文菜单信息接口""" pass def __init__(self): super().__init__() def setHeaderTitle(self, title: str) -> "ContextMenu": return self def setHeaderIcon(self, icon: Any) -> "ContextMenu": return self def setHeaderView(self, view: Any) -> "ContextMenu": return self def clearHeader(self) -> None: pass def toString(self) -> str: return "ContextMenu()" # ═══════════════════════════════════════════════════════════════ # ScaleGestureDetector / SoundEffectConstants / Surface / etc. # ═══════════════════════════════════════════════════════════════ class ScaleGestureDetector(Stub): """ScaleGestureDetector — 缩放手势检测器""" class SimpleOnScaleGestureListener(Stub): def onScale(self, detector: "ScaleGestureDetector") -> bool: return False def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool: return True def onScaleEnd(self, detector: "ScaleGestureDetector") -> None: pass class OnScaleGestureListener(Stub): def onScale(self, detector: "ScaleGestureDetector") -> bool: return False def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool: return True def onScaleEnd(self, detector: "ScaleGestureDetector") -> None: pass def __init__(self, context: Any = None, listener: Optional[Any] = None): super().__init__() self._listener = listener self._scale_factor: float = 1.0 self._focus_x: float = 0.0 self._focus_y: float = 0.0 self._current_span: float = 0.0 self._previous_span: float = 0.0 self._time_delta: int = 0 self._in_progress = False self._quick_scale_enabled = False def getScaleFactor(self) -> float: return self._scale_factor def getFocusX(self) -> float: return self._focus_x def getFocusY(self) -> float: return self._focus_y def getCurrentSpan(self) -> float: return self._current_span def getPreviousSpan(self) -> float: return self._previous_span def getCurrentSpanX(self) -> float: return self._current_span def getCurrentSpanY(self) -> float: return self._current_span def getPreviousSpanX(self) -> float: return self._previous_span def getPreviousSpanY(self) -> float: return self._previous_span def getTimeDelta(self) -> int: return self._time_delta def getEventTime(self) -> int: return 0 def isInProgress(self) -> bool: return self._in_progress def setQuickScaleEnabled(self, enabled: bool) -> None: self._quick_scale_enabled = enabled def isQuickScaleEnabled(self) -> bool: return self._quick_scale_enabled def onTouchEvent(self, ev: Any) -> bool: return True def toString(self) -> str: return (f"ScaleGestureDetector(scale={self._scale_factor:.2f}, " f"inProgress={self._in_progress})") class SoundEffectConstants(Stub): """SoundEffectConstants — 音效常量""" CLICK = 0 NAVIGATION_UP = 1 NAVIGATION_DOWN = 2 NAVIGATION_LEFT = 3 NAVIGATION_RIGHT = 4 NAVIGATION_REPEAT_UP = 5 NAVIGATION_REPEAT_DOWN = 6 NAVIGATION_REPEAT_LEFT = 7 NAVIGATION_REPEAT_RIGHT = 8 @staticmethod def getContantForFocusDirection(direction: int) -> int: return SoundEffectConstants.NAVIGATION_UP class Surface(Stub): """Surface — 表面""" ROTATION_0 = 0 ROTATION_90 = 1 ROTATION_180 = 2 ROTATION_270 = 3 def __init__(self, surface_control: Optional["SurfaceControl"] = None): super().__init__() self._surface_control = surface_control self._is_valid = True self._width: int = 0 self._height: int = 0 def isValid(self) -> bool: return self._is_valid def lockCanvas(self, dirty_rect: Optional[Any] = None) -> Optional[Any]: return None def unlockCanvasAndPost(self, canvas: Any) -> None: pass def getSurfaceControl(self) -> Optional["SurfaceControl"]: return self._surface_control def getWidth(self) -> int: return self._width def getHeight(self) -> int: return self._height def toString(self) -> str: return f"Surface(valid={self._is_valid})" class SurfaceControl(Stub): """SurfaceControl — 表面控制""" BUFFER_TRANSFORM_IDENTITY = 0 BUFFER_TRANSFORM_MIRROR_H = 1 BUFFER_TRANSFORM_MIRROR_V = 2 BUFFER_TRANSFORM_ROTATE_90 = 4 BUFFER_TRANSFORM_ROTATE_180 = 3 BUFFER_TRANSFORM_ROTATE_270 = 7 def __init__(self): super().__init__() self._surface: Optional[Surface] = None self._visible = False self._alpha: float = 1.0 self._layer: int = 0 def createSurface(self) -> Surface: self._surface = Surface(self) return self._surface def setAlpha(self, alpha: float) -> None: self._alpha = max(0.0, min(1.0, alpha)) def setLayer(self, layer: int) -> None: self._layer = layer def setVisible(self, visible: bool) -> None: self._visible = visible def release(self) -> None: self._surface = None def toString(self) -> str: return f"SurfaceControl(layer={self._layer}, visible={self._visible})" class SurfaceView(Stub): """SurfaceView — 表面视图扩展""" def __init__(self, context: Any = None): super().__init__() self._surface: Optional[Surface] = None self._surface_holder: Optional[Any] = None self._callback: Optional[Callable] = None def getHolder(self) -> Optional[Any]: return self._surface_holder def getSurfaceControl(self) -> Optional[SurfaceControl]: return None def setSecure(self, secure: bool) -> None: pass def setZOrderOnTop(self, on_top: bool) -> None: pass def setZOrderMediaOverlay(self, is_media_overlay: bool) -> None: pass def toString(self) -> str: return "SurfaceView()" class TextureView(Stub): """TextureView — 纹理视图""" def __init__(self, context: Any = None): super().__init__() self._surface_texture: Optional[Any] = None self._callback: Optional[Callable] = None self._update_listener: Optional[Callable] = None def getSurfaceTexture(self) -> Optional[Any]: return self._surface_texture def setSurfaceTextureListener(self, listener: Optional[Callable]) -> None: self._update_listener = listener def isAvailable(self) -> bool: return self._surface_texture is not None def setOpaque(self, opaque: bool) -> None: pass def getBitmap(self) -> Optional[Any]: return None def toString(self) -> str: return "TextureView()" class TouchDelegate(Stub): """TouchDelegate — 触摸委托""" def __init__(self, bounds: Any, delegate_view: Any): super().__init__() self._bounds = bounds self._delegate_view = delegate_view self._touch_slop: int = 8 def onTouchEvent(self, event: Any) -> bool: return False def toString(self) -> str: return f"TouchDelegate(delegate={self._delegate_view})" class VelocityTracker(Stub): """VelocityTracker — 速度追踪器""" def __init__(self, strategy: str = ""): super().__init__() self._positions: List[Tuple[float, float, int]] = [] self._strategy = strategy @staticmethod def obtain(strategy: str = "") -> "VelocityTracker": return VelocityTracker(strategy) def addMovement(self, event: Any) -> None: pass def computeCurrentVelocity(self, units: int, max_velocity: float = 10000.0) -> None: pass def getXVelocity(self) -> float: return 0.0 def getYVelocity(self) -> float: return 0.0 def getXVelocity(self, id_val: int) -> float: return 0.0 def getYVelocity(self, id_val: int) -> float: return 0.0 def clear(self) -> None: self._positions.clear() def recycle(self) -> None: self._positions.clear() def toString(self) -> str: return f"VelocityTracker(strategy={self._strategy})" class WindowInsetsAnimation(Stub): """WindowInsetsAnimation — 窗口插入动画""" def __init__(self, type_mask: int = 0, interpolated_fraction: float = 0.0): super().__init__() self._type_mask = type_mask self._interpolated_fraction = interpolated_fraction self._duration: int = 0 self._interpolator: Optional[Any] = None def getTypeMask(self) -> int: return self._type_mask def getInterpolatedFraction(self) -> float: return self._interpolated_fraction def getDurationMillis(self) -> float: return float(self._duration) def setDuration(self, duration: int) -> None: self._duration = duration def setInterpolator(self, interpolator: Any) -> None: self._interpolator = interpolator def getInterpolator(self) -> Optional[Any]: return self._interpolator class Callback(Stub): """WindowInsetsAnimation.Callback — 动画回调""" DISPATCH_MODE_STOP = 0 DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1 def __init__(self, dispatch_mode: int = DISPATCH_MODE_CONTINUE_ON_SUBTREE): super().__init__() self._dispatch_mode = dispatch_mode def onPrepare(self, animation: "WindowInsetsAnimation") -> None: pass def onStart(self, animation: "WindowInsetsAnimation", bounds: WindowInsetsAnimation.Bounds) -> None: pass def onProgress(self, insets: WindowInsets, running_animations: List["WindowInsetsAnimation"]) -> WindowInsets: return insets def onEnd(self, animation: "WindowInsetsAnimation") -> None: pass class Bounds(Stub): """WindowInsetsAnimation.Bounds — 动画边界""" def __init__(self, lower_bound: WindowInsets, upper_bound: WindowInsets): super().__init__() self._lower_bound = lower_bound self._upper_bound = upper_bound def getLowerBound(self) -> WindowInsets: return self._lower_bound def getUpperBound(self) -> WindowInsets: return self._upper_bound def inset(self, insets: WindowInsets) -> "Bounds": return self def toString(self) -> str: return "WindowInsetsAnimation.Bounds()" def toString(self) -> str: return (f"WindowInsetsAnimation(typeMask={self._type_mask}, " f"fraction={self._interpolated_fraction})") class WindowInsetsController(Stub): """WindowInsetsController — 窗口插入控制器""" APPEARANCE_OPAQUE_STATUS_BARS = 1 APPEARANCE_OPAQUE_NAVIGATION_BARS = 2 APPEARANCE_LOW_PROFILE_BARS = 4 APPEARANCE_LIGHT_STATUS_BARS = 8 APPEARANCE_LIGHT_NAVIGATION_BARS = 16 APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS = 32 APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS = 64 BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 0 BEHAVIOR_DEFAULT = 1 BEHAVIOR_SHOW_BARS_BY_TOUCH = 2 BEHAVIOR_SHOW_BARS_BY_SWIPE = 3 def __init__(self): super().__init__() self._appearance: int = 0 self._behavior: int = self.BEHAVIOR_DEFAULT self._show_types: int = 0 self._hide_types: int = 0 def show(self, types: int) -> None: self._show_types |= types def hide(self, types: int) -> None: self._hide_types |= types def setAppearance(self, appearance: int) -> None: self._appearance = appearance def getAppearance(self) -> int: return self._appearance def setBehavior(self, behavior: int) -> None: self._behavior = behavior def getBehavior(self) -> int: return self._behavior def setSystemBarsAppearance(self, appearance: int, mask: int) -> None: self._appearance = (self._appearance & ~mask) | (appearance & mask) def getSystemBarsAppearance(self) -> int: return self._appearance def toString(self) -> str: return (f"WindowInsetsController(show={self._show_types}, " f"hide={self._hide_types})")