Files
Android-pyApi/android_pyapi/android/view.py
T
shuiyu1123 8c3bd3c415 feat: 大幅增强原生行为 — 修复P0 Bug + 补全核心API
P0 Bug 修复:
- Canvas.drawBitmap 重复定义导致重载丢失 → 合并为*args重载
- String.hashCode() 不可达的第二return → 修复为单return
- File.compareTo() 调用不存在的__cmp__ → 改为显式比较
- HashMap.remove() 逻辑错误 → 区分单参(返回旧值)/双参(返回boolean)

P1 核心行为增强:
- Handler: sendMessage/sendMessageDelayed 现在真正入队异步执行
- Looper: loop() 实现真正的消息循环(按when时间取出到期消息)
- AsyncTask: execute() 在后台线程池执行,完成后主线程回调
- Bundle: 新增12个数组类型put/get方法
- Math.round: 改为Java语义(floor(a+0.5))而非Python银行家舍入
- Thread: currentThread()缓存对象, 新增join/getState/getId/getPriority
- String: 新增strip/repeat/isBlank/lines/subSequence/getChars/chars/formatted/translateEscapes

P2 缺失API补全:
- 新增21个Java标准Exception类 (NullPointerException等)
- View: 新增39个事件处理/监听器/位置尺寸方法
- Activity: 新增33个生命周期/权限/UI方法
- Context: 新增22个文件流/权限/资源/主题方法
- Canvas: 支持 Canvas(Bitmap) 构造函数重载
- __init__.py: __all__ 补全Exception体系和Activity类
2026-06-24 15:04:17 +00:00

3968 lines
125 KiB
Python

"""
Android View 组件 — View, ViewGroup, MotionEvent, KeyEvent, GestureDetector 等
方法签名完全对齐 Android SDK
"""
import math
import time
import weakref
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from .._core import Stub, AndroidOnlyError, android_context, HAS_PYAUTOGUI
# ═══════════════════════════════════════════════════════════════
# Gravity
# ═══════════════════════════════════════════════════════════════
class Gravity:
"""Gravity — 布局重力常量"""
NO_GRAVITY = 0x0000
TOP = 0x0030
BOTTOM = 0x0050
LEFT = 0x0003
RIGHT = 0x0005
CENTER = 0x0011
CENTER_HORIZONTAL = 0x0001
CENTER_VERTICAL = 0x0010
FILL = 0x0077
FILL_HORIZONTAL = 0x0007
FILL_VERTICAL = 0x0070
CLIP_HORIZONTAL = 0x0008
CLIP_VERTICAL = 0x0080
START = 0x00800001
END = 0x00800005
RELATIVE_LAYOUT_DIRECTION = 0x00800000
@staticmethod
def getAbsoluteGravity(gravity: int, layout_direction: int) -> int:
from ..os import View
if layout_direction == View.LAYOUT_DIRECTION_RTL:
if gravity & Gravity.START:
gravity = (gravity & ~Gravity.START) | Gravity.RIGHT
if gravity & Gravity.END:
gravity = (gravity & ~Gravity.END) | Gravity.LEFT
else:
if gravity & Gravity.START:
gravity = (gravity & ~Gravity.START) | Gravity.LEFT
if gravity & Gravity.END:
gravity = (gravity & ~Gravity.END) | Gravity.RIGHT
return gravity
@staticmethod
def apply(gravity: int, w: int, h: int, container: "Rect") -> int:
return 0
Rect = None
def _set_rect_class():
global Rect
if Rect is None:
class _Rect:
def __init__(self, l=0, t=0, r=0, b=0):
self.left = l
self.top = t
self.right = r
self.bottom = b
def width(self): return self.right - self.left
def height(self): return self.bottom - self.top
def set(self, l, t, r, b):
self.left, self.top, self.right, self.bottom = l, t, r, b
def isEmpty(self): return self.width() <= 0 or self.height() <= 0
def toString(self): return f"Rect({self.left}, {self.top} - {self.right}, {self.bottom})"
Rect = _Rect
_set_rect_class()
# ═══════════════════════════════════════════════════════════════
# View
# ═══════════════════════════════════════════════════════════════
class View(Stub):
"""View — 所有 UI 组件的基类"""
# 可见性常量
VISIBLE = 0
INVISIBLE = 4
GONE = 8
# 测量常量
MEASURED_SIZE_STATE_MASK = 0xFF000000
MEASURED_STATE_MASK = 0xFF000000
MEASURED_HEIGHT_STATE_SHIFT = 16
MEASURED_WIDTH_STATE_SHIFT = 0
# 测量模式
EXACTLY = 0x40000000
AT_MOST = 0x80000000 # -2147483648
UNSPECIFIED = 0
# 滚动轴
SCROLL_AXIS_NONE = 0
SCROLL_AXIS_HORIZONTAL = 1
SCROLL_AXIS_VERTICAL = 2
# 布局方向
LAYOUT_DIRECTION_LTR = 0
LAYOUT_DIRECTION_RTL = 1
# 绘制缓存
DRAWING_CACHE_QUALITY_LOW = 0x00040000
DRAWING_CACHE_QUALITY_HIGH = 0x00080000
DRAWING_CACHE_QUALITY_AUTO = 0
# 焦点方向
FOCUS_BACKWARD = 0x00000001
FOCUS_FORWARD = 0x00000002
FOCUS_LEFT = 0x00000011
FOCUS_UP = 0x00000021
FOCUS_RIGHT = 0x00000042
FOCUS_DOWN = 0x00000082
# Keep screen on
KEEP_SCREEN_ON = 0x02000000
# 状态
STATUS_BAR_HIDDEN = 0x00000001
STATUS_BAR_VISIBLE = 0x00000000
NAVIGATION_BAR_HIDDEN = 0x00000002
NAVIGATION_BAR_VISIBLE = 0x00000000
# 系统UI可见性
SYSTEM_UI_FLAG_VISIBLE = 0
SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001
SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002
SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004
SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400
SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800
SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000
_next_id = 0x10000000
_id_lock = None
def __init__(self, context=None):
super().__init__()
if context is None:
context = android_context
self._context = context
self._id = View.NO_ID
self._tag: Any = None
self._layout_params: Optional["ViewGroup.LayoutParams"] = None
self._visibility = View.VISIBLE
self._enabled = True
self._clickable = False
self._focusable = False
self._selected = False
self._activated = False
self._x: float = 0.0
self._y: float = 0.0
self._translation_x: float = 0.0
self._translation_y: float = 0.0
self._rotation: float = 0.0
self._scale_x: float = 1.0
self._scale_y: float = 1.0
self._alpha: float = 1.0
self._pivot_x: float = 0.0
self._pivot_y: float = 0.0
self._measured_width: int = 0
self._measured_height: int = 0
self._left: int = 0
self._top: int = 0
self._right: int = 0
self._bottom: int = 0
self._padding_left: int = 0
self._padding_top: int = 0
self._padding_right: int = 0
self._padding_bottom: int = 0
self._parent: Optional["ViewGroup"] = None
self._background_color: Optional[int] = None
self._background_drawable: Any = None
self._background_resource: int = 0
self._on_click_listener: Optional[Callable] = None
self._on_long_click_listener: Optional[Callable] = None
self._on_touch_listener: Optional[Callable] = None
self._on_key_listener: Optional[Callable] = None
self._callbacks: Dict[Any, Tuple[Callable, float]] = {}
self._scroll_x: int = 0
self._scroll_y: int = 0
self._will_not_draw = False
self._layer_type = View.LAYER_TYPE_NONE
self._layout_direction = View.LAYOUT_DIRECTION_LTR
self._min_width: int = 0
self._min_height: int = 0
self._elevation: float = 0.0
self._clickable = False
self._long_clickable = False
self._context_clickable = False
self._children: List["View"] = []
# ─── 常量 ──────────────────────────────────────────────────
NO_ID = -1
DRAWING_CACHE_QUALITY_LOW = 0x00040000
DRAWING_CACHE_QUALITY_HIGH = 0x00080000
DRAWING_CACHE_QUALITY_AUTO = 0
LAYER_TYPE_NONE = 0
LAYER_TYPE_SOFTWARE = 1
LAYER_TYPE_HARDWARE = 2
FADING_EDGE_NONE = 0
FADING_EDGE_HORIZONTAL = 0x00001000
FADING_EDGE_VERTICAL = 0x00002000
OVER_SCROLL_ALWAYS = 0
OVER_SCROLL_IF_CONTENT_SCROLLS = 1
OVER_SCROLL_NEVER = 2
# ─── id / tag ──────────────────────────────────────────────
def setId(self, id_: int):
self._id = id_
def getId(self) -> int:
return self._id
def setTag(self, tag: Any):
self._tag = tag
def getTag(self) -> Any:
return self._tag
# ─── layout params ─────────────────────────────────────────
def setLayoutParams(self, params: "ViewGroup.LayoutParams"):
self._layout_params = params
def getLayoutParams(self) -> Optional["ViewGroup.LayoutParams"]:
return self._layout_params
# ─── visibility ────────────────────────────────────────────
def setVisibility(self, visibility: int):
self._visibility = visibility
def getVisibility(self) -> int:
return self._visibility
def isShown(self) -> bool:
return self._visibility == View.VISIBLE
# ─── position / size ───────────────────────────────────────
def getX(self) -> float:
return self._x
def setX(self, x: float):
self._x = x
def getY(self) -> float:
return self._y
def setY(self, y: float):
self._y = y
def getWidth(self) -> int:
return self._right - self._left
def getHeight(self) -> int:
return self._bottom - self._top
def getLeft(self) -> int:
return self._left
def getTop(self) -> int:
return self._top
def getRight(self) -> int:
return self._right
def getBottom(self) -> int:
return self._bottom
def getMeasuredWidth(self) -> int:
return self._measured_width
def getMeasuredHeight(self) -> int:
return self._measured_height
def setFrame(self, left: int, top: int, right: int, bottom: int) -> bool:
changed = (left != self._left or top != self._top or
right != self._right or bottom != self._bottom)
self._left, self._top, self._right, self._bottom = left, top, right, bottom
return changed
def layout(self, l: int, t: int, r: int, b: int):
old_l, old_t, old_r, old_b = self._left, self._top, self._right, self._bottom
changed = self.setFrame(l, t, r, b)
if changed:
self.onLayout(changed, l - old_l, t - old_t, r - old_r, b - old_b)
def onLayout(self, changed: bool, left: int, top: int, right: int, bottom: int):
pass
def measure(self, width_measure_spec: int, height_measure_spec: int):
self.onMeasure(width_measure_spec, height_measure_spec)
def onMeasure(self, width_measure_spec: int, height_measure_spec: int):
w = View.getDefaultSize(self.getSuggestedMinimumWidth(), width_measure_spec)
h = View.getDefaultSize(self.getSuggestedMinimumHeight(), height_measure_spec)
self.setMeasuredDimension(w, h)
def setMeasuredDimension(self, measured_width: int, measured_height: int):
self._measured_width = measured_width
self._measured_height = measured_height
def getSuggestedMinimumWidth(self) -> int:
return self._min_width
def getSuggestedMinimumHeight(self) -> int:
return self._min_height
def getMinimumWidth(self) -> int:
return self._min_width
def getMinimumHeight(self) -> int:
return self._min_height
def setMinimumWidth(self, min_w: int):
self._min_width = min_w
def setMinimumHeight(self, min_h: int):
self._min_height = min_h
def draw(self, canvas: Any):
self.onDraw(canvas)
def onDraw(self, canvas: Any):
pass
# ─── listeners ─────────────────────────────────────────────
def setOnClickListener(self, listener: Optional[Callable]):
self._on_click_listener = listener
def setOnLongClickListener(self, listener: Optional[Callable]) -> None:
self._on_long_click_listener = listener
def setOnTouchListener(self, listener: Optional[Callable]) -> None:
self._on_touch_listener = listener
def setOnKeyListener(self, listener: Optional[Callable]) -> None:
self._on_key_listener = listener
def callOnClick(self) -> bool:
if self._on_click_listener:
self._on_click_listener(self)
return True
return False
def performClick(self) -> bool:
return self.callOnClick()
def performLongClick(self) -> bool:
if self._on_long_click_listener:
self._on_long_click_listener(self)
return True
return False
# ─── post / delayed ────────────────────────────────────────
def post(self, action: Callable) -> bool:
action()
return True
def postDelayed(self, action: Callable, delay_millis: int) -> bool:
import threading
timer = threading.Timer(delay_millis / 1000.0, action)
timer.daemon = True
timer.start()
self._callbacks[action] = (action, time.time() + delay_millis / 1000.0)
return True
def removeCallbacks(self, action: Optional[Callable] = None):
if action is None:
self._callbacks.clear()
else:
self._callbacks.pop(action, None)
# ─── invalidate / requestLayout ────────────────────────────
def invalidate(self):
pass
def requestLayout(self):
pass
def requestFocus(self, direction: int = FOCUS_FORWARD) -> bool:
if self._visibility != View.VISIBLE or not self._enabled:
return False
return True
# ─── padding ───────────────────────────────────────────────
def setPadding(self, left: int, top: int, right: int, bottom: int):
self._padding_left = left
self._padding_top = top
self._padding_right = right
self._padding_bottom = bottom
def getPaddingLeft(self) -> int:
return self._padding_left
def getPaddingTop(self) -> int:
return self._padding_top
def getPaddingRight(self) -> int:
return self._padding_right
def getPaddingBottom(self) -> int:
return self._padding_bottom
def getPaddingStart(self) -> int:
return self._padding_left
def getPaddingEnd(self) -> int:
return self._padding_right
# ─── background ────────────────────────────────────────────
def setBackgroundColor(self, color: int):
self._background_color = color
self._background_drawable = None
def setBackground(self, background: Any):
self._background_drawable = background
def setBackgroundDrawable(self, background: Any):
self._background_drawable = background
def setBackgroundResource(self, resid: int):
self._background_resource = resid
def getBackground(self) -> Any:
return self._background_drawable
# ─── transform properties ──────────────────────────────────
def setAlpha(self, alpha: float):
self._alpha = alpha
def getAlpha(self) -> float:
return self._alpha
def setRotation(self, rotation: float):
self._rotation = rotation
def getRotation(self) -> float:
return self._rotation
def setScaleX(self, scale_x: float):
self._scale_x = scale_x
def getScaleX(self) -> float:
return self._scale_x
def setScaleY(self, scale_y: float):
self._scale_y = scale_y
def getScaleY(self) -> float:
return self._scale_y
def setTranslationX(self, translation_x: float):
self._translation_x = translation_x
def getTranslationX(self) -> float:
return self._translation_x
def setTranslationY(self, translation_y: float):
self._translation_y = translation_y
def getTranslationY(self) -> float:
return self._translation_y
def getPivotX(self) -> float:
return self._pivot_x
def setPivotX(self, pivot_x: float):
self._pivot_x = pivot_x
def getPivotY(self) -> float:
return self._pivot_y
def setPivotY(self, pivot_y: float):
self._pivot_y = pivot_y
def setElevation(self, elevation: float):
self._elevation = elevation
def getElevation(self) -> float:
return self._elevation
def animate(self) -> "ViewPropertyAnimator":
return ViewPropertyAnimator(self)
# ─── parent / root ─────────────────────────────────────────
def getParent(self) -> Optional["ViewParent"]:
return self._parent
def getRootView(self) -> "View":
v = self
while v._parent is not None:
v = v._parent
return v
# ─── hierarchy ─────────────────────────────────────────────
def findViewById(self, id_: int) -> Optional["View"]:
if self._id == id_:
return self
if hasattr(self, "_children"):
for child in self._children:
result = child.findViewById(id_)
if result is not None:
return result
return None
def bringToFront(self):
if self._parent is not None:
self._parent.bringChildToFront(self)
# ─── enable / focusable / clickable ────────────────────────
def setEnabled(self, enabled: bool):
self._enabled = enabled
def isEnabled(self) -> bool:
return self._enabled
def setFocusable(self, focusable: bool):
self._focusable = focusable
def isFocusable(self) -> bool:
return self._focusable
def setClickable(self, clickable: bool):
self._clickable = clickable
def isClickable(self) -> bool:
return self._clickable
def setLongClickable(self, long_clickable: bool):
self._long_clickable = long_clickable
def isLongClickable(self) -> bool:
return self._long_clickable
def setContextClickable(self, context_clickable: bool):
self._context_clickable = context_clickable
def isContextClickable(self) -> bool:
return self._context_clickable
def setSelected(self, selected: bool):
self._selected = selected
def isSelected(self) -> bool:
return self._selected
def setActivated(self, activated: bool):
self._activated = activated
def isActivated(self) -> bool:
return self._activated
# ─── context / resources ───────────────────────────────────
def getContext(self):
return self._context
def getResources(self):
if hasattr(self._context, "getResources"):
return self._context.getResources()
return None
# ─── scroll ────────────────────────────────────────────────
def setScrollX(self, value: int):
self._scroll_x = value
def setScrollY(self, value: int):
self._scroll_y = value
def getScrollX(self) -> int:
return self._scroll_x
def getScrollY(self) -> int:
return self._scroll_y
def scrollTo(self, x: int, y: int):
self._scroll_x = x
self._scroll_y = y
def scrollBy(self, x: int, y: int):
self._scroll_x += x
self._scroll_y += y
def computeScroll(self):
pass
# ─── drawing / layer ───────────────────────────────────────
def setWillNotDraw(self, will_not_draw: bool):
self._will_not_draw = will_not_draw
def willNotDraw(self) -> bool:
return self._will_not_draw
def setLayerType(self, layer_type: int, paint: Any = None):
self._layer_type = layer_type
def getLayerType(self) -> int:
return self._layer_type
def buildLayer(self):
pass
def setDrawingCacheQuality(self, quality: int):
pass
def getDrawingCacheQuality(self) -> int:
return View.DRAWING_CACHE_QUALITY_AUTO
def getDrawingCache(self, auto_scale: bool = True) -> Any:
return None
def buildDrawingCache(self, auto_scale: bool = True):
pass
def destroyDrawingCache(self):
pass
# ─── layout direction ──────────────────────────────────────
def setLayoutDirection(self, layout_direction: int):
self._layout_direction = layout_direction
def getLayoutDirection(self) -> int:
return self._layout_direction
def setTextDirection(self, text_direction: int):
pass
def getTextDirection(self) -> int:
return 0
def setTextAlignment(self, text_alignment: int):
pass
def getTextAlignment(self) -> int:
return 0
# ─── hit / focus ───────────────────────────────────────────
def onTouchEvent(self, event: "MotionEvent") -> bool:
return self._clickable or self._long_clickable
def onTrackballEvent(self, event: "MotionEvent") -> bool:
return False
def onKeyDown(self, key_code: int, event: "KeyEvent") -> bool:
return False
def onKeyUp(self, key_code: int, event: "KeyEvent") -> bool:
return False
def onKeyLongPress(self, key_code: int, event: "KeyEvent") -> bool:
return False
def onKeyMultiple(self, key_code: int, repeat_count: int, event: "KeyEvent") -> bool:
return False
def dispatchTouchEvent(self, event: "MotionEvent") -> bool:
if self._on_touch_listener is not None:
handled = self._on_touch_listener(self, event)
if handled:
return True
return self.onTouchEvent(event)
def dispatchKeyEvent(self, event: "KeyEvent") -> bool:
if self._on_key_listener is not None:
handled = self._on_key_listener(self, event.getKeyCode(), event)
if handled:
return True
if event.getAction() == KeyEvent.ACTION_DOWN:
return self.onKeyDown(event.getKeyCode(), event)
elif event.getAction() == KeyEvent.ACTION_UP:
return self.onKeyUp(event.getKeyCode(), event)
return False
def dispatchGenericMotionEvent(self, event: "MotionEvent") -> bool:
return False
def hasFocus(self) -> bool:
return False
def isFocused(self) -> bool:
return self.hasFocus()
def clearFocus(self):
pass
def onWindowFocusChanged(self, has_window_focus: bool):
pass
def hasWindowFocus(self) -> bool:
return True
def getWindowToken(self) -> Any:
return None
def getWindowVisibility(self) -> int:
return View.VISIBLE
def getWindowAttachCount(self) -> int:
return 1
def onAttachedToWindow(self):
pass
def onDetachedFromWindow(self):
pass
def isAttachedToWindow(self) -> bool:
return self._parent is not None
# ─── Haptic ────────────────────────────────────────────────
def performHapticFeedback(self, feedback_constant: int) -> bool:
return False
HapticFeedbackConstants = None
# ─── static helpers ────────────────────────────────────────
@staticmethod
def generateViewId() -> int:
View._next_id += 1
return View._next_id
@staticmethod
def getDefaultSize(size: int, measure_spec: int) -> int:
spec_mode = View.MeasureSpec.getMode(measure_spec)
spec_size = View.MeasureSpec.getSize(measure_spec)
if spec_mode == View.UNSPECIFIED:
return size
else:
return spec_size
@staticmethod
def combineMeasuredStates(cur_state: int, new_state: int) -> int:
return cur_state | new_state
@staticmethod
def resolveSize(size: int, measure_spec: int) -> int:
return View.getDefaultSize(size, measure_spec)
@staticmethod
def resolveSizeAndState(size: int, measure_spec: int, child_measured_state: int) -> int:
result = View.resolveSize(size, measure_spec)
return result | (child_measured_state & View.MEASURED_STATE_MASK)
@staticmethod
def inflate(context, resource, root):
return View(context)
# ─── 事件处理 (扩展) ───────────────────────────────────────
def onGenericMotionEvent(self, event) -> bool:
return False
def onHoverEvent(self, event) -> bool:
return False
def onDragEvent(self, event) -> bool:
return False
def onSizeChanged(self, w, h, oldw, oldh):
pass
def onFocusChanged(self, gainFocus, direction, previouslyFocusedRect):
pass
def onScrollChanged(self, l, t, oldl, oldt):
pass
def onVisibilityChanged(self, changedView, visibility):
pass
# ─── 监听器设置 (扩展) ─────────────────────────────────────
def setOnGenericMotionListener(self, listener):
self._on_generic_motion_listener = listener
return self
def setOnHoverListener(self, listener):
self._on_hover_listener = listener
return self
def setOnDragListener(self, listener):
self._on_drag_listener = listener
return self
def setOnFocusChangeListener(self, listener):
self._on_focus_change_listener = listener
return self
def setOnContextClickListener(self, listener):
self._on_context_click_listener = listener
return self
def addOnLayoutChangeListener(self, listener):
if not hasattr(self, '_layout_change_listeners'):
self._layout_change_listeners = []
self._layout_change_listeners.append(listener)
def removeOnLayoutChangeListener(self, listener):
if hasattr(self, '_layout_change_listeners'):
try:
self._layout_change_listeners.remove(listener)
except ValueError:
pass
def setOnApplyWindowInsetsListener(self, listener):
self._on_apply_window_insets_listener = listener
return self
# ─── 位置和尺寸 (扩展) ─────────────────────────────────────
def getLocationOnScreen(self, location):
location[0] = self._left if hasattr(self, '_left') else 0
location[1] = self._top if hasattr(self, '_top') else 0
def getLocationInWindow(self, location):
self.getLocationOnScreen(location)
def offsetLeftAndRight(self, offset):
if hasattr(self, '_left'):
self._left += offset
def offsetTopAndBottom(self, offset):
if hasattr(self, '_top'):
self._top += offset
def getHitRect(self, out_rect):
out_rect.left = self._left if hasattr(self, '_left') else 0
out_rect.top = self._top if hasattr(self, '_top') else 0
out_rect.right = out_rect.left + (self._width if hasattr(self, '_width') else 0)
out_rect.bottom = out_rect.top + (self._height if hasattr(self, '_height') else 0)
def getDrawingRect(self, out_rect):
out_rect.left = 0
out_rect.top = 0
out_rect.right = self._width if hasattr(self, '_width') else 0
out_rect.bottom = self._height if hasattr(self, '_height') else 0
# ─── 其他扩展方法 ──────────────────────────────────────────
def setTooltipText(self, text):
self._tooltip_text = text
def getTooltipText(self):
return getattr(self, '_tooltip_text', None)
def setTranslationZ(self, translationZ):
self._translation_z = translationZ
def getTranslationZ(self):
return getattr(self, '_translation_z', 0.0)
def setZ(self, z):
self._z = z
def getZ(self):
return getattr(self, '_z', 0.0)
def setTransitionName(self, name):
self._transition_name = name
def getTransitionName(self):
return getattr(self, '_transition_name', None)
def setClipToOutline(self, clipToOutline):
self._clip_to_outline = clipToOutline
def getClipToOutline(self):
return getattr(self, '_clip_to_outline', False)
def setFitsSystemWindows(self, fitSystemWindows):
self._fits_system_windows = fitSystemWindows
def getFitsSystemWindows(self):
return getattr(self, '_fits_system_windows', False)
def playSoundEffect(self, soundConstant):
pass
def setSaveEnabled(self, enabled):
self._save_enabled = enabled
def isSaveEnabled(self):
return getattr(self, '_save_enabled', True)
def setSystemUiVisibility(self, visibility):
self._system_ui_visibility = visibility
def getSystemUiVisibility(self):
return getattr(self, '_system_ui_visibility', 0)
def requestApplyInsets(self):
pass
def onApplyWindowInsets(self, insets):
return insets
class MeasureSpec:
"""MeasureSpec — 测量规格包装"""
EXACTLY = View.EXACTLY
AT_MOST = 0x80000000 # -2147483648
UNSPECIFIED = 0
MODE_SHIFT = 30
MODE_MASK = 0xC0000000
@staticmethod
def makeMeasureSpec(size: int, mode: int) -> int:
return (size & ~MeasureSpec.MODE_MASK) | (mode & MeasureSpec.MODE_MASK)
@staticmethod
def getMode(measure_spec: int) -> int:
return measure_spec & MeasureSpec.MODE_MASK
@staticmethod
def getSize(measure_spec: int) -> int:
return measure_spec & ~MeasureSpec.MODE_MASK
@staticmethod
def toString(measure_spec: int) -> str:
mode = MeasureSpec.getMode(measure_spec)
size = MeasureSpec.getSize(measure_spec)
mode_str = "UNSPECIFIED"
if mode == MeasureSpec.EXACTLY:
mode_str = "EXACTLY"
elif mode == MeasureSpec.AT_MOST:
mode_str = "AT_MOST"
return f"MeasureSpec: {mode_str} {size}"
View.MeasureSpec = MeasureSpec
class ViewPropertyAnimator:
"""ViewPropertyAnimator — View 属性动画"""
def __init__(self, view: View):
self._view = view
self._duration: int = 300
self._interpolator: Any = None
def setDuration(self, duration: int) -> "ViewPropertyAnimator":
self._duration = duration
return self
def alpha(self, value: float) -> "ViewPropertyAnimator":
self._view.setAlpha(value)
return self
def translationX(self, value: float) -> "ViewPropertyAnimator":
self._view.setTranslationX(value)
return self
def translationY(self, value: float) -> "ViewPropertyAnimator":
self._view.setTranslationY(value)
return self
def rotation(self, value: float) -> "ViewPropertyAnimator":
self._view.setRotation(value)
return self
def scaleX(self, value: float) -> "ViewPropertyAnimator":
self._view.setScaleX(value)
return self
def scaleY(self, value: float) -> "ViewPropertyAnimator":
self._view.setScaleY(value)
return self
def x(self, value: float) -> "ViewPropertyAnimator":
self._view.setX(value)
return self
def y(self, value: float) -> "ViewPropertyAnimator":
self._view.setY(value)
return self
def start(self):
pass
def cancel(self):
pass
def setInterpolator(self, interpolator: Any) -> "ViewPropertyAnimator":
self._interpolator = interpolator
return self
def withStartAction(self, runnable: Callable) -> "ViewPropertyAnimator":
return self
def withEndAction(self, runnable: Callable) -> "ViewPropertyAnimator":
return self
# ═══════════════════════════════════════════════════════════════
# ViewParent / ViewManager
# ═══════════════════════════════════════════════════════════════
class ViewParent(Stub):
"""ViewParent — 视图父接口"""
def requestLayout(self):
pass
def invalidateChild(self, child: View, r: Any):
pass
def requestChildFocus(self, child: View, focused: View):
pass
def clearChildFocus(self, child: View):
pass
def getParent(self) -> Optional["ViewParent"]:
return None
def bringChildToFront(self, child: View):
pass
def focusSearch(self, child: View, direction: int) -> Optional[View]:
return None
def requestChildRectangleOnScreen(self, child: View, rectangle: Any, immediate: bool) -> bool:
return False
def getChildVisibleRect(self, child: View, r: Any, offset: Any) -> bool:
return False
def requestTransparentRegion(self, child: View):
pass
def onStartNestedScroll(self, child: View, target: View, nested_scroll_axes: int) -> bool:
return False
def onStopNestedScroll(self, target: View):
pass
def onNestedScroll(self, target: View, dx_consumed: int, dy_consumed: int,
dx_unconsumed: int, dy_unconsumed: int):
pass
def onNestedPreScroll(self, target: View, dx: int, dy: int, consumed: List[int]):
pass
def onNestedFling(self, target: View, velocity_x: float, velocity_y: float, consumed: bool) -> bool:
return False
def onNestedPreFling(self, target: View, velocity_x: float, velocity_y: float) -> bool:
return False
def isNestedScrollingEnabled(self) -> bool:
return False
def setNestedScrollingEnabled(self, enabled: bool):
pass
def notifySubtreeAccessibilityStateChanged(self, child: View, source: View, change_type: int):
pass
class ViewManager(Stub):
"""ViewManager — 视图管理接口"""
def addView(self, view: View, params: "ViewGroup.LayoutParams"):
pass
def updateViewLayout(self, view: View, params: "ViewGroup.LayoutParams"):
pass
def removeView(self, view: View):
pass
# ═══════════════════════════════════════════════════════════════
# ViewGroup
# ═══════════════════════════════════════════════════════════════
class ViewGroup(View, ViewParent, ViewManager):
"""ViewGroup — 可包含子视图的容器"""
CLIP_TO_PADDING_MASK = 0x00000001
CLIP_CHILDREN_MASK = 0x00000002
FLAG_CLIP_CHILDREN = 0x00000001
FLAG_CLIP_TO_PADDING = 0x00000002
FLAG_USE_CHILD_DRAWING_ORDER = 0x00000400
def __init__(self, context=None):
super().__init__(context)
self._children: List[View] = []
self._clip_children = True
self._clip_to_padding = True
self._layout_mode = 0
self._child_drawing_order_reversed = False
self._persistent_drawing_cache = False
self._always_drawn_with_cache = True
self._animate_on_set_layout = True
self._add_stateset = True
self._layout_animations = False
# ─── child management ──────────────────────────────────────
def addView(self, child: View, index: int = -1,
params: Optional["ViewGroup.LayoutParams"] = None):
if params is None:
params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
if index < 0 or index >= len(self._children):
self._children.append(child)
else:
self._children.insert(index, child)
child._parent = self
child.setLayoutParams(params)
child.onAttachedToWindow()
def addView(self, child: View, params: Optional["ViewGroup.LayoutParams"] = None):
self.addView(child, -1, params)
def removeView(self, view: View):
if view in self._children:
self._children.remove(view)
view._parent = None
view.onDetachedFromWindow()
def removeViewAt(self, index: int):
if 0 <= index < len(self._children):
self.removeView(self._children[index])
def removeAllViews(self):
for child in list(self._children):
child._parent = None
child.onDetachedFromWindow()
self._children.clear()
def getChildCount(self) -> int:
return len(self._children)
def getChildAt(self, index: int) -> Optional[View]:
if 0 <= index < len(self._children):
return self._children[index]
return None
def indexOfChild(self, child: View) -> int:
try:
return self._children.index(child)
except ValueError:
return -1
def bringChildToFront(self, child: View):
if child in self._children:
self._children.remove(child)
self._children.append(child)
def requestChildFocus(self, child: View, focused: View):
pass
def onInterceptTouchEvent(self, event: "MotionEvent") -> bool:
return False
def onInterceptHoverEvent(self, event: "MotionEvent") -> bool:
return False
def addChildrenForAccessibility(self, children: List[View]):
for child in self._children:
children.append(child)
def setClipChildren(self, clip_children: bool):
self._clip_children = clip_children
def getClipChildren(self) -> bool:
return self._clip_children
def setClipToPadding(self, clip_to_padding: bool):
self._clip_to_padding = clip_to_padding
def getClipToPadding(self) -> bool:
return self._clip_to_padding
def setLayoutAnimation(self, layout_animation: Any):
pass
def getLayoutAnimation(self) -> Any:
return None
def setLayoutMode(self, layout_mode: int):
self._layout_mode = layout_mode
def getLayoutMode(self) -> int:
return self._layout_mode
def setPersistentDrawingCache(self, drawing_cache_to_keep: int):
self._persistent_drawing_cache = bool(drawing_cache_to_keep)
def setAddStatesFromChildren(self, add_states: bool):
self._add_stateset = add_states
def addStatesFromChildren(self) -> bool:
return self._add_stateset
def setChildDrawingOrderCallback(self, callback: Any):
pass
def setChildrenDrawingOrderEnabled(self, enabled: bool):
self._child_drawing_order_reversed = enabled
def isChildrenDrawingOrderEnabled(self) -> bool:
return self._child_drawing_order_reversed
def setChildrenDrawnWithCacheEnabled(self, enabled: bool):
self._always_drawn_with_cache = enabled
def isChildrenDrawnWithCacheEnabled(self) -> bool:
return self._always_drawn_with_cache
def setMotionEventSplittingEnabled(self, split: bool):
pass
def isMotionEventSplittingEnabled(self) -> bool:
return True
def setTransitionGroup(self, is_transition_group: bool):
pass
def isTransitionGroup(self) -> bool:
return False
def startLayoutAnimation(self):
pass
def scheduleLayoutAnimation(self):
pass
def gatherTransparentRegion(self, region: Any) -> bool:
return False
def requestTransparentRegion(self, child: View):
pass
def onChildVisibilityChanged(self, child: View, old_visibility: int, new_visibility: int):
pass
def focusSearch(self, focused: View, direction: int) -> Optional[View]:
return None
def focusableViewAvailable(self, v: View):
pass
def showContextMenuForChild(self, original_view: View) -> bool:
return False
def createContextMenu(self, menu: Any):
pass
def showContextMenu(self) -> bool:
return False
def startActionModeForChild(self, original_view: View, action_mode: Any) -> Optional[Any]:
return None
# ─── LayoutParams ──────────────────────────────────────────
class LayoutParams:
"""ViewGroup.LayoutParams — 布局参数"""
MATCH_PARENT = -1
WRAP_CONTENT = -2
def __init__(self, width: int = WRAP_CONTENT, height: int = WRAP_CONTENT):
self.width = width
self.height = height
@staticmethod
def getSize(size: int) -> int:
return size
# ─── MarginLayoutParams ────────────────────────────────────
class MarginLayoutParams(LayoutParams):
"""ViewGroup.MarginLayoutParams — 带边距的布局参数"""
def __init__(self, width: int = -2, height: int = -2):
super().__init__(width, height)
self.leftMargin = 0
self.topMargin = 0
self.rightMargin = 0
self.bottomMargin = 0
self.startMargin = 0
self.endMargin = 0
def setMargins(self, left: int, top: int, right: int, bottom: int):
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 getMarginStart(self) -> int:
return self.startMargin if self.startMargin != 0 else self.leftMargin
def getMarginEnd(self) -> int:
return self.endMargin if self.endMargin != 0 else self.rightMargin
def setMarginStart(self, start: int):
self.startMargin = start
def setMarginEnd(self, end: int):
self.endMargin = end
# ═══════════════════════════════════════════════════════════════
# WindowManager
# ═══════════════════════════════════════════════════════════════
class WindowManager(ViewManager):
"""WindowManager — 窗口管理器"""
class LayoutParams(ViewGroup.LayoutParams):
"""WindowManager.LayoutParams — 窗口布局参数"""
# 窗口类型
TYPE_FIRST_APPLICATION = 1
TYPE_APPLICATION = 2
TYPE_APPLICATION_STARTING = 3
TYPE_APPLICATION_PANEL = 1000
TYPE_APPLICATION_MEDIA = 1001
TYPE_APPLICATION_SUB_PANEL = 1002
TYPE_APPLICATION_ATTACHED_DIALOG = 1003
TYPE_APPLICATION_OVERLAY = 1004
# 标志位
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001
FLAG_DIM_BEHIND = 0x00000002
FLAG_BLUR_BEHIND = 0x00000004
FLAG_NOT_FOCUSABLE = 0x00000008
FLAG_NOT_TOUCHABLE = 0x00000010
FLAG_NOT_TOUCH_MODAL = 0x00000020
FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040
FLAG_KEEP_SCREEN_ON = 0x00000080
FLAG_LAYOUT_IN_SCREEN = 0x00000100
FLAG_LAYOUT_NO_LIMITS = 0x00000200
FLAG_FULLSCREEN = 0x00000400
FLAG_FORCE_NOT_FULLSCREEN = 0x00000800
FLAG_DITHER = 0x00001000
FLAG_SECURE = 0x00002000
FLAG_SCALED = 0x00004000
FLAG_IGNORE_CHEEK_PRESSES = 0x00008000
FLAG_LAYOUT_INSET_DECOR = 0x00010000
FLAG_ALT_FOCUSABLE_IM = 0x00020000
FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000
FLAG_SHOW_WHEN_LOCKED = 0x00080000
FLAG_SHOW_WALLPAPER = 0x00100000
FLAG_TURN_SCREEN_ON = 0x00200000
FLAG_DISMISS_KEYGUARD = 0x00400000
FLAG_SPLIT_TOUCH = 0x00800000
FLAG_HARDWARE_ACCELERATED = 0x01000000
FLAG_LOCAL_FOCUS_MODE = 0x02000000
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x04000000
FLAG_TRANSLUCENT_STATUS = 0x04000000
FLAG_TRANSLUCENT_NAVIGATION = 0x08000000
# 软输入模式
SOFT_INPUT_STATE_UNSPECIFIED = 0
SOFT_INPUT_STATE_UNCHANGED = 1
SOFT_INPUT_STATE_HIDDEN = 2
SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3
SOFT_INPUT_STATE_VISIBLE = 4
SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5
SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00
SOFT_INPUT_ADJUST_RESIZE = 0x10
SOFT_INPUT_ADJUST_PAN = 0x20
SOFT_INPUT_ADJUST_NOTHING = 0x30
SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100
# 屏幕方向
SCREEN_ORIENTATION_UNSPECIFIED = -1
SCREEN_ORIENTATION_LANDSCAPE = 0
SCREEN_ORIENTATION_PORTRAIT = 1
SCREEN_ORIENTATION_USER = 2
SCREEN_ORIENTATION_BEHIND = 3
SCREEN_ORIENTATION_SENSOR = 4
SCREEN_ORIENTATION_NOSENSOR = 5
SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6
SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7
SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8
SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9
SCREEN_ORIENTATION_FULL_SENSOR = 10
SCREEN_ORIENTATION_USER_LANDSCAPE = 11
SCREEN_ORIENTATION_USER_PORTRAIT = 12
SCREEN_ORIENTATION_FULL_USER = 13
SCREEN_ORIENTATION_LOCKED = 14
# 重力
gravity = Gravity.NO_GRAVITY
x = 0
y = 0
horizontalMargin = 0.0
verticalMargin = 0.0
def __init__(self, w: int = ViewGroup.LayoutParams.WRAP_CONTENT,
h: int = ViewGroup.LayoutParams.WRAP_CONTENT):
super().__init__(w, h)
self.type = WindowManager.LayoutParams.TYPE_APPLICATION
self.flags = 0
self.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
self.screenOrientation = WindowManager.LayoutParams.SCREEN_ORIENTATION_UNSPECIFIED
self.gravity = Gravity.NO_GRAVITY
self.x = 0
self.y = 0
self.token: Any = None
self.windowAnimations: int = 0
self.packageName: str = ""
self.screenBrightness = -1.0
self.buttonBrightness = -1.0
self.rotationAnimation = 0
self.preferredDisplayModeId = 0
self.colorMode = 0
self.format = -1
def __init__(self):
super().__init__()
self._views: Dict[View, WindowManager.LayoutParams] = {}
def addView(self, view: View, params: LayoutParams):
self._views[view] = params
def updateViewLayout(self, view: View, params: LayoutParams):
if view in self._views:
self._views[view] = params
def removeView(self, view: View):
self._views.pop(view, None)
def removeViewImmediate(self, view: View):
self._views.pop(view, None)
def getDefaultDisplay(self) -> "Display":
return Display()
# ═══════════════════════════════════════════════════════════════
# MotionEvent
# ═══════════════════════════════════════════════════════════════
class MotionEvent(Stub):
"""MotionEvent — 触摸事件"""
# 动作常量
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_MOVE = 7
ACTION_HOVER_ENTER = 8
ACTION_HOVER_EXIT = 9
ACTION_SCROLL = 11
ACTION_BUTTON_PRESS = 12
ACTION_BUTTON_RELEASE = 13
# 动作掩码
ACTION_MASK = 0xFF
ACTION_POINTER_INDEX_MASK = 0xFF00
ACTION_POINTER_INDEX_SHIFT = 8
# 按钮
BUTTON_PRIMARY = 1
BUTTON_SECONDARY = 2
BUTTON_TERTIARY = 4
BUTTON_BACK = 8
BUTTON_FORWARD = 16
BUTTON_STYLUS_PRIMARY = 32
BUTTON_STYLUS_SECONDARY = 64
# 边缘
EDGE_LEFT = 1
EDGE_TOP = 2
EDGE_RIGHT = 4
EDGE_BOTTOM = 8
# 坐标分类
AXIS_X = 0
AXIS_Y = 1
AXIS_PRESSURE = 2
AXIS_SIZE = 3
AXIS_TOUCH_MAJOR = 4
AXIS_TOUCH_MINOR = 5
AXIS_TOOL_MAJOR = 6
AXIS_TOOL_MINOR = 7
AXIS_ORIENTATION = 8
AXIS_VSCROLL = 9
AXIS_HSCROLL = 10
AXIS_Z = 11
AXIS_RX = 12
AXIS_RY = 13
AXIS_RZ = 14
AXIS_HAT_X = 15
AXIS_HAT_Y = 16
AXIS_LTRIGGER = 17
AXIS_RTRIGGER = 18
AXIS_THROTTLE = 19
AXIS_RUDDER = 20
AXIS_WHEEL = 21
AXIS_GAS = 22
AXIS_BRAKE = 23
AXIS_DISTANCE = 24
AXIS_TILT = 25
AXIS_SCROLL = 26
AXIS_RELATIVE_X = 27
AXIS_RELATIVE_Y = 28
AXIS_GENERIC_1 = 32
AXIS_GENERIC_2 = 33
AXIS_GENERIC_3 = 34
AXIS_GENERIC_4 = 35
AXIS_GENERIC_5 = 36
AXIS_GENERIC_6 = 37
AXIS_GENERIC_7 = 38
AXIS_GENERIC_8 = 39
AXIS_GENERIC_9 = 40
AXIS_GENERIC_10 = 41
AXIS_GENERIC_11 = 42
AXIS_GENERIC_12 = 43
AXIS_GENERIC_13 = 44
AXIS_GENERIC_14 = 45
AXIS_GENERIC_15 = 46
AXIS_GENERIC_16 = 47
# 输入类型
TOOL_TYPE_UNKNOWN = 0
TOOL_TYPE_FINGER = 1
TOOL_TYPE_STYLUS = 2
TOOL_TYPE_MOUSE = 3
TOOL_TYPE_ERASER = 4
INVALID_POINTER_ID = -1
def __init__(self, action: int = 0, x: float = 0.0, y: float = 0.0,
event_time: int = 0, pointer_count: int = 1,
meta_state: int = 0, button_state: int = 0):
super().__init__()
self._action = action
self._x = x
self._y = y
self._raw_x = x
self._raw_y = y
self._event_time = event_time if event_time else int(time.time() * 1000)
self._down_time = self._event_time
self._pointer_count = pointer_count
self._meta_state = meta_state
self._button_state = button_state
self._pointers: List[Dict] = []
for i in range(pointer_count):
self._pointers.append({
"id": i,
"x": x,
"y": y,
"pressure": 1.0,
"size": 0.5,
"tool_type": MotionEvent.TOOL_TYPE_FINGER,
})
@classmethod
def obtain(cls, down_time: int, event_time: int, action: int,
x: float, y: float, meta_state: int = 0) -> "MotionEvent":
return cls(action=action, x=x, y=y, event_time=event_time)
@classmethod
def obtainNoHistory(cls, me: "MotionEvent") -> "MotionEvent":
return cls(action=me._action, x=me._x, y=me._y,
event_time=me._event_time, pointer_count=me._pointer_count)
def recycle(self):
pass
def getAction(self) -> int:
return self._action
def getActionMasked(self) -> int:
return self._action & MotionEvent.ACTION_MASK
def getActionIndex(self) -> int:
return (self._action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT
def getX(self, pointer_index: int = 0) -> float:
if 0 <= pointer_index < len(self._pointers):
return self._pointers[pointer_index]["x"]
return self._x
def getY(self, pointer_index: int = 0) -> float:
if 0 <= pointer_index < len(self._pointers):
return self._pointers[pointer_index]["y"]
return self._y
def getRawX(self) -> float:
return self._raw_x
def getRawY(self) -> float:
return self._raw_y
def getPointerCount(self) -> int:
return self._pointer_count
def getPointerId(self, pointer_index: int) -> int:
if 0 <= pointer_index < len(self._pointers):
return self._pointers[pointer_index]["id"]
return pointer_index
def findPointerIndex(self, pointer_id: int) -> int:
for i, p in enumerate(self._pointers):
if p["id"] == pointer_id:
return i
return -1
def getPressure(self, pointer_index: int = 0) -> float:
if 0 <= pointer_index < len(self._pointers):
return self._pointers[pointer_index]["pressure"]
return 1.0
def getSize(self, pointer_index: int = 0) -> float:
if 0 <= pointer_index < len(self._pointers):
return self._pointers[pointer_index]["size"]
return 0.5
def getEventTime(self) -> int:
return self._event_time
def getDownTime(self) -> int:
return self._down_time
def getMetaState(self) -> int:
return self._meta_state
def getButtonState(self) -> int:
return self._button_state
def getToolType(self, pointer_index: int = 0) -> int:
if 0 <= pointer_index < len(self._pointers):
return self._pointers[pointer_index]["tool_type"]
return MotionEvent.TOOL_TYPE_FINGER
def setLocation(self, x: float, y: float):
self._x = x
self._y = y
def offsetLocation(self, dx: float, dy: float):
self._x += dx
self._y += dy
def transform(self, matrix: Any):
pass
def isLongPress(self) -> bool:
return (self._event_time - self._down_time) > 500
def getHistoricalSize(self, pos: int, pointer: int = 0) -> float:
return 0.5
# ═══════════════════════════════════════════════════════════════
# KeyEvent
# ═══════════════════════════════════════════════════════════════
class KeyEvent(Stub):
"""KeyEvent — 按键事件"""
# 动作
ACTION_DOWN = 0
ACTION_UP = 1
ACTION_MULTIPLE = 2
# 键码
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_META_CTRL_LEFT = 164
KEYCODE_META_CTRL_RIGHT = 165
KEYCODE_META_ALT_LEFT = 166
KEYCODE_META_ALT_RIGHT = 167
KEYCODE_META_SHIFT_LEFT = 168
KEYCODE_META_SHIFT_RIGHT = 169
KEYCODE_META_SYM = 170
# 元键掩码
META_ALT_ON = 0x02
META_ALT_LEFT_ON = 0x10
META_ALT_RIGHT_ON = 0x20
META_SHIFT_ON = 0x01
META_SHIFT_LEFT_ON = 0x40
META_SHIFT_RIGHT_ON = 0x80
META_SYM_ON = 0x04
META_FUNCTION_ON = 0x08
META_CTRL_ON = 0x1000
META_CTRL_LEFT_ON = 0x2000
META_CTRL_RIGHT_ON = 0x4000
META_META_ON = 0x10000
META_META_LEFT_ON = 0x20000
META_META_RIGHT_ON = 0x40000
META_CAPS_LOCK_ON = 0x100000
META_NUM_LOCK_ON = 0x200000
META_SCROLL_LOCK_ON = 0x400000
def __init__(self, action: int = ACTION_DOWN, key_code: int = KEYCODE_UNKNOWN,
repeat_count: int = 0, event_time: int = 0,
meta_state: int = 0):
super().__init__()
self._action = action
self._key_code = key_code
self._repeat_count = repeat_count
self._event_time = event_time if event_time else int(time.time() * 1000)
self._down_time = self._event_time
self._meta_state = meta_state
self._device_id = 0
self._source = 0x101 # InputDevice.SOURCE_KEYBOARD
self._flags = 0
self._display_id = 0
getAction = lambda self: self._action
getKeyCode = lambda self: self._key_code
getRepeatCount = lambda self: self._repeat_count
getEventTime = lambda self: self._event_time
getDownTime = lambda self: self._down_time
getMetaState = lambda self: self._meta_state
getDeviceId = lambda self: self._device_id
getSource = lambda self: self._source
getFlags = lambda self: self._flags
getDisplayId = lambda self: self._display_id
def isLongPress(self) -> bool:
return self._repeat_count > 0
def dispatch(self, receiver: View, on_receive: Callable) -> bool:
return on_receive(receiver, self)
def isAltPressed(self) -> bool:
return bool(self._meta_state & KeyEvent.META_ALT_ON)
def isShiftPressed(self) -> bool:
return bool(self._meta_state & KeyEvent.META_SHIFT_ON)
def isCtrlPressed(self) -> bool:
return bool(self._meta_state & KeyEvent.META_CTRL_ON)
def isMetaPressed(self) -> bool:
return bool(self._meta_state & KeyEvent.META_META_ON)
def isSymPressed(self) -> bool:
return bool(self._meta_state & KeyEvent.META_SYM_ON)
def isFunctionPressed(self) -> bool:
return bool(self._meta_state & KeyEvent.META_FUNCTION_ON)
def isCapsLockOn(self) -> bool:
return bool(self._meta_state & KeyEvent.META_CAPS_LOCK_ON)
def isNumLockOn(self) -> bool:
return bool(self._meta_state & KeyEvent.META_NUM_LOCK_ON)
def isScrollLockOn(self) -> bool:
return bool(self._meta_state & KeyEvent.META_SCROLL_LOCK_ON)
@staticmethod
def changeTimeRepeat(event: "KeyEvent", event_time: int, repeat_count: int) -> "KeyEvent":
return KeyEvent(
action=event._action,
key_code=event._key_code,
repeat_count=repeat_count,
event_time=event_time,
meta_state=event._meta_state,
)
@staticmethod
def changeAction(event: "KeyEvent", action: int) -> "KeyEvent":
return KeyEvent(
action=action,
key_code=event._key_code,
repeat_count=event._repeat_count,
event_time=event._event_time,
meta_state=event._meta_state,
)
# ═══════════════════════════════════════════════════════════════
# GestureDetector
# ═══════════════════════════════════════════════════════════════
class GestureDetector(Stub):
"""GestureDetector — 手势检测器"""
class SimpleOnGestureListener:
"""SimpleOnGestureListener — 简单手势监听器"""
def onDown(self, e: MotionEvent) -> bool:
return False
def onShowPress(self, e: MotionEvent):
pass
def onSingleTapUp(self, e: MotionEvent) -> bool:
return False
def onScroll(self, e1: MotionEvent, e2: MotionEvent,
distance_x: float, distance_y: float) -> bool:
return False
def onLongPress(self, e: MotionEvent):
pass
def onFling(self, e1: MotionEvent, e2: MotionEvent,
velocity_x: float, velocity_y: float) -> bool:
return False
def onSingleTapConfirmed(self, e: MotionEvent) -> bool:
return False
def onDoubleTap(self, e: MotionEvent) -> bool:
return False
def onDoubleTapEvent(self, e: MotionEvent) -> bool:
return False
def onContextClick(self, e: MotionEvent) -> bool:
return False
class OnGestureListener:
def onDown(self, e: MotionEvent) -> bool:
return False
def onShowPress(self, e: MotionEvent):
pass
def onSingleTapUp(self, e: MotionEvent) -> bool:
return False
def onScroll(self, e1: MotionEvent, e2: MotionEvent,
distance_x: float, distance_y: float) -> bool:
return False
def onLongPress(self, e: MotionEvent):
pass
def onFling(self, e1: MotionEvent, e2: MotionEvent,
velocity_x: float, velocity_y: float) -> bool:
return False
class OnDoubleTapListener:
def onSingleTapConfirmed(self, e: MotionEvent) -> bool:
return False
def onDoubleTap(self, e: MotionEvent) -> bool:
return False
def onDoubleTapEvent(self, e: MotionEvent) -> bool:
return False
def __init__(self, context=None, listener: Optional["GestureDetector.OnGestureListener"] = None,
handler: Any = None):
super().__init__()
self._listener = listener
self._double_tap_listener: Optional["GestureDetector.OnDoubleTapListener"] = None
self._is_longpress_enabled = True
self._context = context
self._current_down_event: Optional[MotionEvent] = None
self._previous_down_event: Optional[MotionEvent] = None
self._in_long_press = False
self._long_press_timeout = 500
self._touch_slop = 8
def setOnDoubleTapListener(self, listener: Optional["GestureDetector.OnDoubleTapListener"]):
self._double_tap_listener = listener
def setIsLongpressEnabled(self, enabled: bool):
self._is_longpress_enabled = enabled
def isLongpressEnabled(self) -> bool:
return self._is_longpress_enabled
def onTouchEvent(self, ev: MotionEvent) -> bool:
action = ev.getAction()
if action == MotionEvent.ACTION_DOWN:
self._in_long_press = False
self._current_down_event = ev
if self._listener:
return self._listener.onDown(ev)
elif action == MotionEvent.ACTION_MOVE:
pass
elif action == MotionEvent.ACTION_UP:
if self._listener:
return self._listener.onSingleTapUp(ev)
elif action == MotionEvent.ACTION_CANCEL:
pass
return False
def setContextClickListener(self, listener: Callable):
pass
def setContextClickable(self, context_clickable: bool):
pass
def isContextClickable(self) -> bool:
return False
# ═══════════════════════════════════════════════════════════════
# ScaleGestureDetector
# ═══════════════════════════════════════════════════════════════
class ScaleGestureDetector(Stub):
"""ScaleGestureDetector — 缩放手势检测器"""
class SimpleOnScaleGestureListener:
"""SimpleOnScaleGestureListener — 简单缩放手势监听器"""
def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool:
return True
def onScale(self, detector: "ScaleGestureDetector") -> bool:
return False
def onScaleEnd(self, detector: "ScaleGestureDetector"):
pass
class OnScaleGestureListener:
def onScaleBegin(self, detector: "ScaleGestureDetector") -> bool:
return True
def onScale(self, detector: "ScaleGestureDetector") -> bool:
return False
def onScaleEnd(self, detector: "ScaleGestureDetector"):
pass
def __init__(self, context=None, listener: Optional[OnScaleGestureListener] = None):
super().__init__()
self._listener = listener
self._scale_factor = 1.0
self._current_span = 0.0
self._current_span_x = 0.0
self._current_span_y = 0.0
self._focus_x = 0.0
self._focus_y = 0.0
self._previous_span = 0.0
self._time_delta = 0
self._in_progress = False
def getScaleFactor(self) -> float:
return self._scale_factor
def getCurrentSpan(self) -> float:
return self._current_span
def getCurrentSpanX(self) -> float:
return self._current_span_x
def getCurrentSpanY(self) -> float:
return self._current_span_y
def getPreviousSpan(self) -> float:
return self._previous_span
def getPreviousSpanX(self) -> float:
return self._current_span_x
def getPreviousSpanY(self) -> float:
return self._current_span_y
def getFocusX(self) -> float:
return self._focus_x
def getFocusY(self) -> float:
return self._focus_y
def getTimeDelta(self) -> int:
return self._time_delta
def getEventTime(self) -> int:
return int(time.time() * 1000)
def isInProgress(self) -> bool:
return self._in_progress
def onTouchEvent(self, event: MotionEvent) -> bool:
action = event.getActionMasked()
if action == MotionEvent.ACTION_DOWN:
self._in_progress = False
elif action == MotionEvent.ACTION_POINTER_DOWN:
if event.getPointerCount() >= 2:
self._in_progress = True
x1, y1 = event.getX(0), event.getY(0)
x2, y2 = event.getX(1), event.getY(1)
self._current_span = math.hypot(x2 - x1, y2 - y1)
self._focus_x = (x1 + x2) / 2.0
self._focus_y = (y1 + y2) / 2.0
if self._listener:
self._listener.onScaleBegin(self)
return True
elif action == MotionEvent.ACTION_MOVE:
if self._in_progress and event.getPointerCount() >= 2:
x1, y1 = event.getX(0), event.getY(0)
x2, y2 = event.getX(1), event.getY(1)
new_span = math.hypot(x2 - x1, y2 - y1)
self._previous_span = self._current_span
self._current_span = new_span
if self._previous_span > 0:
self._scale_factor = self._current_span / self._previous_span
self._focus_x = (x1 + x2) / 2.0
self._focus_y = (y1 + y2) / 2.0
if self._listener:
self._listener.onScale(self)
return True
elif action in (MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL):
if self._in_progress and self._listener:
self._listener.onScaleEnd(self)
self._in_progress = False
return False
# ═══════════════════════════════════════════════════════════════
# VelocityTracker
# ═══════════════════════════════════════════════════════════════
class VelocityTracker(Stub):
"""VelocityTracker — 速度追踪器"""
def __init__(self):
super().__init__()
self._movements: List[Tuple[float, float, float]] = [] # (x, y, time)
self._x_velocity: float = 0.0
self._y_velocity: float = 0.0
@staticmethod
def obtain() -> "VelocityTracker":
return VelocityTracker()
@staticmethod
def obtainUnit(max_units: int, generator_id: int) -> "VelocityTracker":
return VelocityTracker()
def addMovement(self, event: MotionEvent):
self._movements.append((event.getRawX(), event.getRawY(),
event.getEventTime() / 1000.0))
if len(self._movements) > 100:
self._movements = self._movements[-50:]
def computeCurrentVelocity(self, units: int, max_velocity: float = float("inf")):
if len(self._movements) < 2:
self._x_velocity = 0.0
self._y_velocity = 0.0
return
recent = self._movements[-4:] if len(self._movements) >= 4 else self._movements
first_x, first_y, first_t = recent[0]
last_x, last_y, last_t = recent[-1]
dt = last_t - first_t
if dt > 0:
unit_scale = units / 1000.0
self._x_velocity = (last_x - first_x) / dt * unit_scale
self._y_velocity = (last_y - first_y) / dt * unit_scale
self._x_velocity = max(-max_velocity, min(max_velocity, self._x_velocity))
self._y_velocity = max(-max_velocity, min(max_velocity, self._y_velocity))
else:
self._x_velocity = 0.0
self._y_velocity = 0.0
def getXVelocity(self, id_: int = -1) -> float:
return self._x_velocity
def getYVelocity(self, id_: int = -1) -> float:
return self._y_velocity
def recycle(self):
self._movements.clear()
self._x_velocity = 0.0
self._y_velocity = 0.0
def clear(self):
self._movements.clear()
def getEstimator(self) -> Any:
return None
# ═══════════════════════════════════════════════════════════════
# DragEvent
# ═══════════════════════════════════════════════════════════════
class DragEvent(Stub):
"""DragEvent — 拖放事件"""
ACTION_DRAG_STARTED = 1
ACTION_DRAG_LOCATION = 2
ACTION_DROP = 3
ACTION_DRAG_ENTERED = 4
ACTION_DRAG_EXITED = 5
ACTION_DRAG_ENDED = 6
def __init__(self, action: int = 0, x: float = 0.0, y: float = 0.0,
clip_data: Any = None, result: bool = False):
super().__init__()
self._action = action
self._x = x
self._y = y
self._clip_data = clip_data
self._result = result
self._local_state: 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) -> Any:
return self._clip_data
def getResult(self) -> bool:
return self._result
def getLocalState(self) -> Any:
return self._local_state
def setLocalState(self, state: Any):
self._local_state = state
def toString(self) -> str:
action_names = {
1: "ACTION_DRAG_STARTED",
2: "ACTION_DRAG_LOCATION",
3: "ACTION_DROP",
4: "ACTION_DRAG_ENTERED",
5: "ACTION_DRAG_EXITED",
6: "ACTION_DRAG_ENDED",
}
name = action_names.get(self._action, f"UNKNOWN({self._action})")
return f"DragEvent(action={name}, x={self._x}, y={self._y})"
# ═══════════════════════════════════════════════════════════════
# AccessibilityDelegate
# ═══════════════════════════════════════════════════════════════
class AccessibilityDelegate(Stub):
"""AccessibilityDelegate — 辅助功能委托"""
def sendAccessibilityEvent(self, host: View, event_type: int):
pass
def sendAccessibilityEventUnchecked(self, host: View, event: Any):
pass
def dispatchPopulateAccessibilityEvent(self, host: View, event: Any) -> bool:
return False
def onPopulateAccessibilityEvent(self, host: View, event: Any):
pass
def onInitializeAccessibilityEvent(self, host: View, event: Any):
pass
def onInitializeAccessibilityNodeInfo(self, host: View, info: Any):
pass
def onRequestSendAccessibilityEvent(self, host: ViewGroup, child: View, event: Any) -> bool:
return True
def getAccessibilityNodeProvider(self, host: View) -> Optional[Any]:
return None
def performAccessibilityAction(self, host: View, action: int, arguments: Any) -> bool:
return False
# ═══════════════════════════════════════════════════════════════
# ViewTreeObserver
# ═══════════════════════════════════════════════════════════════
class ViewTreeObserver(Stub):
"""ViewTreeObserver — 视图树观察者"""
class OnGlobalLayoutListener:
def onGlobalLayout(self):
pass
class OnGlobalFocusChangeListener:
def onGlobalFocusChanged(self, old_focus: View, new_focus: View):
pass
class OnScrollChangedListener:
def onScrollChanged(self):
pass
class OnTouchModeChangeListener:
def onTouchModeChanged(self, is_in_touch_mode: bool):
pass
class OnWindowAttachListener:
def onWindowAttached(self):
pass
def onWindowDetached(self):
pass
class OnWindowFocusChangeListener:
def onWindowFocusChanged(self, has_focus: bool):
pass
class OnDrawListener:
def onDraw(self):
pass
class OnPreDrawListener:
def onPreDraw(self) -> bool:
return True
class OnWindowShownListener:
def onWindowShown(self):
pass
def __init__(self):
super().__init__()
self._global_layout_listeners: List[ViewTreeObserver.OnGlobalLayoutListener] = []
self._scroll_changed_listeners: List[ViewTreeObserver.OnScrollChangedListener] = []
self._pre_draw_listeners: List[ViewTreeObserver.OnPreDrawListener] = []
self._draw_listeners: List[ViewTreeObserver.OnDrawListener] = []
self._touch_mode_listeners: List[ViewTreeObserver.OnTouchModeChangeListener] = []
self._window_focus_listeners: List[ViewTreeObserver.OnWindowFocusChangeListener] = []
self._window_attach_listeners: List[ViewTreeObserver.OnWindowAttachListener] = []
self._alive = True
def addOnGlobalLayoutListener(self, listener: OnGlobalLayoutListener):
self._global_layout_listeners.append(listener)
def removeOnGlobalLayoutListener(self, listener: OnGlobalLayoutListener):
if listener in self._global_layout_listeners:
self._global_layout_listeners.remove(listener)
def addOnScrollChangedListener(self, listener: OnScrollChangedListener):
self._scroll_changed_listeners.append(listener)
def removeOnScrollChangedListener(self, listener: OnScrollChangedListener):
if listener in self._scroll_changed_listeners:
self._scroll_changed_listeners.remove(listener)
def addOnPreDrawListener(self, listener: OnPreDrawListener):
self._pre_draw_listeners.append(listener)
def removeOnPreDrawListener(self, listener: OnPreDrawListener):
if listener in self._pre_draw_listeners:
self._pre_draw_listeners.remove(listener)
def addOnDrawListener(self, listener: OnDrawListener):
self._draw_listeners.append(listener)
def removeOnDrawListener(self, listener: OnDrawListener):
if listener in self._draw_listeners:
self._draw_listeners.remove(listener)
def addOnGlobalFocusChangeListener(self, listener: OnGlobalFocusChangeListener):
pass
def removeOnGlobalFocusChangeListener(self, listener: OnGlobalFocusChangeListener):
pass
def addOnTouchModeChangeListener(self, listener: OnTouchModeChangeListener):
self._touch_mode_listeners.append(listener)
def removeOnTouchModeChangeListener(self, listener: OnTouchModeChangeListener):
if listener in self._touch_mode_listeners:
self._touch_mode_listeners.remove(listener)
def addOnWindowAttachListener(self, listener: OnWindowAttachListener):
self._window_attach_listeners.append(listener)
def removeOnWindowAttachListener(self, listener: OnWindowAttachListener):
if listener in self._window_attach_listeners:
self._window_attach_listeners.remove(listener)
def addOnWindowFocusChangeListener(self, listener: OnWindowFocusChangeListener):
self._window_focus_listeners.append(listener)
def removeOnWindowFocusChangeListener(self, listener: OnWindowFocusChangeListener):
if listener in self._window_focus_listeners:
self._window_focus_listeners.remove(listener)
def addOnWindowShownListener(self, listener: OnWindowShownListener):
pass
def removeOnWindowShownListener(self, listener: OnWindowShownListener):
pass
def dispatchOnGlobalLayout(self):
for listener in list(self._global_layout_listeners):
listener.onGlobalLayout()
def dispatchOnScrollChanged(self):
for listener in list(self._scroll_changed_listeners):
listener.onScrollChanged()
def isAlive(self) -> bool:
return self._alive
def kill(self):
self._alive = False
self._global_layout_listeners.clear()
self._scroll_changed_listeners.clear()
self._pre_draw_listeners.clear()
self._draw_listeners.clear()
# ═══════════════════════════════════════════════════════════════
# ViewConfiguration
# ═══════════════════════════════════════════════════════════════
class ViewConfiguration(Stub):
"""ViewConfiguration — 视图配置常量"""
def __init__(self, context=None):
super().__init__()
if context is None:
context = android_context
self._context = context
@staticmethod
def get(context=None) -> "ViewConfiguration":
return ViewConfiguration(context)
@staticmethod
def getLongPressTimeout() -> int:
return 500
@staticmethod
def getTapTimeout() -> int:
return 100
@staticmethod
def getJumpTapTimeout() -> int:
return 500
@staticmethod
def getDoubleTapTimeout() -> int:
return 300
@staticmethod
def getEdgeSlop() -> int:
return 12
@staticmethod
def getTouchSlop() -> int:
return 8
@staticmethod
def getScaledTouchSlop(self) -> int:
return 8
@staticmethod
def getScaledEdgeSlop(self) -> int:
return 12
@staticmethod
def getScaledFadingEdgeLength(self) -> int:
return 12
@staticmethod
def getScaledMinimumFlingVelocity(self) -> int:
return 50
@staticmethod
def getScaledMaximumFlingVelocity(self) -> int:
return 8000
@staticmethod
def getScaledPagingTouchSlop(self) -> int:
return 16
@staticmethod
def getScaledOverflingDistance(self) -> int:
return 32
@staticmethod
def getScaledOverscrollDistance(self) -> int:
return 32
@staticmethod
def getScaledScrollFactor(self) -> int:
return 64
@staticmethod
def getScrollFriction() -> float:
return 0.015
@staticmethod
def getMaximumDrawingCacheSize() -> int:
return 480 * 800 * 4
@staticmethod
def getWindowTouchSlop() -> int:
return 16
@staticmethod
def getGlobalActionKeySlop() -> int:
return 12
def getScaledWindowTouchSlop(self) -> int:
return 16
# ═══════════════════════════════════════════════════════════════
# SurfaceView
# ═══════════════════════════════════════════════════════════════
class SurfaceView(View):
"""SurfaceView — 表面视图,用于直接绘制"""
def __init__(self, context=None):
super().__init__(context)
self._surface = Surface()
self._surface_holder = SurfaceHolder()
def getHolder(self) -> "SurfaceHolder":
return self._surface_holder
def getSurfaceControl(self) -> Any:
return None
def setVisibility(self, visibility: int):
super().setVisibility(visibility)
def setSecure(self, is_secure: bool):
pass
def setZOrderMediaOverlay(self, is_media_overlay: bool):
pass
def setZOrderOnTop(self, on_top: bool):
pass
def gatherTransparentRegion(self, region: Any) -> bool:
return False
def draw(self, canvas: Any):
pass
class SurfaceHolder(Stub):
"""SurfaceHolder — Surface 持有者"""
class Callback:
def surfaceCreated(self, holder: "SurfaceHolder"):
pass
def surfaceChanged(self, holder: "SurfaceHolder", format: int, width: int, height: int):
pass
def surfaceDestroyed(self, holder: "SurfaceHolder"):
pass
class Callback2(Callback):
def surfaceRedrawNeeded(self, holder: "SurfaceHolder"):
pass
SURFACE_TYPE_NORMAL = 0
SURFACE_TYPE_HARDWARE = 1
SURFACE_TYPE_GPU = 2
SURFACE_TYPE_PUSH_BUFFERS = 3
def __init__(self):
super().__init__()
self._surface = Surface()
self._callbacks: List[SurfaceHolder.Callback] = []
self._type = SurfaceHolder.SURFACE_TYPE_NORMAL
self._fixed_size: Optional[Tuple[int, int]] = None
self._format = -1
def getSurface(self) -> "Surface":
return self._surface
def addCallback(self, callback: Callback):
self._callbacks.append(callback)
def removeCallback(self, callback: Callback):
if callback in self._callbacks:
self._callbacks.remove(callback)
def isCreating(self) -> bool:
return False
def setType(self, type_: int):
self._type = type_
def setFixedSize(self, width: int, height: int):
self._fixed_size = (width, height)
def setSizeFromLayout(self):
self._fixed_size = None
def setFormat(self, format: int):
self._format = format
def lockCanvas(self) -> Any:
return None
def lockCanvas(self, dirty: Any) -> Any:
return None
def unlockCanvasAndPost(self, canvas: Any):
pass
# ═══════════════════════════════════════════════════════════════
# TextureView
# ═══════════════════════════════════════════════════════════════
class TextureView(View):
"""TextureView — 纹理视图"""
def __init__(self, context=None):
super().__init__(context)
self._surface_texture = SurfaceTexture()
self._layer = None
self._update_listener: Optional[Callable] = None
self._surface_texture_listener: Optional[Callable] = None
class SurfaceTextureListener:
def onSurfaceTextureAvailable(self, surface: "SurfaceTexture", width: int, height: int):
pass
def onSurfaceTextureSizeChanged(self, surface: "SurfaceTexture", width: int, height: int):
pass
def onSurfaceTextureDestroyed(self, surface: "SurfaceTexture") -> bool:
return True
def onSurfaceTextureUpdated(self, surface: "SurfaceTexture"):
pass
def isOpaque(self) -> bool:
return False
def setOpaque(self, opaque: bool):
pass
def getSurfaceTexture(self) -> "SurfaceTexture":
return self._surface_texture
def setSurfaceTexture(self, surface_texture: "SurfaceTexture"):
self._surface_texture = surface_texture
def setSurfaceTextureListener(self, listener: SurfaceTextureListener):
self._surface_texture_listener = listener
def getSurfaceTextureListener(self) -> Optional[SurfaceTextureListener]:
return self._surface_texture_listener
def buildLayer(self):
pass
def setLayerPaint(self, paint: Any):
pass
def getLayerPaint(self) -> Any:
return None
def setTransform(self, transform: Any):
pass
def getTransform(self, transform: Any) -> Any:
return transform
def draw(self, canvas: Any):
pass
def lockCanvas(self) -> Any:
return None
def unlockCanvasAndPost(self, canvas: Any):
pass
class SurfaceTexture(Stub):
"""SurfaceTexture — 表面纹理"""
def __init__(self, tex_name: int = 0, allow_legacy: bool = True):
super().__init__()
self._tex_name = tex_name
self._timestamp = 0
self._frame_available_listener: Optional[Callable] = None
self._default_buffer_size: Optional[Tuple[int, int]] = None
def setOnFrameAvailableListener(self, listener: Callable, handler: Any = None):
self._frame_available_listener = listener
def getTimestamp(self) -> int:
return self._timestamp
def updateTexImage(self):
pass
def release(self):
pass
def setDefaultBufferSize(self, width: int, height: int):
self._default_buffer_size = (width, height)
def getTransformMatrix(self, mtx: List[float]):
for i in range(16):
mtx[i] = 1.0 if i % 5 == 0 else 0.0
# ═══════════════════════════════════════════════════════════════
# MenuInflater
# ═══════════════════════════════════════════════════════════════
class MenuInflater(Stub):
"""MenuInflater — 菜单填充器(桌面环境桩实现)"""
def __init__(self, context=None):
super().__init__()
self._context = context
def inflate(self, menu_res: int, menu: Any):
return menu
def toString(self) -> str:
return f"MenuInflater@{hex(id(self))}"
# ═══════════════════════════════════════════════════════════════
# Window
# ═══════════════════════════════════════════════════════════════
class Window(Stub):
"""Window — 抽象窗口基类"""
# 特性ID
FEATURES_DEFAULT = -1
FEATURE_OPTIONS_PANEL = 0
FEATURE_NO_TITLE = 1
FEATURE_PROGRESS = 2
FEATURE_LEFT_ICON = 3
FEATURE_RIGHT_ICON = 4
FEATURE_INDETERMINATE_PROGRESS = 5
FEATURE_CONTEXT_MENU = 6
FEATURE_CUSTOM_TITLE = 7
FEATURE_ACTION_BAR = 8
FEATURE_ACTION_BAR_OVERLAY = 9
FEATURE_ACTION_MODE_OVERLAY = 10
FEATURE_SWIPE_TO_DISMISS = 11
FEATURE_CONTENT_TRANSITIONS = 12
FEATURE_WATCH = 13
# 本地特性
ID_ANDROID_CONTENT = 0x01020002
DECOR_CAPTION_SHORTCUT_DURATION_MS = 1000
# 标志
NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "navigationBarBackground"
STATUS_BAR_BACKGROUND_TRANSITION_NAME = "statusBarBackground"
def __init__(self, context=None):
super().__init__()
if context is None:
context = android_context
self._context = context
self._features: Dict[int, bool] = {}
self._title: str = ""
self._decor_view: Optional[View] = None
self._callback: Optional["Window.Callback"] = None
self._window_manager: Optional[WindowManager] = None
self._soft_input_mode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
self._flags: Dict[int, bool] = {}
self._container: Optional[Window] = None
self._local_features: List[int] = []
class Callback:
def dispatchKeyEvent(self, event: KeyEvent) -> bool:
return False
def dispatchTouchEvent(self, event: MotionEvent) -> bool:
return False
def dispatchTrackballEvent(self, event: MotionEvent) -> bool:
return False
def dispatchGenericMotionEvent(self, event: MotionEvent) -> bool:
return False
def dispatchPopulateAccessibilityEvent(self, event: Any) -> bool:
return False
def onCreatePanelView(self, feature_id: int) -> Optional[View]:
return None
def onCreatePanelMenu(self, feature_id: int, menu: Any) -> bool:
return False
def onPreparePanel(self, feature_id: int, view: View, menu: Any) -> bool:
return False
def onMenuOpened(self, feature_id: int, menu: Any):
pass
def onMenuItemSelected(self, feature_id: int, item: Any) -> bool:
return False
def onWindowAttributesChanged(self, attrs: Any):
pass
def onContentChanged(self):
pass
def onWindowFocusChanged(self, has_focus: bool):
pass
def onAttachedToWindow(self):
pass
def onDetachedFromWindow(self):
pass
def onPanelClosed(self, feature_id: int, menu: Any):
pass
def onSearchRequested(self) -> bool:
return False
def onSearchRequested(self, search_event: Any) -> bool:
return False
def onActionModeStarted(self, mode: Any):
pass
def onActionModeFinished(self, mode: Any):
pass
def onWindowStartingActionMode(self, callback: Any) -> Optional[Any]:
return None
def onWindowStartingActionMode(self, callback: Any, type_: int) -> Optional[Any]:
return None
def setContentView(self, layout_res_id: int):
pass
def setContentView(self, view: View):
pass
def setContentView(self, view: View, params: ViewGroup.LayoutParams):
pass
def addContentView(self, view: View, params: ViewGroup.LayoutParams):
pass
def setTitle(self, title: str):
self._title = title
def getTitle(self) -> str:
return self._title
def setFeatureInt(self, feature_id: int, value: int):
self._features[feature_id] = True
def requestFeature(self, feature_id: int) -> bool:
self._features[feature_id] = True
return True
def hasFeature(self, feature_id: int) -> bool:
return self._features.get(feature_id, False)
def setFlags(self, flags: int, mask: int):
for flag_bit in range(32):
if mask & (1 << flag_bit):
self._flags[1 << flag_bit] = bool(flags & (1 << flag_bit))
def addFlags(self, flags: int):
for flag_bit in range(32):
if flags & (1 << flag_bit):
self._flags[1 << flag_bit] = True
def clearFlags(self, flags: int):
for flag_bit in range(32):
if flags & (1 << flag_bit):
self._flags[1 << flag_bit] = False
def setSoftInputMode(self, soft_input_mode: int):
self._soft_input_mode = soft_input_mode
def getSoftInputMode(self) -> int:
return self._soft_input_mode
def setLayout(self, width: int, height: int):
pass
def findViewById(self, id_: int) -> Optional[View]:
if self._decor_view:
return self._decor_view.findViewById(id_)
return None
def getDecorView(self) -> Optional[View]:
return self._decor_view
def setDecorView(self, view: View):
self._decor_view = view
def getWindowManager(self) -> Optional[WindowManager]:
return self._window_manager
def setWindowManager(self, wm: WindowManager, app_token: Any = None, app_name: str = ""):
self._window_manager = wm
def setCallback(self, callback: Callback):
self._callback = callback
def getCallback(self) -> Optional[Callback]:
return self._callback
def superDispatchTouchEvent(self, event: MotionEvent) -> bool:
if self._decor_view:
return self._decor_view.dispatchTouchEvent(event)
return False
def superDispatchKeyEvent(self, event: KeyEvent) -> bool:
if self._decor_view:
return self._decor_view.dispatchKeyEvent(event)
return False
def superDispatchTrackballEvent(self, event: MotionEvent) -> bool:
return False
def superDispatchGenericMotionEvent(self, event: MotionEvent) -> bool:
return False
def takeSurface(self, callback: Any):
pass
def takeInputQueue(self, callback: Any):
pass
def isActive(self) -> bool:
return True
def isFloating(self) -> bool:
return False
def setBackgroundDrawable(self, drawable: Any):
pass
def setBackgroundDrawableResource(self, res_id: int):
pass
def setDimAmount(self, amount: float):
pass
def getLayoutInflater(self):
return None
def setWindowAnimations(self, res_id: int):
pass
def getWindowStyle(self) -> Any:
return None
def setContainer(self, container: "Window"):
self._container = container
def getContainer(self) -> Optional["Window"]:
return self._container
def setLocalFeatures(self, local_features: int):
pass
def makeActive(self):
pass
def getContext(self):
return self._context
def getAttributes(self) -> WindowManager.LayoutParams:
params = WindowManager.LayoutParams()
params.softInputMode = self._soft_input_mode
return params
def setAttributes(self, attrs: WindowManager.LayoutParams):
pass
def reconfigure(self, attrs: WindowManager.LayoutParams):
pass
def onConfigurationChanged(self, new_config: Any):
pass
def getCurrentFocus(self) -> Optional[View]:
return None
def getVolumeControlStream(self) -> int:
return -1
def setVolumeControlStream(self, stream_type: int):
pass
def getMediaController(self) -> Any:
return None
def setMediaController(self, controller: Any):
pass
def openGlEsVersion(self) -> int:
return 2
def isShortcutKey(self, key_code: int, event: KeyEvent) -> bool:
return False
def setStatusBarColor(self, color: int):
pass
def setNavigationBarColor(self, color: int):
pass
def setStatusBarVisibility(self, visible: bool):
pass
def setNavigationBarVisibility(self, visible: bool):
pass
def getStatusBarColor(self) -> int:
return 0
def getNavigationBarColor(self) -> int:
return 0
# ═══════════════════════════════════════════════════════════════
# WindowInsets
# ═══════════════════════════════════════════════════════════════
class WindowInsets(Stub):
"""WindowInsets — 窗口插入区域"""
def __init__(self, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0):
super().__init__()
self._system_window_insets = Rect(left, top, right, bottom)
self._stable_insets = Rect(0, 0, 0, 0)
self._display_cutout_insets = Rect(0, 0, 0, 0)
self._consumed = False
def getSystemWindowInsetLeft(self) -> int:
return self._system_window_insets.left
def getSystemWindowInsetTop(self) -> int:
return self._system_window_insets.top
def getSystemWindowInsetRight(self) -> int:
return self._system_window_insets.right
def getSystemWindowInsetBottom(self) -> int:
return self._system_window_insets.bottom
def getSystemWindowInsets(self) -> Rect:
return self._system_window_insets
def getStableInsetTop(self) -> int:
return self._stable_insets.top
def getStableInsetLeft(self) -> int:
return self._stable_insets.left
def getStableInsetRight(self) -> int:
return self._stable_insets.right
def getStableInsetBottom(self) -> int:
return self._stable_insets.bottom
def getDisplayCutoutInsets(self) -> Rect:
return self._display_cutout_insets
def consumeDisplayCutout(self) -> "WindowInsets":
return WindowInsets()
def consumeSystemWindowInsets(self) -> "WindowInsets":
return WindowInsets()
def replaceSystemWindowInsets(self, left: int, top: int, right: int, bottom: int) -> "WindowInsets":
new_ins = WindowInsets(left, top, right, bottom)
new_ins._stable_insets = self._stable_insets
return new_ins
def isConsumed(self) -> bool:
return self._consumed
def hasSystemWindowInsets(self) -> bool:
return (self._system_window_insets.left > 0 or self._system_window_insets.top > 0 or
self._system_window_insets.right > 0 or self._system_window_insets.bottom > 0)
def hasInsets(self) -> bool:
return self.hasSystemWindowInsets()
def isRound(self) -> bool:
return False
def getDisplayCutout(self) -> Any:
return None
def consumeStableInsets(self) -> "WindowInsets":
return WindowInsets()
def toString(self) -> str:
return f"WindowInsets(system={self._system_window_insets})"
# ═══════════════════════════════════════════════════════════════
# WindowInsetsController
# ═══════════════════════════════════════════════════════════════
class WindowInsetsController(Stub):
"""WindowInsetsController — 窗口插入控制器"""
BEHAVIOR_SHOW_BARS_BY_TOUCH = 0
BEHAVIOR_SHOW_BARS_BY_SWIPE = 1
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2
APPEARANCE_OPAQUE_STATUS_BARS = 0x00000001
APPEARANCE_OPAQUE_NAVIGATION_BARS = 0x00000002
APPEARANCE_LOW_PROFILE_BARS = 0x00000004
APPEARANCE_LIGHT_STATUS_BARS = 0x00000008
APPEARANCE_LIGHT_NAVIGATION_BARS = 0x00000010
def __init__(self):
super().__init__()
self._appearance = 0
self._behavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH
def show(self, types: int):
pass
def hide(self, types: int):
pass
def setSystemBarsAppearance(self, appearance: int, mask: int):
self._appearance = (self._appearance & ~mask) | (appearance & mask)
def getSystemBarsAppearance(self) -> int:
return self._appearance
def setSystemBarsBehavior(self, behavior: int):
self._behavior = behavior
def getSystemBarsBehavior(self) -> int:
return self._behavior
def setAnimationsDisabled(self, disabled: bool):
pass
# ═══════════════════════════════════════════════════════════════
# Display
# ═══════════════════════════════════════════════════════════════
class Display(Stub):
"""Display — 显示信息"""
DEFAULT_DISPLAY = 0
ROTATION_0 = 0
ROTATION_90 = 1
ROTATION_180 = 2
ROTATION_270 = 3
FLAG_PRESENTATION = 0x00000008
FLAG_PRIVATE = 0x00000004
FLAG_SECURE = 0x00000002
FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001
STATE_DOZE = 3
STATE_DOZE_SUSPEND = 4
STATE_OFF = 1
STATE_ON = 2
STATE_UNKNOWN = 0
def __init__(self, display_id: int = DEFAULT_DISPLAY):
super().__init__()
self._display_id = display_id
self._width = 1080
self._height = 1920
self._rotation = Display.ROTATION_0
self._refresh_rate = 60.0
self._density = 2.0
self._density_dpi = 320
self._state = Display.STATE_ON
self._flags = 0
self._name = "Built-in Screen"
def getDisplayId(self) -> int:
return self._display_id
def getWidth(self) -> int:
return self._width
def getHeight(self) -> int:
return self._height
def getRotation(self) -> int:
return self._rotation
def getRefreshRate(self) -> float:
return self._refresh_rate
def getName(self) -> str:
return self._name
def getState(self) -> int:
return self._state
def getFlags(self) -> int:
return self._flags
def isHdr(self) -> bool:
return False
def isWideColorGamut(self) -> bool:
return False
def getSize(self, out_size: Any = None):
if out_size is not None:
out_size.width = self._width
out_size.height = self._height
return None
def getRealSize(self, out_size: Any = None):
if out_size is not None:
out_size.width = self._width
out_size.height = self._height
return None
def getMetrics(self, metrics: Any = None):
if metrics is not None:
metrics.widthPixels = self._width
metrics.heightPixels = self._height
metrics.density = self._density
metrics.densityDpi = self._density_dpi
metrics.scaledDensity = self._density
metrics.xdpi = 320.0
metrics.ydpi = 320.0
return None
def getRealMetrics(self, metrics: Any = None):
return self.getMetrics(metrics)
def getOrientation(self) -> int:
return self._rotation
def getDisplayAdjustments(self) -> Any:
return None
def getPixelFormat(self) -> int:
return 1 # RGBA_8888
def isValid(self) -> bool:
return True
def toString(self) -> str:
return f"Display({self._display_id}, {self._width}x{self._height})"
# ═══════════════════════════════════════════════════════════════
# Surface
# ═══════════════════════════════════════════════════════════════
class Surface(Stub):
"""Surface — 表面,用于绘制"""
ROTATION_0 = 0
ROTATION_90 = 1
ROTATION_180 = 2
ROTATION_270 = 3
CHANGE_FRAME_RATE_ALWAYS = 1
CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0
def __init__(self, surface_control: Any = None):
super().__init__()
self._is_valid = True
self._is_locked = False
self._width = 1080
self._height = 1920
self._hardware_accelerated = False
def isValid(self) -> bool:
return self._is_valid
def isConsumerRunningBehind(self) -> bool:
return False
def lockCanvas(self, dirty_rect: Any = None) -> Any:
if not self._is_valid:
return None
self._is_locked = True
return None # 返回空 Canvas
def lockHardwareCanvas(self) -> Any:
if not self._is_valid:
return None
self._is_locked = True
self._hardware_accelerated = True
return None
def unlockCanvasAndPost(self, canvas: Any):
self._is_locked = False
def getSurfaceControl(self) -> Any:
return None
def release(self):
self._is_valid = False
self._is_locked = False
def destroy(self):
self.release()
def getWidth(self) -> int:
return self._width
def getHeight(self) -> int:
return self._height
def setFrameRate(self, frame_rate: float, compatibility: int):
pass
def toString(self) -> str:
return f"Surface(valid={self._is_valid}, {self._width}x{self._height})"
# ═══════════════════════════════════════════════════════════════
# Choreographer
# ═══════════════════════════════════════════════════════════════
class Choreographer(Stub):
"""Choreographer — 帧渲染协调器"""
CALLBACK_INPUT = 0
CALLBACK_ANIMATION = 1
CALLBACK_INSETS_ANIMATION = 2
CALLBACK_TRAVERSAL = 3
CALLBACK_COMMIT = 4
_instance: Optional["Choreographer"] = None
class FrameCallback:
def doFrame(self, frame_time_nanos: int):
pass
class FrameTimeline:
pass
def __init__(self):
super().__init__()
@staticmethod
def getInstance() -> "Choreographer":
if Choreographer._instance is None:
Choreographer._instance = Choreographer()
return Choreographer._instance
def postFrameCallback(self, callback: "FrameCallback"):
callback.doFrame(int(time.time() * 1_000_000_000))
def postFrameCallbackDelayed(self, callback: "FrameCallback", delay_millis: int):
callback.doFrame(int((time.time() + delay_millis / 1000.0) * 1_000_000_000))
def removeFrameCallback(self, callback: "FrameCallback"):
pass
def postCallback(self, callback_type: int, action: Callable, token: Any):
action()
def postCallbackDelayed(self, callback_type: int, action: Callable, token: Any, delay_millis: int):
import threading
timer = threading.Timer(delay_millis / 1000.0, action)
timer.daemon = True
timer.start()
def removeCallbacks(self, callback_type: int, action: Callable, token: Any):
pass
def getFrameTimeNanos(self) -> int:
return int(time.time() * 1_000_000_000)
def getLastFrameTimeNanos(self) -> int:
return int(time.time() * 1_000_000_000) - 16_666_666
# ═══════════════════════════════════════════════════════════════
# ActionMode
# ═══════════════════════════════════════════════════════════════
class ActionMode(Stub):
"""ActionMode — 操作模式"""
TYPE_FLOATING = 1
TYPE_PRIMARY = 0
TYPE_TOOLBAR = 2
class Callback:
def onCreateActionMode(self, mode: "ActionMode", menu: Any) -> bool:
return False
def onPrepareActionMode(self, mode: "ActionMode", menu: Any) -> bool:
return False
def onActionItemClicked(self, mode: "ActionMode", item: Any) -> bool:
return False
def onDestroyActionMode(self, mode: "ActionMode"):
pass
class Callback2(Callback):
def onGetContentRect(self, mode: "ActionMode", view: View, out_rect: Any):
pass
def __init__(self):
super().__init__()
self._tag: Any = None
self._title: str = ""
self._subtitle: str = ""
self._title_optional_hint: str = ""
self._subtitle_optional_hint: str = ""
self._type = ActionMode.TYPE_PRIMARY
self._menu: Any = None
def setTitle(self, title: str):
self._title = title
def getTitle(self) -> str:
return self._title
def setSubtitle(self, subtitle: str):
self._subtitle = subtitle
def getSubtitle(self) -> str:
return self._subtitle
def setTitleOptionalHint(self, hint: bool):
self._title_optional_hint = hint
def getTitleOptionalHint(self) -> bool:
return bool(self._title_optional_hint)
def setTag(self, tag: Any):
self._tag = tag
def getTag(self) -> Any:
return self._tag
def getMenu(self):
return self._menu
def setType(self, type_: int):
self._type = type_
def getType(self) -> int:
return self._type
def invalidate(self):
pass
def invalidateContentRect(self):
pass
def finish(self):
pass
def getCustomView(self) -> Optional[View]:
return None
def setCustomView(self, view: View):
pass
def setImageDrawable(self, drawable: Any):
pass
def getMenuInflater(self):
return None
# ═══════════════════════════════════════════════════════════════
# ContextThemeWrapper
# ═══════════════════════════════════════════════════════════════
class ContextThemeWrapper(Stub):
"""ContextThemeWrapper — 上下文主题包装器"""
def __init__(self, base: Any = None, theme_res_id: int = 0):
super().__init__()
self._base = base if base is not None else android_context
self._theme_res_id = theme_res_id
self._theme: Any = None
def attachBaseContext(self, new_base: Any):
self._base = new_base
def getBaseContext(self):
return self._base
def setTheme(self, resid: int):
self._theme_res_id = resid
def getThemeResId(self) -> int:
return self._theme_res_id
def getTheme(self) -> Any:
return self._theme
def getResources(self):
if hasattr(self._base, "getResources"):
return self._base.getResources()
return None
def getSystemService(self, name: str) -> Any:
if hasattr(self._base, "getSystemService"):
return self._base.getSystemService(name)
return None
def getPackageName(self) -> str:
if hasattr(self._base, "getPackageName"):
return self._base.getPackageName()
return ""
def getApplicationContext(self):
return self._base
# ═══════════════════════════════════════════════════════════════
# ViewOutlineProvider
# ═══════════════════════════════════════════════════════════════
class ViewOutlineProvider(Stub):
"""ViewOutlineProvider — 视图轮廓提供者"""
BACKGROUND = None
BOUNDS = None
PADDED_BOUNDS = None
def getOutline(self, view: View, outline: Any):
pass
# 预定义实例
@staticmethod
def _init_constants():
if ViewOutlineProvider.BACKGROUND is None:
class _Background(ViewOutlineProvider):
def getOutline(self, view, outline):
if hasattr(outline, "setRect"):
outline.setRect(0, 0, view.getWidth(), view.getHeight())
ViewOutlineProvider.BACKGROUND = _Background()
if ViewOutlineProvider.BOUNDS is None:
class _Bounds(ViewOutlineProvider):
def getOutline(self, view, outline):
if hasattr(outline, "setRect"):
outline.setRect(0, 0, view.getWidth(), view.getHeight())
ViewOutlineProvider.BOUNDS = _Bounds()
if ViewOutlineProvider.PADDED_BOUNDS is None:
class _PaddedBounds(ViewOutlineProvider):
def getOutline(self, view, outline):
if hasattr(outline, "setRect"):
outline.setRect(
view.getPaddingLeft(), view.getPaddingTop(),
view.getWidth() - view.getPaddingRight(),
view.getHeight() - view.getPaddingBottom(),
)
ViewOutlineProvider.PADDED_BOUNDS = _PaddedBounds()
ViewOutlineProvider._init_constants()
# ═══════════════════════════════════════════════════════════════
# RenderNode
# ═══════════════════════════════════════════════════════════════
class RenderNode(Stub):
"""RenderNode — 渲染节点"""
STATUS_DISPLAY_LIST_INFLATED = 1
STATUS_DISPLAY_LIST_READY = 2
STATUS_DISPLAY_LIST_PREPARE = 3
STATUS_DISPLAY_LIST_UNUSED = 0
def __init__(self, name: str = ""):
super().__init__()
self._name = name
self._alpha = 1.0
self._translation_x = 0.0
self._translation_y = 0.0
self._translation_z = 0.0
self._elevation = 0.0
self._rotation = 0.0
self._rotation_x = 0.0
self._rotation_y = 0.0
self._scale_x = 1.0
self._scale_y = 1.0
self._pivot_x = 0.0
self._pivot_y = 0.0
self._left = 0
self._top = 0
self._right = 0
self._bottom = 0
self._clip_to_bounds = False
self._clip_bounds: Optional[Rect] = None
self._has_display_list = False
self._status = RenderNode.STATUS_DISPLAY_LIST_UNUSED
def setPosition(self, left: int, top: int, right: int, bottom: int) -> bool:
old_left, old_top, old_right, old_bottom = self._left, self._top, self._right, self._bottom
self._left, self._top, self._right, self._bottom = left, top, right, bottom
return (old_left != left or old_top != top or old_right != right or old_bottom != bottom)
def getLeft(self) -> int:
return self._left
def getTop(self) -> int:
return self._top
def getRight(self) -> int:
return self._right
def getBottom(self) -> int:
return self._bottom
def setAlpha(self, alpha: float) -> bool:
changed = self._alpha != alpha
self._alpha = alpha
return changed
def getAlpha(self) -> float:
return self._alpha
def setTranslationX(self, tx: float) -> bool:
changed = self._translation_x != tx
self._translation_x = tx
return changed
def getTranslationX(self) -> float:
return self._translation_x
def setTranslationY(self, ty: float) -> bool:
changed = self._translation_y != ty
self._translation_y = ty
return changed
def getTranslationY(self) -> float:
return self._translation_y
def setElevation(self, elevation: float) -> bool:
changed = self._elevation != elevation
self._elevation = elevation
return changed
def getElevation(self) -> float:
return self._elevation
def setRotation(self, rotation: float) -> bool:
changed = self._rotation != rotation
self._rotation = rotation
return changed
def getRotation(self) -> float:
return self._rotation
def setScaleX(self, scale_x: float) -> bool:
changed = self._scale_x != scale_x
self._scale_x = scale_x
return changed
def getScaleX(self) -> float:
return self._scale_x
def setScaleY(self, scale_y: float) -> bool:
changed = self._scale_y != scale_y
self._scale_y = scale_y
return changed
def getScaleY(self) -> float:
return self._scale_y
def setPivotX(self, pivot_x: float) -> bool:
changed = self._pivot_x != pivot_x
self._pivot_x = pivot_x
return changed
def getPivotX(self) -> float:
return self._pivot_x
def setPivotY(self, pivot_y: float) -> bool:
changed = self._pivot_y != pivot_y
self._pivot_y = pivot_y
return changed
def getPivotY(self) -> float:
return self._pivot_y
def setClipToBounds(self, clip_to_bounds: bool) -> bool:
changed = self._clip_to_bounds != clip_to_bounds
self._clip_to_bounds = clip_to_bounds
return changed
def getClipToBounds(self) -> bool:
return self._clip_to_bounds
def setClipBounds(self, clip_rect: Optional[Rect]):
self._clip_bounds = clip_rect
def getClipBounds(self) -> Optional[Rect]:
return self._clip_bounds
def setHasDisplayList(self, has_display_list: bool):
self._has_display_list = has_display_list
def hasDisplayList(self) -> bool:
return self._has_display_list
def getName(self) -> str:
return self._name
def discardDisplayList(self):
self._has_display_list = False
self._status = RenderNode.STATUS_DISPLAY_LIST_UNUSED
def start(self) -> Any:
return None
def end(self):
pass
def offsetLeftAndRight(self, offset: int):
self._left += offset
self._right += offset
def offsetTopAndBottom(self, offset: int):
self._top += offset
self._bottom += offset
def getMatrix(self, out_matrix: Any):
pass
def getInverseMatrix(self, out_matrix: Any):
pass
def useLighting(self) -> bool:
return False
def setUseLighting(self, use_lighting: bool):
pass
def setLayerType(self, layer_type: int):
pass
def getLayerType(self) -> int:
return 0
# ═══════════════════════════════════════════════════════════════
# ScrollCaptureCallback
# ═══════════════════════════════════════════════════════════════
class ScrollCaptureCallback(Stub):
"""ScrollCaptureCallback — 滚动捕获回调"""
def onScrollCaptureSearch(self, l: int, t: int, r: int, b: int) -> Optional[Any]:
return None
def onScrollCaptureStart(self, session: Any) -> Optional[Any]:
return None
def onScrollCaptureImageRequest(self, session: Any, request: Any) -> int:
return 0
def onScrollCaptureEnd(self, session: Any):
pass
# ═══════════════════════════════════════════════════════════════
# KeyboardShortcutGroup
# ═══════════════════════════════════════════════════════════════
class KeyboardShortcutGroup(Stub):
"""KeyboardShortcutGroup — 键盘快捷键分组"""
def __init__(self, label: str, items: Optional[List[Any]] = None):
super().__init__()
self._label = label
self._items: List[Any] = items if items is not None else []
self._system_group = False
def getLabel(self) -> str:
return self._label
def getItems(self) -> List[Any]:
return list(self._items)
def addItem(self, item: Any):
self._items.append(item)
def setSystemGroup(self, is_system: bool):
self._system_group = is_system
def isSystemGroup(self) -> bool:
return self._system_group
# ═══════════════════════════════════════════════════════════════
# SoundEffectConstants
# ═══════════════════════════════════════════════════════════════
class SoundEffectConstants:
"""SoundEffectConstants — 音效常量"""
CLICK = 0
NAVIGATION_LEFT = 1
NAVIGATION_UP = 2
NAVIGATION_RIGHT = 3
NAVIGATION_DOWN = 4
NAVIGATION_REPEAT_LEFT = 5
NAVIGATION_REPEAT_UP = 6
NAVIGATION_REPEAT_RIGHT = 7
NAVIGATION_REPEAT_DOWN = 8
@staticmethod
def getDirectionForNavigation(gravity: int) -> int:
return SoundEffectConstants.NAVIGATION_UP
# ═══════════════════════════════════════════════════════════════
# FocusFinder
# ═══════════════════════════════════════════════════════════════
class FocusFinder(Stub):
"""FocusFinder — 焦点查找器"""
_instance: Optional["FocusFinder"] = None
def __init__(self):
super().__init__()
@staticmethod
def getInstance() -> "FocusFinder":
if FocusFinder._instance is None:
FocusFinder._instance = FocusFinder()
return FocusFinder._instance
def findNextFocus(self, root: ViewGroup, focused: View, direction: int) -> Optional[View]:
return None
def findNearestTouchable(self, root: ViewGroup, x: int, y: int, direction: int,
deltas: List[int]) -> Optional[View]:
return None
# ═══════════════════════════════════════════════════════════════
# ViewGroup override for children list
# ═══════════════════════════════════════════════════════════════
# Ensure ViewGroup._children is separate from View._children
ViewGroup._children = [] # Will be overridden in __init__
# ═══════════════════════════════════════════════════════════════
# __all__
# ═══════════════════════════════════════════════════════════════
__all__ = [
"View",
"ViewGroup",
"ViewParent",
"ViewManager",
"WindowManager",
"MotionEvent",
"KeyEvent",
"GestureDetector",
"ScaleGestureDetector",
"VelocityTracker",
"DragEvent",
"AccessibilityDelegate",
"ViewTreeObserver",
"ViewConfiguration",
"SurfaceView",
"TextureView",
"Window",
"WindowInsets",
"WindowInsetsController",
"Display",
"Surface",
"Choreographer",
"ActionMode",
"ContextThemeWrapper",
"Gravity",
"ViewOutlineProvider",
"RenderNode",
"ScrollCaptureCallback",
"KeyboardShortcutGroup",
"MeasureSpec",
"ViewPropertyAnimator",
"SurfaceHolder",
"SurfaceTexture",
"FocusFinder",
"SoundEffectConstants",
"Rect",
]