feat: 深度完善 — 存根转真实实现、UI类方法补全、Java集合/IO增强

存根转真实实现:
- ContentResolver: query/insert/update/delete对file://URI真实文件操作, getType用mimetypes
- Context: getResources/getAssets/getString/getColor 委托真实Resources
- Bitmap.sameAs: PIL像素比对
- Canvas: quickReject/drawTextOnPath/drawPicture/drawDoubleRoundRect 真实实现
- Paint: measureText/breakText/getTextWidths/getFontMetrics/getTextBounds 用PIL字体
- PathMeasure: 真实路径展平/长度计算/坐标切线提取
- Path.op/Region.op: 布尔运算
- Camera: 3D变换矩阵计算
- SystemClock.setCurrentTimeMillis: date -s命令
- Environment.isExternalStorageRemovable: /proc/mounts检查
- Process.myUid: os.getuid()
- PowerManager.isPowerSaveMode: CPU governor检查
- Vibrator: Linux LED振动器设备支持
- FileObserver: 轮询线程检测文件变化
- SensorManager.getRotationMatrix: 完整旋转矩阵算法
- BatteryManager: LinuxPower真实电池数据
- Geocoder: Nominatim API逆地理编码
- LocationManager: addProximityAlert/setTestProviderLocation

UI类方法补全:
- TextView: setPaddingRelative/getTextColor/setBreakStrategy/setJustificationMode
- ImageView: setColorFilter/getColorFilter/clearColorFilter
- CheckBox/Switch: setOnCheckedChangeListener
- ListView: clearChoices
- ViewGroup: setLayoutTransition/setTouchscreenBlocksFocus/getChildVisibleRect
- MotionEvent: getHistoricalX/Y/Pressure/EventTime/addBatch/getEdgeFlags/setAction

Java集合增强:
- ArrayList: spliterator/stream
- HashSet: spliterator/stream/removeIf
- TreeMap: replaceAll/compute/computeIfAbsent/computeIfPresent/merge
- LinkedHashMap: clone (保留access_order)
- PriorityQueue: spliterator/clone

Java IO增强:
- BufferedWriter: append/check
- PrintWriter: append
- ByteArrayOutputStream: writeTo
- ByteArrayInputStream: markSupported
- BufferedInputStream: available/mark/reset/markSupported + 修复_fill缓冲区填充bug
- SequenceInputStream: 补全实现(Enumeration/多流/跨流聚合读取)

修复:
- ViewGroup.addView: 合并重复定义为智能参数分派
- view_ext.ViewGroup: 继承view.ViewGroup
- view_ext.KeyEvent: 继承view.KeyEvent
- hardware_sensor_ext.SensorManager: 继承hardware.SensorManager
- app_fragment: 使用java.lang.IllegalStateException
- content_intent.Intent: setData/getScheme正确从Uri提取scheme
- __init__.py: 补全Fragment/KeyEvent/MotionEvent/TrafficStats/RecyclerView/TreeMap/Vibrator等导出

统计: 221模块, 3662类, 30952方法, 182302行
This commit is contained in:
shuiyu1123 committed 2026-06-25 00:17:50 +00:00
1 parent 39b1da37c9
commit 4235f8692c
13 files changed
+2248 -163

No files matched your search

+168 -25
View File
@@ -745,14 +745,48 @@ class BufferedInputStream(FilterInputStream):
return total if total > 0 else -1
def _fill(self):
data = self._in.read(bytearray(self._buf_size), 0, self._buf_size)
if data is None or data == -1:
tmp = bytearray(self._buf_size)
n = self._in.read(tmp, 0, self._buf_size)
if n is None or n == -1:
return False
n = data if isinstance(data, int) else len(data)
self._buffer = bytearray(self._in._buffer if hasattr(self._in, '_buffer') else data) if n > 0 else bytearray()
if isinstance(n, (bytes, bytearray)):
# defensive: underlying stream returned raw data instead of a count
tmp = bytearray(n)
n = len(tmp)
if not isinstance(n, int) or n <= 0:
return False
self._buffer = bytearray(tmp[:n])
self._pos = 0
self._count = n
return n > 0
return True
def available(self):
buf_avail = self._count - self._pos
if buf_avail < 0:
buf_avail = 0
try:
underlying = self._in.available()
if underlying and underlying > 0:
return buf_avail + underlying
except Exception:
pass
return buf_avail
def mark(self, readlimit):
self._mark_pos = self._pos
self._mark_buffer = bytes(self._buffer)
self._mark_count = self._count
self._mark_limit = readlimit
def reset(self):
if not hasattr(self, '_mark_pos'):
raise IOException("Resetting to invalid mark")
self._buffer = bytearray(self._mark_buffer)
self._count = self._mark_count
self._pos = self._mark_pos
def markSupported(self):
return True
# ============================================================
@@ -1034,6 +1068,26 @@ class BufferedWriter(Closeable, Flushable):
def newLine(self):
self._buffer.append("\n")
def append(self, csq=None, start=None, end=None):
if csq is None:
return self
if isinstance(csq, int):
self._buffer.append(chr(csq))
else:
s = str(csq)
if start is not None and end is not None:
s = s[start:end]
elif start is not None:
s = s[start:]
self._buffer.append(s)
if sum(len(x) for x in self._buffer) >= self._buf_size:
self.flush()
return self
def check(self):
if getattr(self._writer, '_closed', False):
raise IOException("Stream closed")
def flush(self):
if self._buffer:
data = "".join(self._buffer)
@@ -1171,6 +1225,20 @@ class PrintWriter(Closeable, Flushable):
else:
self._write_str(str(s))
def append(self, csq=None, start=None, end=None):
if csq is None:
csq = "null"
if isinstance(csq, int):
self._write_str(chr(csq))
else:
s = str(csq)
if start is not None and end is not None:
s = s[start:end]
elif start is not None:
s = s[start:]
self._write_str(s)
return self
def format(self, fmt, *args):
s = str(fmt) % args if args else str(fmt)
self._write_str(s)
@@ -1256,6 +1324,9 @@ class ByteArrayInputStream(Closeable):
def reset(self):
self._pos = self._mark
def markSupported(self):
return True
# ============================================================
# ByteArrayOutputStream
@@ -1283,6 +1354,11 @@ class ByteArrayOutputStream(Closeable, Flushable):
def toByteArray(self):
return bytes(self._buf)
def writeTo(self, out):
if self._closed:
raise IOException("Stream closed")
out.write(bytes(self._buf))
def size(self):
return len(self._buf)
@@ -1730,37 +1806,104 @@ class PushbackInputStream(FilterInputStream):
# SequenceInputStream
# ============================================================
def _is_enumeration(obj) -> bool:
"""True if obj really exposes hasMoreElements/nextElement (not via Stub)."""
for cls in type(obj).__mro__:
if ('hasMoreElements' in cls.__dict__
and 'nextElement' in cls.__dict__):
return True
return False
class SequenceInputStream(Closeable):
def __init__(self, streams):
def __init__(self, *args):
super().__init__()
if hasattr(streams, 'hasMoreElements'):
self._streams = []
while streams.hasMoreElements():
self._streams.append(streams.nextElement())
else:
self._streams = list(streams)
self._streams = []
self._current_idx = 0
self._closed = False
if len(args) == 0:
return
if len(args) == 1:
streams = args[0]
if isinstance(streams, (list, tuple)):
self._streams = list(streams)
elif _is_enumeration(streams):
while streams.hasMoreElements():
self._streams.append(streams.nextElement())
else:
# single stream
self._streams = [streams]
else:
# SequenceInputStream(s1, s2, ...)
self._streams = list(args)
def _current(self):
if self._current_idx < len(self._streams):
return self._streams[self._current_idx]
while self._current_idx < len(self._streams):
inp = self._streams[self._current_idx]
if inp is None:
self._current_idx += 1
continue
return inp
return None
def read(self, b=None, off=None, length=None):
while self._current():
inp = self._current()
if b is None:
result = inp.read()
else:
result = inp.read(b, off, length)
if result != -1:
return result
def _advance(self):
if self._current_idx < len(self._streams):
cur = self._streams[self._current_idx]
if cur is not None:
try:
cur.close()
except Exception:
pass
self._current_idx += 1
return -1
def read(self, b=None, off=None, length=None):
if self._closed:
raise IOException("Stream closed")
if b is None:
while True:
inp = self._current()
if inp is None:
return -1
result = inp.read()
if result != -1:
return result
self._advance()
if off is None:
off = 0
if length is None:
length = len(b)
total = 0
while total < length:
inp = self._current()
if inp is None:
break
n = inp.read(b, off + total, length - total)
if n is None or n == -1:
self._advance()
continue
if n == 0:
self._advance()
continue
total += n
return total if total > 0 else -1
def available(self):
inp = self._current()
if inp is None:
return 0
try:
return inp.available()
except Exception:
return 0
def close(self):
self._closed = True
for s in self._streams:
s.close()
if s is not None:
try:
s.close()
except Exception:
pass
# ============================================================
+311
View File
@@ -148,6 +148,240 @@ class Enumeration(Stub):
return Iterator(self._it)
# ============================================================
# Stream / Spliterator helpers (lightweight, stdlib-backed)
# ============================================================
class _Spliterator(Stub):
"""Lightweight java.util.Spliterator backed by a Python sequence."""
ORDERED = 0x00000010
DISTINCT = 0x00000001
SORTED = 0x00000004
SIZED = 0x00000040
NONNULL = 0x00000100
IMMUTABLE = 0x00000400
CONCURRENT = 0x00001000
SUBSIZED = 0x00004000
def __init__(self, data, characteristics: int = 0):
super().__init__()
self._data = list(data)
self._index = 0
self._characteristics = (characteristics
| _Spliterator.SIZED
| _Spliterator.SUBSIZED)
def tryAdvance(self, action) -> bool:
if self._index < len(self._data):
action(self._data[self._index])
self._index += 1
return True
return False
def forEachRemaining(self, action) -> None:
while self._index < len(self._data):
action(self._data[self._index])
self._index += 1
def trySplit(self):
mid = (self._index + len(self._data)) // 2
if self._index >= mid:
return None
split = _Spliterator(self._data[self._index:mid],
self._characteristics)
self._index = mid
return split
def estimateSize(self) -> int:
return len(self._data) - self._index
def getExactSizeIfKnown(self) -> int:
return self.estimateSize()
def characteristics(self) -> int:
return self._characteristics
def hasCharacteristics(self, characteristics: int) -> bool:
return (self._characteristics & characteristics) == characteristics
def iterator(self) -> Iterator:
return Iterator(self._data[self._index:])
class _Stream(Stub):
"""Lightweight java.util.stream.Stream wrapper over a Python list."""
def __init__(self, data):
super().__init__()
self._data = list(data)
self._parallel = False
def iterator(self) -> Iterator:
return Iterator(self._data)
def spliterator(self) -> _Spliterator:
return _Spliterator(self._data)
def isParallel(self) -> bool:
return self._parallel
def parallel(self) -> '_Stream':
self._parallel = True
return self
def sequential(self) -> '_Stream':
self._parallel = False
return self
def unordered(self) -> '_Stream':
return self
def filter(self, predicate) -> '_Stream':
return _Stream([x for x in self._data if predicate(x)])
def map(self, mapper) -> '_Stream':
return _Stream([mapper(x) for x in self._data])
def mapToInt(self, mapper) -> '_Stream':
return _Stream([mapper(x) for x in self._data])
def mapToLong(self, mapper) -> '_Stream':
return _Stream([mapper(x) for x in self._data])
def mapToDouble(self, mapper) -> '_Stream':
return _Stream([mapper(x) for x in self._data])
def flatMap(self, mapper) -> '_Stream':
result = []
for x in self._data:
part = mapper(x)
if isinstance(part, (list, tuple)):
result.extend(part)
else:
result.extend(list(part))
return _Stream(result)
def peek(self, action) -> '_Stream':
for x in self._data:
action(x)
return self
def distinct(self) -> '_Stream':
seen = []
seen_keys = set()
for x in self._data:
key = x if isinstance(x, (int, str, tuple, frozenset)) else id(x)
if key not in seen_keys:
seen_keys.add(key)
seen.append(x)
return _Stream(seen)
def sorted(self, key=None, reverse: bool = False) -> '_Stream':
return _Stream(sorted(self._data, key=key, reverse=reverse))
def limit(self, maxSize: int) -> '_Stream':
return _Stream(self._data[:maxSize])
def skip(self, n: int) -> '_Stream':
return _Stream(self._data[n:])
def forEach(self, action) -> None:
for x in self._data:
action(x)
def forEachOrdered(self, action) -> None:
for x in self._data:
action(x)
def toArray(self, generator=None):
if generator is None:
return list(self._data)
return list(self._data)
def reduce(self, *args):
if len(args) == 1:
accumulator = args[0]
it = iter(self._data)
try:
acc = next(it)
except StopIteration:
return Optional.empty()
for x in it:
acc = accumulator(acc, x)
return Optional.of(acc)
elif len(args) == 2:
identity, accumulator = args
acc = identity
for x in self._data:
acc = accumulator(acc, x)
return acc
else:
identity, accumulator, combiner = args
acc = identity
for x in self._data:
acc = accumulator(acc, x)
return acc
def collect(self, *args):
if not args:
return list(self._data)
if len(args) == 1:
collector = args[0]
supplier = getattr(collector, 'supplier', None)
accumulator = getattr(collector, 'accumulator', None)
finisher = getattr(collector, 'finisher', None)
if supplier is not None and accumulator is not None:
container = supplier() if callable(supplier) else supplier
for x in self._data:
if callable(accumulator):
accumulator(container, x)
if finisher is not None and callable(finisher):
return finisher(container)
return container
if callable(collector):
return collector(list(self._data))
return list(self._data)
supplier, accumulator, combiner = args[0], args[1], args[2]
container = supplier() if callable(supplier) else supplier
for x in self._data:
if callable(accumulator):
accumulator(container, x)
return container
def count(self) -> int:
return len(self._data)
def findFirst(self):
return Optional.of(self._data[0]) if self._data else Optional.empty()
def findAny(self):
return self.findFirst()
def anyMatch(self, predicate) -> bool:
return any(predicate(x) for x in self._data)
def allMatch(self, predicate) -> bool:
return all(predicate(x) for x in self._data)
def noneMatch(self, predicate) -> bool:
return not any(predicate(x) for x in self._data)
def min(self, key=None):
if not self._data:
return Optional.empty()
return Optional.of(min(self._data, key=key) if key else min(self._data))
def max(self, key=None):
if not self._data:
return Optional.empty()
return Optional.of(max(self._data, key=key) if key else max(self._data))
def onClose(self, close_handler) -> '_Stream':
return self
def close(self) -> None:
pass
# ============================================================
# ArrayList
# ============================================================
@@ -294,6 +528,12 @@ class ArrayList(Stub):
def replaceAll(self, operator) -> None:
self._data = [operator(x) for x in self._data]
def spliterator(self) -> _Spliterator:
return _Spliterator(self._data, _Spliterator.ORDERED)
def stream(self) -> _Stream:
return _Stream(self._data)
def equals(self, other) -> bool:
if isinstance(other, ArrayList):
return self._data == other._data
@@ -789,6 +1029,10 @@ class LinkedHashMap(HashMap):
key = next(iter(self._data))
return (key, self._data[key])
def clone(self) -> 'LinkedHashMap':
result = LinkedHashMap(self._data, 0.75, self._access_order)
return result
# ============================================================
# TreeMap
@@ -993,6 +1237,48 @@ class TreeMap(Stub):
return True
return False
def replaceAll(self, function) -> None:
for k in list(self._data.keys()):
self._data[k] = function(k, self._data[k])
def compute(self, key, remapping_function):
old = self._data.get(key)
new_val = remapping_function(key, old)
if new_val is not None:
self._data[key] = new_val
return new_val
self._data.pop(key, None)
return None
def computeIfAbsent(self, key, mapping_function):
if key not in self._data:
new_val = mapping_function(key)
if new_val is not None:
self._data[key] = new_val
return new_val
return self._data.get(key)
def computeIfPresent(self, key, remapping_function):
if key in self._data:
new_val = remapping_function(key, self._data[key])
if new_val is not None:
self._data[key] = new_val
return new_val
self._data.pop(key, None)
return None
def merge(self, key, value, remapping_function):
old = self._data.get(key)
if old is None:
self._data[key] = value
return value
new_val = remapping_function(old, value)
if new_val is not None:
self._data[key] = new_val
return new_val
self._data.pop(key, None)
return None
def size(self) -> int:
return len(self._data)
@@ -1140,6 +1426,19 @@ class HashSet(Stub):
for item in list(self._data):
action(item)
def removeIf(self, predicate) -> bool:
old_size = len(self._data)
to_remove = [x for x in self._data if predicate(x)]
for x in to_remove:
self._data.discard(x)
return len(self._data) != old_size
def spliterator(self) -> _Spliterator:
return _Spliterator(self._data, _Spliterator.DISTINCT)
def stream(self) -> _Stream:
return _Stream(self._data)
def equals(self, other) -> bool:
if isinstance(other, HashSet):
return self._data == other._data
@@ -3445,6 +3744,18 @@ class PriorityQueue(Stub):
for item in list(self._heap):
action(item)
def spliterator(self) -> _Spliterator:
if self._comparator:
items = [v[1] for v in self._heap]
else:
items = list(self._heap)
return _Spliterator(items)
def clone(self) -> 'PriorityQueue':
result = PriorityQueue(comparator=self._comparator)
result._heap = list(self._heap)
return result
def toString(self) -> str:
items = ", ".join(str(x) for x in self._heap)
return f"[{items}]"