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类
This commit is contained in:
1 parent
4645015004
commit
8c3bd3c415
9 files changed
+1017
-52
No files matched your search
+346
-12
@@ -18,6 +18,16 @@ from datetime import datetime as _datetime
|
||||
|
||||
__all__ = [
|
||||
"Object", "Throwable", "Exception", "RuntimeException", "Error",
|
||||
"NullPointerException", "IllegalArgumentException", "IllegalStateException",
|
||||
"IndexOutOfBoundsException", "ArrayIndexOutOfBoundsException",
|
||||
"StringIndexOutOfBoundsException", "ClassCastException",
|
||||
"UnsupportedOperationException", "ArithmeticException",
|
||||
"NumberFormatException", "SecurityException",
|
||||
"ConcurrentModificationException", "NegativeArraySizeException",
|
||||
"NoSuchFieldException", "NoSuchMethodException", "InterruptedException",
|
||||
"CloneNotSupportedException", "IllegalMonitorStateException",
|
||||
"IllegalThreadStateException", "EnumConstantNotPresentException",
|
||||
"TypeNotPresentException",
|
||||
"String", "Integer", "Long", "Short", "Byte", "Float", "Double",
|
||||
"Boolean", "Character", "Math", "StrictMath", "System",
|
||||
"Thread", "ThreadLocal", "StringBuilder", "StringBuffer",
|
||||
@@ -148,6 +158,75 @@ class Error(Throwable):
|
||||
pass
|
||||
|
||||
|
||||
class NullPointerException(RuntimeException):
|
||||
pass
|
||||
|
||||
class IllegalArgumentException(RuntimeException):
|
||||
pass
|
||||
|
||||
class IllegalStateException(RuntimeException):
|
||||
pass
|
||||
|
||||
class IndexOutOfBoundsException(RuntimeException):
|
||||
pass
|
||||
|
||||
class ArrayIndexOutOfBoundsException(IndexOutOfBoundsException):
|
||||
pass
|
||||
|
||||
class StringIndexOutOfBoundsException(IndexOutOfBoundsException):
|
||||
pass
|
||||
|
||||
class ClassCastException(RuntimeException):
|
||||
pass
|
||||
|
||||
class UnsupportedOperationException(RuntimeException):
|
||||
pass
|
||||
|
||||
class ArithmeticException(RuntimeException):
|
||||
pass
|
||||
|
||||
class NumberFormatException(IllegalArgumentException):
|
||||
pass
|
||||
|
||||
class SecurityException(RuntimeException):
|
||||
pass
|
||||
|
||||
class ConcurrentModificationException(RuntimeException):
|
||||
pass
|
||||
|
||||
class NegativeArraySizeException(RuntimeException):
|
||||
pass
|
||||
|
||||
class NoSuchFieldException(Exception):
|
||||
pass
|
||||
|
||||
class NoSuchMethodException(Exception):
|
||||
pass
|
||||
|
||||
class InterruptedException(Exception):
|
||||
pass
|
||||
|
||||
class CloneNotSupportedException(Exception):
|
||||
pass
|
||||
|
||||
class IllegalMonitorStateException(RuntimeException):
|
||||
pass
|
||||
|
||||
class IllegalThreadStateException(IllegalArgumentException):
|
||||
pass
|
||||
|
||||
class EnumConstantNotPresentException(RuntimeException):
|
||||
def __init__(self, e, constant):
|
||||
super().__init__(f"{e}.{constant}")
|
||||
self.enumType = e
|
||||
self.constantName = constant
|
||||
|
||||
class TypeNotPresentException(RuntimeException):
|
||||
def __init__(self, typeName, cause=None):
|
||||
super().__init__(f"Type {typeName} not present", cause)
|
||||
self.typeName = typeName
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StackTraceElement
|
||||
# ============================================================
|
||||
@@ -277,11 +356,10 @@ class String(CharSequence):
|
||||
def getBytes(self, charset="UTF-8"):
|
||||
return self._str.encode(charset, errors="replace")
|
||||
|
||||
def hashCode(self):
|
||||
def hashCode(self) -> int:
|
||||
h = 0
|
||||
for c in self._str:
|
||||
h = (31 * h + ord(c)) & 0xFFFFFFFF
|
||||
return h if h < 0x80000000 else h - 0x100000000
|
||||
for i in range(len(self._str)):
|
||||
h = 31 * h + ord(self._str[i])
|
||||
return h & 0x7FFFFFFF
|
||||
|
||||
def indexOf(self, ch, fromIndex=0):
|
||||
@@ -362,6 +440,89 @@ class String(CharSequence):
|
||||
def trim(self):
|
||||
return String(self._str.strip())
|
||||
|
||||
def strip(self):
|
||||
return String(self._str.strip())
|
||||
|
||||
def stripLeading(self):
|
||||
return String(self._str.lstrip())
|
||||
|
||||
def stripTrailing(self):
|
||||
return String(self._str.rstrip())
|
||||
|
||||
def isBlank(self):
|
||||
return self._str.strip() == ""
|
||||
|
||||
def repeat(self, count):
|
||||
return String(self._str * count)
|
||||
|
||||
def lines(self):
|
||||
from .util import ArrayList
|
||||
result = ArrayList()
|
||||
for line in self._str.splitlines():
|
||||
result.add(String(line))
|
||||
return result
|
||||
|
||||
def subSequence(self, start, end):
|
||||
return self.substring(start, end)
|
||||
|
||||
def getChars(self, srcBegin, srcEnd, dst, dstBegin):
|
||||
chars = self._str[srcBegin:srcEnd]
|
||||
for i, c in enumerate(chars):
|
||||
dst[dstBegin + i] = c
|
||||
|
||||
def chars(self):
|
||||
return [ord(c) for c in self._str]
|
||||
|
||||
def formatted(self, *args):
|
||||
return String(self._str.format(*args))
|
||||
|
||||
def translateEscapes(self):
|
||||
result = []
|
||||
s = self._str
|
||||
i = 0
|
||||
n = len(s)
|
||||
while i < n:
|
||||
c = s[i]
|
||||
if c == '\\' and i + 1 < n:
|
||||
nxt = s[i + 1]
|
||||
if nxt == 'b':
|
||||
result.append('\b'); i += 2
|
||||
elif nxt == 't':
|
||||
result.append('\t'); i += 2
|
||||
elif nxt == 'n':
|
||||
result.append('\n'); i += 2
|
||||
elif nxt == 'f':
|
||||
result.append('\f'); i += 2
|
||||
elif nxt == 'r':
|
||||
result.append('\r'); i += 2
|
||||
elif nxt == 's':
|
||||
result.append(' '); i += 2
|
||||
elif nxt == '"':
|
||||
result.append('"'); i += 2
|
||||
elif nxt == "'":
|
||||
result.append("'"); i += 2
|
||||
elif nxt == '\\':
|
||||
result.append('\\'); i += 2
|
||||
elif nxt in '01234567':
|
||||
octal = nxt
|
||||
i += 2
|
||||
max_digits = 2 if nxt in '0123' else 1
|
||||
while len(octal) < max_digits + 1 and i < n and s[i] in '01234567':
|
||||
octal += s[i]
|
||||
i += 1
|
||||
result.append(chr(int(octal, 8)))
|
||||
elif nxt == '\n':
|
||||
i += 2
|
||||
elif nxt == '\r':
|
||||
i += 2
|
||||
if i < n and s[i] == '\n':
|
||||
i += 1
|
||||
else:
|
||||
result.append(nxt); i += 2
|
||||
else:
|
||||
result.append(c); i += 1
|
||||
return String(''.join(result))
|
||||
|
||||
@staticmethod
|
||||
def valueOf(obj):
|
||||
return String(str(obj))
|
||||
@@ -1200,7 +1361,8 @@ class Math:
|
||||
@staticmethod
|
||||
def floor(a): return int(math.floor(a))
|
||||
@staticmethod
|
||||
def round(a): return round(a)
|
||||
def round(a: float) -> int:
|
||||
return int(math.floor(a + 0.5))
|
||||
@staticmethod
|
||||
def min(a, b): return a if a < b else b
|
||||
@staticmethod
|
||||
@@ -1266,8 +1428,58 @@ class StrictMath(Math):
|
||||
pass
|
||||
|
||||
|
||||
class _Console:
|
||||
"""java.io.Console 简化实现,供 System.console() 使用"""
|
||||
def readLine(self, fmt=None, *args):
|
||||
if fmt is not None:
|
||||
try:
|
||||
_sys.stdout.write(str(fmt) % args if args else str(fmt))
|
||||
except Exception:
|
||||
_sys.stdout.write(str(fmt))
|
||||
_sys.stdout.flush()
|
||||
line = _sys.stdin.readline()
|
||||
if line == "":
|
||||
return None
|
||||
return line.rstrip("\r\n")
|
||||
|
||||
def readPassword(self, fmt=None, *args):
|
||||
import getpass
|
||||
if fmt is not None:
|
||||
try:
|
||||
_sys.stderr.write(str(fmt) % args if args else str(fmt))
|
||||
except Exception:
|
||||
_sys.stderr.write(str(fmt))
|
||||
_sys.stderr.flush()
|
||||
pwd = getpass.getpass("")
|
||||
return list(pwd) if pwd is not None else None
|
||||
|
||||
def printf(self, fmt, *args):
|
||||
try:
|
||||
_sys.stdout.write(str(fmt) % args if args else str(fmt))
|
||||
except Exception:
|
||||
_sys.stdout.write(str(fmt))
|
||||
return self
|
||||
|
||||
def format(self, fmt, *args):
|
||||
try:
|
||||
_sys.stdout.write(str(fmt) % args if args else str(fmt))
|
||||
except Exception:
|
||||
_sys.stdout.write(str(fmt))
|
||||
return self
|
||||
|
||||
def flush(self):
|
||||
_sys.stdout.flush()
|
||||
|
||||
def writer(self):
|
||||
return _sys.stdout
|
||||
|
||||
def reader(self):
|
||||
return _sys.stdin
|
||||
|
||||
|
||||
class System:
|
||||
"""java.lang.System"""
|
||||
_console = None
|
||||
@staticmethod
|
||||
def currentTimeMillis(): return int(time.time() * 1000)
|
||||
@staticmethod
|
||||
@@ -1294,6 +1506,28 @@ class System:
|
||||
os.environ[key] = value
|
||||
return value
|
||||
@staticmethod
|
||||
def clearProperty(key):
|
||||
return _os.environ.pop(key, None)
|
||||
@staticmethod
|
||||
def getenv(name=None):
|
||||
if name is None:
|
||||
return dict(_os.environ)
|
||||
return _os.environ.get(name)
|
||||
@staticmethod
|
||||
def console():
|
||||
if System._console is None:
|
||||
System._console = _Console()
|
||||
return System._console
|
||||
@staticmethod
|
||||
def setIn(in_stream):
|
||||
System.in_ = in_stream
|
||||
@staticmethod
|
||||
def setOut(out_stream):
|
||||
System.out = out_stream
|
||||
@staticmethod
|
||||
def setErr(err_stream):
|
||||
System.err = err_stream
|
||||
@staticmethod
|
||||
def lineSeparator(): return _os.linesep
|
||||
in_ = _sys.stdin
|
||||
out = _sys.stdout
|
||||
@@ -1306,6 +1540,18 @@ class Thread(Runnable):
|
||||
NORM_PRIORITY = 5
|
||||
MAX_PRIORITY = 10
|
||||
|
||||
# Thread.State 常量(java.lang.Thread.State)
|
||||
NEW = "NEW"
|
||||
RUNNABLE = "RUNNABLE"
|
||||
BLOCKED = "BLOCKED"
|
||||
WAITING = "WAITING"
|
||||
TIMED_WAITING = "TIMED_WAITING"
|
||||
TERMINATED = "TERMINATED"
|
||||
|
||||
# 按 Python 线程 ident 缓存 Thread 对象,供 currentThread() 复用
|
||||
_thread_cache = {}
|
||||
_default_uncaught_exception_handler = None
|
||||
|
||||
def __init__(self, target=None, name=None):
|
||||
super().__init__()
|
||||
self._target = target
|
||||
@@ -1313,25 +1559,91 @@ class Thread(Runnable):
|
||||
self._alive = False
|
||||
self._daemon = False
|
||||
self._interrupted = False
|
||||
self._priority = Thread.NORM_PRIORITY
|
||||
self._state = Thread.NEW
|
||||
self._py_thread = None
|
||||
self._id = _threading.get_ident()
|
||||
|
||||
def start(self):
|
||||
self._alive = True
|
||||
if self._target:
|
||||
_threading.Thread(target=self.run, daemon=self._daemon).start()
|
||||
self._state = Thread.RUNNABLE
|
||||
self._py_thread = _threading.Thread(
|
||||
target=self._run_wrapper, daemon=self._daemon, name=self._name
|
||||
)
|
||||
self._py_thread.start()
|
||||
self._id = self._py_thread.ident
|
||||
|
||||
def _run_wrapper(self):
|
||||
tid = _threading.get_ident()
|
||||
self._id = tid
|
||||
Thread._thread_cache[tid] = self
|
||||
try:
|
||||
self.run()
|
||||
except (SystemExit, KeyboardInterrupt):
|
||||
raise
|
||||
except BaseException as e:
|
||||
# 注意:模块内 Exception 已被 java.lang.Exception 覆盖,
|
||||
# 这里用 BaseException 捕获 Python 原生异常并转发给未捕获异常处理器
|
||||
handler = Thread._default_uncaught_exception_handler
|
||||
if handler is not None:
|
||||
try:
|
||||
handler.uncaughtException(self, e)
|
||||
except BaseException:
|
||||
pass
|
||||
finally:
|
||||
self._alive = False
|
||||
self._state = Thread.TERMINATED
|
||||
Thread._thread_cache.pop(tid, None)
|
||||
|
||||
def run(self):
|
||||
if self._target:
|
||||
self._target()
|
||||
|
||||
def join(self, millis=0):
|
||||
if self._py_thread is not None:
|
||||
if millis and millis > 0:
|
||||
self._py_thread.join(millis / 1000.0)
|
||||
else:
|
||||
self._py_thread.join()
|
||||
|
||||
def interrupt(self):
|
||||
self._interrupted = True
|
||||
|
||||
def isInterrupted(self):
|
||||
return self._interrupted
|
||||
|
||||
@staticmethod
|
||||
def interrupted():
|
||||
tid = _threading.get_ident()
|
||||
t = Thread._thread_cache.get(tid)
|
||||
if t is not None:
|
||||
status = t._interrupted
|
||||
t._interrupted = False
|
||||
return status
|
||||
return False
|
||||
|
||||
def isAlive(self):
|
||||
if self._py_thread is not None:
|
||||
return self._py_thread.is_alive()
|
||||
return self._alive
|
||||
|
||||
def getState(self):
|
||||
if self._py_thread is not None:
|
||||
if self._py_thread.is_alive():
|
||||
return Thread.RUNNABLE
|
||||
return Thread.TERMINATED
|
||||
return self._state
|
||||
|
||||
def getPriority(self):
|
||||
return self._priority
|
||||
|
||||
def setPriority(self, priority):
|
||||
if Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY:
|
||||
self._priority = priority
|
||||
|
||||
def getId(self):
|
||||
return self._id
|
||||
|
||||
def getName(self): return self._name
|
||||
def setName(self, n): self._name = n
|
||||
def setDaemon(self, d): self._daemon = d
|
||||
@@ -1339,15 +1651,37 @@ class Thread(Runnable):
|
||||
|
||||
@staticmethod
|
||||
def currentThread():
|
||||
return Thread(name="main")
|
||||
tid = _threading.get_ident()
|
||||
t = Thread._thread_cache.get(tid)
|
||||
if t is not None:
|
||||
return t
|
||||
# 未缓存的线程(如主线程):创建并缓存一个代表对象
|
||||
try:
|
||||
is_main = (tid == _threading.main_thread().ident)
|
||||
except Exception:
|
||||
is_main = False
|
||||
t = Thread(name="main" if is_main else f"Thread-{tid}")
|
||||
t._state = Thread.RUNNABLE
|
||||
t._alive = True
|
||||
t._id = tid
|
||||
Thread._thread_cache[tid] = t
|
||||
return t
|
||||
|
||||
@staticmethod
|
||||
def sleep(millis):
|
||||
import time
|
||||
time.sleep(millis / 1000.0)
|
||||
_time.sleep(millis / 1000.0)
|
||||
|
||||
@staticmethod
|
||||
def yield_():
|
||||
import time
|
||||
time.sleep(0)
|
||||
_time.sleep(0)
|
||||
|
||||
@staticmethod
|
||||
def setDefaultUncaughtExceptionHandler(handler):
|
||||
Thread._default_uncaught_exception_handler = handler
|
||||
|
||||
@staticmethod
|
||||
def getDefaultUncaughtExceptionHandler():
|
||||
return Thread._default_uncaught_exception_handler
|
||||
|
||||
|
||||
class ThreadLocal(Stub):
|
||||
|
||||
Reference in new issue
Block a user