Files
Android-pyApi/android_pyapi/android/util.py
T
shuiyu1123 bfe27fdc08 feat: Android-pyApi v1.0 - 全面翻译 Android SDK API 为 Python
52 个模块覆盖 Android + Java + org.json 标准库
2026-06-24 11:16:16 +00:00

1055 lines
31 KiB
Python

"""
Android Util 组件 — Log, SparseArray, LruCache, DisplayMetrics 等
方法签名完全对齐 Android SDK
"""
import math
import re as _re
import sys
from datetime import datetime
from typing import Any, Callable, Dict, Generic, List, Optional, Set, Tuple, TypeVar, Union
from .._core import (
Stub, AndroidOnlyError, android_context,
resolve_android_path, to_android_path,
_sdcard_root, _app_data_dir,
)
# ═══════════════════════════════════════════════════════════════
# Log
# ═══════════════════════════════════════════════════════════════
class Log(Stub):
"""Log — 日志输出"""
ASSERT = 7
DEBUG = 3
ERROR = 6
INFO = 4
VERBOSE = 2
WARN = 5
_min_log_level = VERBOSE
@staticmethod
def v(tag: str, msg: str) -> int:
if Log._min_log_level <= Log.VERBOSE:
sys.stderr.write(f"V/{tag}: {msg}\n")
return 0
@staticmethod
def d(tag: str, msg: str) -> int:
if Log._min_log_level <= Log.DEBUG:
sys.stderr.write(f"D/{tag}: {msg}\n")
return 0
@staticmethod
def i(tag: str, msg: str) -> int:
if Log._min_log_level <= Log.INFO:
sys.stderr.write(f"I/{tag}: {msg}\n")
return 0
@staticmethod
def w(tag: str, msg: str) -> int:
if Log._min_log_level <= Log.WARN:
sys.stderr.write(f"W/{tag}: {msg}\n")
return 0
@staticmethod
def e(tag: str, msg: str) -> int:
if Log._min_log_level <= Log.ERROR:
sys.stderr.write(f"E/{tag}: {msg}\n")
return 0
@staticmethod
def wtf(tag: str, msg: str) -> int:
sys.stderr.write(f"WTF/{tag}: {msg}\n")
return 0
@staticmethod
def println(log_level: int, tag: str, msg: str) -> int:
level_map = {
Log.VERBOSE: "V",
Log.DEBUG: "D",
Log.INFO: "I",
Log.WARN: "W",
Log.ERROR: "E",
Log.ASSERT: "A",
}
prefix = level_map.get(log_level, "?")
sys.stderr.write(f"{prefix}/{tag}: {msg}\n")
return 0
@staticmethod
def isLoggable(tag: str, level: int) -> bool:
return level >= Log._min_log_level
@staticmethod
def getStackTraceString(tr: Exception) -> str:
import traceback
return "".join(traceback.format_exception(type(tr), tr, tr.__traceback__))
@staticmethod
def setMinLogLevel(level: int):
Log._min_log_level = level
@staticmethod
def wtf(tag: str, tr: Exception) -> int:
sys.stderr.write(f"WTF/{tag}: {Log.getStackTraceString(tr)}\n")
return 0
# ═══════════════════════════════════════════════════════════════
# SparseArray
# ═══════════════════════════════════════════════════════════════
T = TypeVar("T")
class SparseArray(Generic[T], Stub):
"""SparseArray — 稀疏数组(int 键映射)"""
def __init__(self, initial_capacity: int = 10):
super().__init__()
self._keys: List[int] = []
self._values: List[Optional[T]] = []
self._size = 0
def put(self, key: int, value: T):
"""如果 key 已存在则替换"""
try:
idx = self._keys.index(key)
self._values[idx] = value
except ValueError:
self._keys.append(key)
self._values.append(value)
self._size += 1
def get(self, key: int, default: Optional[T] = None) -> Optional[T]:
try:
idx = self._keys.index(key)
return self._values[idx]
except ValueError:
return default
def delete(self, key: int):
try:
idx = self._keys.index(key)
self._keys.pop(idx)
self._values.pop(idx)
self._size -= 1
except ValueError:
pass
def remove(self, key: int):
self.delete(key)
def removeAt(self, index: int):
if 0 <= index < self._size:
self._keys.pop(index)
self._values.pop(index)
self._size -= 1
def size(self) -> int:
return self._size
def keyAt(self, index: int) -> int:
if 0 <= index < self._size:
return self._keys[index]
return 0
def valueAt(self, index: int) -> Optional[T]:
if 0 <= index < self._size:
return self._values[index]
return None
def setValueAt(self, index: int, value: T):
if 0 <= index < self._size:
self._values[index] = value
def indexOfKey(self, key: int) -> int:
try:
return self._keys.index(key)
except ValueError:
return -1
def indexOfValue(self, value: T) -> int:
try:
return self._values.index(value)
except ValueError:
return -1
def clear(self):
self._keys.clear()
self._values.clear()
self._size = 0
def append(self, key: int, value: T):
self.put(key, value)
def containsKey(self, key: int) -> bool:
return key in self._keys
def putAll(self, other: "SparseArray[T]"):
for i in range(other.size()):
self.put(other.keyAt(i), other.valueAt(i))
def clone(self) -> "SparseArray[T]":
sa = SparseArray[T]()
sa._keys = list(self._keys)
sa._values = list(self._values)
sa._size = self._size
return sa
def toString(self) -> str:
pairs = ", ".join(
f"{k}={v}" for k, v in zip(self._keys, self._values)
)
return f"SparseArray{{{pairs}}}"
def __getitem__(self, key: int) -> Optional[T]:
return self.get(key)
def __setitem__(self, key: int, value: T):
self.put(key, value)
def __delitem__(self, key: int):
self.delete(key)
def __len__(self) -> int:
return self._size
def __contains__(self, key: int) -> bool:
return key in self._keys
class SparseIntArray(Stub):
"""SparseIntArray — int 到 int 的映射"""
def __init__(self, initial_capacity: int = 10):
super().__init__()
self._keys: List[int] = []
self._values: List[int] = []
def put(self, key: int, value: int):
try:
idx = self._keys.index(key)
self._values[idx] = value
except ValueError:
self._keys.append(key)
self._values.append(value)
def get(self, key: int, default: int = 0) -> int:
try:
idx = self._keys.index(key)
return self._values[idx]
except ValueError:
return default
def delete(self, key: int):
try:
idx = self._keys.index(key)
self._keys.pop(idx)
self._values.pop(idx)
except ValueError:
pass
def removeAt(self, index: int):
if 0 <= index < len(self._keys):
self._keys.pop(index)
self._values.pop(index)
def size(self) -> int:
return len(self._keys)
def keyAt(self, index: int) -> int:
if 0 <= index < len(self._keys):
return self._keys[index]
return 0
def valueAt(self, index: int) -> int:
if 0 <= index < len(self._values):
return self._values[index]
return 0
def indexOfKey(self, key: int) -> int:
try:
return self._keys.index(key)
except ValueError:
return -1
def indexOfValue(self, value: int) -> int:
try:
return self._values.index(value)
except ValueError:
return -1
def clear(self):
self._keys.clear()
self._values.clear()
def append(self, key: int, value: int):
self.put(key, value)
def toString(self) -> str:
pairs = ", ".join(f"{k}={v}" for k, v in zip(self._keys, self._values))
return f"SparseIntArray{{{pairs}}}"
class SparseBooleanArray(Stub):
"""SparseBooleanArray — int 到 bool 的映射"""
def __init__(self, initial_capacity: int = 10):
super().__init__()
self._keys: List[int] = []
self._values: List[bool] = []
def put(self, key: int, value: bool):
try:
idx = self._keys.index(key)
self._values[idx] = value
except ValueError:
self._keys.append(key)
self._values.append(value)
def get(self, key: int, default: bool = False) -> bool:
try:
idx = self._keys.index(key)
return self._values[idx]
except ValueError:
return default
def delete(self, key: int):
try:
idx = self._keys.index(key)
self._keys.pop(idx)
self._values.pop(idx)
except ValueError:
pass
def size(self) -> int:
return len(self._keys)
def keyAt(self, index: int) -> int:
if 0 <= index < len(self._keys):
return self._keys[index]
return 0
def valueAt(self, index: int) -> bool:
if 0 <= index < len(self._values):
return self._values[index]
return False
def indexOfKey(self, key: int) -> int:
try:
return self._keys.index(key)
except ValueError:
return -1
def indexOfValue(self, value: bool) -> int:
try:
return self._values.index(value)
except ValueError:
return -1
def clear(self):
self._keys.clear()
self._values.clear()
def append(self, key: int, value: bool):
self.put(key, value)
def toString(self) -> str:
pairs = ", ".join(f"{k}={v}" for k, v in zip(self._keys, self._values))
return f"SparseBooleanArray{{{pairs}}}"
# ═══════════════════════════════════════════════════════════════
# LruCache
# ═══════════════════════════════════════════════════════════════
class LruCache(Stub):
"""LruCache — LRU 缓存"""
def __init__(self, max_size: int):
super().__init__()
self._max_size = max_size
self._size = 0
self._map: Dict[Any, Any] = {}
def get(self, key: Any) -> Optional[Any]:
return self._map.get(key)
def put(self, key: Any, value: Any) -> Optional[Any]:
old = self._map.get(key)
self._map[key] = value
self._size += self._safe_size_of(key, value)
if old is not None:
self._size -= self._safe_size_of(key, old)
self._trim_to_size(self._max_size)
return old
def remove(self, key: Any) -> Optional[Any]:
value = self._map.pop(key, None)
if value is not None:
self._size -= self._safe_size_of(key, value)
return value
def size(self) -> int:
return self._size
def maxSize(self) -> int:
return self._max_size
def trimToSize(self, max_size: int):
self._trim_to_size(max_size)
def _trim_to_size(self, max_size: int):
while self._size > max_size and self._map:
# Remove oldest (first key)
oldest_key = next(iter(self._map))
self.remove(oldest_key)
def snapshot(self) -> Dict[Any, Any]:
return dict(self._map)
def evictAll(self):
self._map.clear()
self._size = 0
def _safe_size_of(self, key: Any, value: Any) -> int:
try:
return self.sizeOf(key, value)
except Exception:
return 1
def sizeOf(self, key: Any, value: Any) -> int:
return 1
def entryRemoved(self, evicted: bool, key: Any, old_value: Any, new_value: Optional[Any]):
pass
def create(self, key: Any) -> Optional[Any]:
return None
def getCount(self) -> int:
return len(self._map)
def putCount(self) -> int:
return len(self._map)
def evictionCount(self) -> int:
return 0
def hitCount(self) -> int:
return 0
def missCount(self) -> int:
return 0
def toString(self) -> str:
return f"LruCache(maxSize={self._max_size}, size={self._size})"
# ═══════════════════════════════════════════════════════════════
# DisplayMetrics
# ═══════════════════════════════════════════════════════════════
class DisplayMetrics(Stub):
"""DisplayMetrics — 屏幕显示度量"""
DENSITY_LOW = 120
DENSITY_MEDIUM = 160
DENSITY_TV = 213
DENSITY_HIGH = 240
DENSITY_XHIGH = 320
DENSITY_XXHIGH = 480
DENSITY_XXXHIGH = 640
DENSITY_DEFAULT = DENSITY_MEDIUM
DENSITY_DEVICE_STABLE = DENSITY_XXXHIGH
def __init__(self):
super().__init__()
self.widthPixels = 1080
self.heightPixels = 1920
self.density = 2.75
self.densityDpi = 440
self.scaledDensity = 2.75
self.xdpi = 440.0
self.ydpi = 440.0
self.noncompatWidthPixels = 1080
self.noncompatHeightPixels = 1920
self.noncompatDensity = 2.75
self.noncompatDensityDpi = 440
self.noncompatScaledDensity = 2.75
self.noncompatXdpi = 440.0
self.noncompatYdpi = 440.0
def setTo(self, other: "DisplayMetrics"):
self.widthPixels = other.widthPixels
self.heightPixels = other.heightPixels
self.density = other.density
self.densityDpi = other.densityDpi
self.scaledDensity = other.scaledDensity
self.xdpi = other.xdpi
self.ydpi = other.ydpi
def setToDefaults(self):
self.__init__()
def toString(self) -> str:
return (f"DisplayMetrics({self.widthPixels}x{self.heightPixels}, "
f"density={self.density}, dpi={self.densityDpi})")
# ═══════════════════════════════════════════════════════════════
# TypedValue
# ═══════════════════════════════════════════════════════════════
class TypedValue(Stub):
"""TypedValue — 类型化值的容器"""
COMPLEX_UNIT_PX = 0
COMPLEX_UNIT_DIP = 1
COMPLEX_UNIT_SP = 2
COMPLEX_UNIT_PT = 3
COMPLEX_UNIT_IN = 4
COMPLEX_UNIT_MM = 5
COMPLEX_UNIT_FRACTION = 6
COMPLEX_UNIT_FRACTION_PARENT = 7
TYPE_NULL = 0x00
TYPE_REFERENCE = 0x01
TYPE_ATTRIBUTE = 0x02
TYPE_STRING = 0x03
TYPE_FLOAT = 0x04
TYPE_DIMENSION = 0x05
TYPE_FRACTION = 0x06
TYPE_FIRST_INT = 0x10
TYPE_INT_DEC = 0x10
TYPE_INT_HEX = 0x11
TYPE_INT_BOOLEAN = 0x12
TYPE_INT_COLOR_ARGB8 = 0x1C
TYPE_INT_COLOR_RGB8 = 0x1D
TYPE_INT_COLOR_ARGB4 = 0x1E
TYPE_INT_COLOR_RGB4 = 0x1F
TYPE_LAST_COLOR_INT = 0x1F
TYPE_LAST_INT = 0x1F
def __init__(self):
super().__init__()
self.type = self.TYPE_NULL
self.data = 0
self.assetCookie = 0
self.resourceId = 0
self.changingConfigurations = 0
self.string = None
self.density = 0
@staticmethod
def applyDimension(unit: int, value: float, metrics: DisplayMetrics) -> float:
if unit == TypedValue.COMPLEX_UNIT_PX:
return value
if unit == TypedValue.COMPLEX_UNIT_DIP:
return value * metrics.density
if unit == TypedValue.COMPLEX_UNIT_SP:
return value * metrics.scaledDensity
if unit == TypedValue.COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0 / 72)
if unit == TypedValue.COMPLEX_UNIT_IN:
return value * metrics.xdpi
if unit == TypedValue.COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0 / 25.4)
return value
@staticmethod
def complexToDimension(data: int, metrics: DisplayMetrics) -> float:
unit = data & 0xF
value = (data >> 4) & 0xFFFFFF
# Sign-extend
if value & 0x800000:
value = value - 0x1000000
return TypedValue.applyDimension(unit, float(value), metrics)
@staticmethod
def complexToFloat(data: int) -> float:
value = (data & 0xFFFFFF00) >> 8
exp = (data & 0xFF) - 150
return float(value) * (10.0 ** exp)
@staticmethod
def complexToDimensionPixelOffset(data: int, metrics: DisplayMetrics) -> int:
return int(TypedValue.complexToDimension(data, metrics))
@staticmethod
def complexToDimensionPixelSize(data: int, metrics: DisplayMetrics) -> int:
val = TypedValue.complexToDimension(data, metrics)
if val >= 0:
return int(val + 0.5)
return int(val - 0.5)
def getFloat(self) -> float:
return float(self.data)
def toString(self) -> str:
return f"TypedValue(type={self.type}, data={self.data})"
# ═══════════════════════════════════════════════════════════════
# Pair
# ═══════════════════════════════════════════════════════════════
class Pair(Stub):
"""Pair — 有序对"""
def __init__(self, first: Any, second: Any):
super().__init__()
self.first = first
self.second = second
@staticmethod
def create(a: Any, b: Any) -> "Pair":
return Pair(a, b)
def hashCode(self) -> int:
return hash((self.first, self.second))
def equals(self, other: Any) -> bool:
if not isinstance(other, Pair):
return False
return self.first == other.first and self.second == other.second
def toString(self) -> str:
return f"Pair({self.first}, {self.second})"
def __eq__(self, other):
return self.equals(other)
def __hash__(self):
return self.hashCode()
def __repr__(self):
return self.toString()
def __iter__(self):
return iter((self.first, self.second))
# ═══════════════════════════════════════════════════════════════
# Size / SizeF
# ═══════════════════════════════════════════════════════════════
class Size(Stub):
"""Size — 整数尺寸"""
def __init__(self, width: int, height: int):
super().__init__()
self._width = width
self._height = height
def getWidth(self) -> int:
return self._width
def getHeight(self) -> int:
return self._height
def equals(self, other: Any) -> bool:
if not isinstance(other, Size):
return False
return self._width == other._width and self._height == other._height
def hashCode(self) -> int:
return (self._height << 16) ^ self._width
def toString(self) -> str:
return f"{self._width}x{self._height}"
@staticmethod
def parseSize(string: str) -> "Size":
parts = string.split("x")
if len(parts) == 2:
return Size(int(parts[0]), int(parts[1]))
raise ValueError(f"Invalid size: {string}")
def __eq__(self, other):
return self.equals(other)
def __hash__(self):
return self.hashCode()
def __repr__(self):
return self.toString()
class SizeF(Stub):
"""SizeF — 浮点数尺寸"""
def __init__(self, width: float, height: float):
super().__init__()
self._width = width
self._height = height
def getWidth(self) -> float:
return self._width
def getHeight(self) -> float:
return self._height
def equals(self, other: Any) -> bool:
if not isinstance(other, SizeF):
return False
return abs(self._width - other._width) < 0.001 and abs(self._height - other._height) < 0.001
def hashCode(self) -> int:
return hash((self._width, self._height))
def toString(self) -> str:
return f"{self._width:.1f}x{self._height:.1f}"
@staticmethod
def parseSizeF(string: str) -> "SizeF":
parts = string.split("x")
if len(parts) == 2:
return SizeF(float(parts[0]), float(parts[1]))
raise ValueError(f"Invalid size: {string}")
def __eq__(self, other):
return self.equals(other)
def __hash__(self):
return self.hashCode()
def __repr__(self):
return self.toString()
# ═══════════════════════════════════════════════════════════════
# StateSet
# ═══════════════════════════════════════════════════════════════
class StateSet(Stub):
"""StateSet — 状态集合"""
VIEW_STATE_WINDOW_FOCUSED = 1
VIEW_STATE_SELECTED = 1 << 1
VIEW_STATE_FOCUSED = 1 << 2
VIEW_STATE_ENABLED = 1 << 3
VIEW_STATE_PRESSED = 1 << 4
VIEW_STATE_ACTIVATED = 1 << 5
VIEW_STATE_ACCELERATED = 1 << 6
VIEW_STATE_HOVERED = 1 << 7
VIEW_STATE_DRAG_CAN_ACCEPT = 1 << 8
VIEW_STATE_DRAG_HOVERED = 1 << 9
WILD_CARD = 0x00000000
@staticmethod
def isWildCard(state_spec_or_mask: Any) -> bool:
if isinstance(state_spec_or_mask, list):
return len(state_spec_or_mask) == 0
return state_spec_or_mask == StateSet.WILD_CARD
@staticmethod
def trimStateSet(states: List[int], new_size: int) -> List[int]:
return states[:new_size]
@staticmethod
def dump(states: List[int]) -> str:
if not states:
return "[]"
return "[" + ", ".join(str(s) for s in states) + "]"
# ═══════════════════════════════════════════════════════════════
# MathUtils
# ═══════════════════════════════════════════════════════════════
class MathUtils(Stub):
"""MathUtils — 数学工具"""
DEG_TO_RAD = math.pi / 180.0
RAD_TO_DEG = 180.0 / math.pi
@staticmethod
def abs(v: float) -> float:
return abs(v)
@staticmethod
def constrain(amount: float, low: float, high: float) -> float:
return max(low, min(high, amount))
@staticmethod
def constrainInt(amount: int, low: int, high: int) -> int:
return max(low, min(high, amount))
@staticmethod
def lerp(start: float, stop: float, amount: float) -> float:
return start + (stop - start) * amount
@staticmethod
def lerpInv(a: float, b: float, value: float) -> float:
if a != b:
return (value - a) / (b - a)
return 0.0
@staticmethod
def norm(start: float, stop: float, value: float) -> float:
return MathUtils.lerpInv(start, stop, value)
@staticmethod
def map(min_start: float, min_stop: float, max_start: float, max_stop: float, value: float) -> float:
return max_start + (value - min_start) * (max_stop - max_start) / (min_stop - min_start)
@staticmethod
def dist(x1: float, y1: float, x2: float, y2: float) -> float:
return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
@staticmethod
def max(var1: float, var2: float) -> float:
return max(var1, var2)
@staticmethod
def min(var1: float, var2: float) -> float:
return min(var1, var2)
@staticmethod
def degrees(radians: float) -> float:
return math.degrees(radians)
@staticmethod
def radians(degrees: float) -> float:
return math.radians(degrees)
@staticmethod
def exp(a: float) -> float:
return math.exp(a)
@staticmethod
def log(a: float) -> float:
return math.log(a)
@staticmethod
def pow(a: float, b: float) -> float:
return a ** b
@staticmethod
def sqrt(a: float) -> float:
return math.sqrt(a)
@staticmethod
def sin(angle: float) -> float:
return math.sin(angle)
@staticmethod
def cos(angle: float) -> float:
return math.cos(angle)
@staticmethod
def tan(angle: float) -> float:
return math.tan(angle)
@staticmethod
def atan2(a: float, b: float) -> float:
return math.atan2(a, b)
@staticmethod
def random() -> float:
import random
return random.random()
@staticmethod
def isNaN(v: float) -> bool:
return math.isnan(v)
@staticmethod
def nanToZero(value: float) -> float:
return 0.0 if math.isnan(value) else value
# ═══════════════════════════════════════════════════════════════
# Pattern (re)
# ═══════════════════════════════════════════════════════════════
class Pattern(Stub):
"""Pattern — 正则表达式模式"""
CASE_INSENSITIVE = 2
MULTILINE = 8
DOTALL = 32
UNICODE_CASE = 64
CANON_EQ = 128
UNIX_LINES = 1
LITERAL = 16
COMMENTS = 4
def __init__(self, pattern: str, flags: int = 0):
super().__init__()
self._pattern_str = pattern
self._flags = flags
re_flags = 0
if flags & self.CASE_INSENSITIVE:
re_flags |= _re.IGNORECASE
if flags & self.MULTILINE:
re_flags |= _re.MULTILINE
if flags & self.DOTALL:
re_flags |= _re.DOTALL
if flags & self.UNICODE_CASE:
re_flags |= _re.UNICODE
if flags & self.UNIX_LINES:
pass # no re equivalent
self._compiled = _re.compile(pattern, re_flags)
@staticmethod
def compile(pattern: str, flags: int = 0) -> "Pattern":
return Pattern(pattern, flags)
def matcher(self, input_str: str) -> "Matcher":
return Matcher(self._compiled, input_str)
def split(self, input_str: str, limit: int = 0) -> List[str]:
if limit < 0:
return self._compiled.split(input_str, maxsplit=0)
return self._compiled.split(input_str, maxsplit=limit - 1 if limit > 0 else 0)
def pattern(self) -> str:
return self._pattern_str
def flags(self) -> int:
return self._flags
@staticmethod
def matches(regex: str, input_str: str) -> bool:
return bool(_re.fullmatch(regex, input_str))
@staticmethod
def quote(s: str) -> str:
return _re.escape(s)
def toString(self) -> str:
return self._pattern_str
class Matcher(Stub):
"""Matcher — 正则匹配器"""
def __init__(self, compiled_pattern: "Pattern", input_str: str):
super().__init__()
self._pattern = compiled_pattern
self._input = input_str
self._region_start = 0
self._region_end = len(input_str)
self._match: Optional[Any] = None
def matches(self) -> bool:
self._match = self._pattern.fullmatch(self._input,
self._region_start, self._region_end)
return self._match is not None
def find(self, start: int = 0) -> bool:
self._match = self._pattern.search(self._input, start or self._region_start,
self._region_end)
return self._match is not None
def lookingAt(self) -> bool:
self._match = self._pattern.match(self._input, self._region_start,
self._region_end)
return self._match is not None
def group(self, group: int = 0) -> Optional[str]:
if self._match:
return self._match.group(group)
return None
def groupCount(self) -> int:
if self._match:
return len(self._match.groups())
return 0
def start(self, group: int = 0) -> int:
if self._match:
return self._match.start(group)
return -1
def end(self, group: int = 0) -> int:
if self._match:
return self._match.end(group)
return -1
def replaceAll(self, replacement: str) -> str:
return self._pattern.sub(replacement, self._input)
def replaceFirst(self, replacement: str) -> str:
return self._pattern.sub(replacement, self._input, count=1)
def region(self, start: int, end: int) -> "Matcher":
self._region_start = start
self._region_end = end
return self
def regionStart(self) -> int:
return self._region_start
def regionEnd(self) -> int:
return self._region_end
def reset(self, input_str: Optional[str] = None) -> "Matcher":
if input_str is not None:
self._input = input_str
self._match = None
return self
def hitEnd(self) -> bool:
return False
def requireEnd(self) -> bool:
return False
def usePattern(self, new_pattern: "Pattern") -> "Matcher":
self._pattern = new_pattern
return self
def appendReplacement(self, sb: Any, replacement: str):
pass
def appendTail(self, sb: Any):
pass
def toString(self) -> str:
return f"Matcher({self._pattern.pattern()})"
# ═══════════════════════════════════════════════════════════════
# TYPED_VALUE 常量
# ═══════════════════════════════════════════════════════════════
TYPED_VALUE = TypedValue # 别名
# ═══════════════════════════════════════════════════════════════
# Pair 反向兼容 (android.util.Pair)
# ═══════════════════════════════════════════════════════════════
# Pair 已在上面定义
# ═══════════════════════════════════════════════════════════════
# __all__
# ═══════════════════════════════════════════════════════════════
__all__ = [
"Log",
"SparseArray",
"SparseIntArray",
"SparseBooleanArray",
"LruCache",
"DisplayMetrics",
"TypedValue",
"Pair",
"Size",
"SizeF",
"StateSet",
"MathUtils",
"Pattern",
"Matcher",
"TYPED_VALUE",
]