feat: 第三轮深度完善 — SQLite/JSON/网络/媒体/文本 真实实现

SQLite真实数据库:
- SQLiteDatabase: execSQL/insert/insertOrThrow/replace/update/delete/query 用sqlite3
- 修复getVersion/setVersion用PRAGMA user_version
- 修复getMaximumSize/getPageSize/setMaximumSize/setPageSize用PRAGMA
- SQLiteStatement: execute/simpleQueryForLong/simpleQueryForString/execQuery
- SQLiteOpenHelper: onCreate/onUpgrade/onDowngrade回调正确触发
- 修复SQLiteCursor.moveToPosition越界处理
- 修复ContentValues值对提取bug

JSON真实实现:
- JSONObject: isNull/append/putOnce/putOpt/getNames
- JSONArray: 完整put/get/opt/length/toString

网络真实实现:
- NetworkInterface: getByName/getNetworkInterfaces/getHardwareAddress 用/sys/class/net+fcntl.ioctl
- InterfaceAddress: 新增类
- ConnectivityManager: getActiveNetwork/getAllNetworks 用LinuxNetwork
- WifiManager: getScanResults用nmcli, setWifiEnabled用nmcli/rfkill
- BluetoothAdapter: getAddress/getName 用bluetoothctl

媒体真实实现:
- MediaPlayer: prepare检查文件, getCurrentPosition实时计算, getDuration/getVideoWidth用ffprobe
- MediaRecorder: setVideoSize/setVideoFrameRate/setVideoEncodingBitRate配置存储
- MediaMetadataRetriever: extractMetadata用ffprobe, getFrameAtTime用ffmpeg, getEmbeddedPicture用ffmpeg

文本真实实现:
- TextUtils: split用re.split, concat/indexOf/lastIndexOf/urlEncode/urlDecode
- SpannableString: setSpan/getSpans/getSpanFlags/nextSpanTransition 真实实现
- SpannableStringBuilder: 修复append重载bug

Provider增强:
- Settings: putBoolean/getBoolean
- MediaStore: getContentUri/VOLUME常量
- ContactsContract: 补全常量和CommonDataKinds

Util增强:
- Log: w/e/wtf支持Throwable参数, 修复wtf重复定义bug
- TypedValue: 修复complexToDimension/complexToFloat/getFloat实现

修复:
- __init__.py: 补全NetworkInterface/InetAddress/MediaMetadataRetriever/SpannableStringBuilder导出

统计: 221模块, 3666类, 31005方法, 183529行
This commit is contained in:
shuiyu1123 committed 2026-06-25 00:40:59 +00:00
1 parent 4235f8692c
commit fbb8263b13
13 files changed
+1373 -146

No files matched your search

+203 -50
View File
@@ -181,9 +181,13 @@ class SQLiteProgram(SQLiteClosable):
def clearBindings(self):
self._bindings.clear()
def _ordered_bind_args(self) -> list:
"""按绑定索引升序返回参数列表(1-based 索引排序)。"""
return [self._bindings[k] for k in sorted(self._bindings.keys())]
def _bind_parameters(self, cursor: _sqlite3.Cursor):
for idx, val in sorted(self._bindings.items()):
cursor.execute(f"PRAGMA dummy={idx}")
for idx in sorted(self._bindings.keys()):
cursor.bind(idx, self._bindings[idx])
# ═══════════════════════════════════════════════════════════════
@@ -199,16 +203,18 @@ class SQLiteStatement(SQLiteProgram):
def execute(self):
try:
conn = self._db._acquire_connection()
cursor = conn.execute(self._sql, list(self._bindings.values()))
conn.commit()
conn.execute(self._sql, self._ordered_bind_args())
if not self._db._in_transaction:
conn.commit()
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e), self._sql)
def executeUpdateDelete(self) -> int:
try:
conn = self._db._acquire_connection()
cursor = conn.execute(self._sql, list(self._bindings.values()))
conn.commit()
cursor = conn.execute(self._sql, self._ordered_bind_args())
if not self._db._in_transaction:
conn.commit()
return cursor.rowcount
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e), self._sql)
@@ -216,8 +222,9 @@ class SQLiteStatement(SQLiteProgram):
def executeInsert(self) -> int:
try:
conn = self._db._acquire_connection()
cursor = conn.execute(self._sql, list(self._bindings.values()))
conn.commit()
cursor = conn.execute(self._sql, self._ordered_bind_args())
if not self._db._in_transaction:
conn.commit()
return cursor.lastrowid
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e), self._sql)
@@ -225,9 +232,10 @@ class SQLiteStatement(SQLiteProgram):
def simpleQueryForLong(self) -> int:
try:
conn = self._db._acquire_connection()
cursor = conn.execute(self._sql, list(self._bindings.values()))
cursor = conn.execute(self._sql, self._ordered_bind_args())
row = cursor.fetchone()
conn.commit()
if not self._db._in_transaction:
conn.commit()
if row:
return int(row[0]) if row[0] is not None else 0
raise SQLiteDoneException("no results")
@@ -237,15 +245,43 @@ class SQLiteStatement(SQLiteProgram):
def simpleQueryForString(self) -> Optional[str]:
try:
conn = self._db._acquire_connection()
cursor = conn.execute(self._sql, list(self._bindings.values()))
cursor = conn.execute(self._sql, self._ordered_bind_args())
row = cursor.fetchone()
conn.commit()
if not self._db._in_transaction:
conn.commit()
if row:
return str(row[0]) if row[0] is not None else None
raise SQLiteDoneException("no results")
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e), self._sql)
def simpleQueryForBlobString(self) -> Optional[bytes]:
try:
conn = self._db._acquire_connection()
cursor = conn.execute(self._sql, self._ordered_bind_args())
row = cursor.fetchone()
if not self._db._in_transaction:
conn.commit()
if row:
v = row[0]
if v is None:
return None
if isinstance(v, bytes):
return v
if isinstance(v, str):
return v.encode("utf-8")
return bytes(str(v), "utf-8")
raise SQLiteDoneException("no results")
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e), self._sql)
def execQuery(self) -> "SQLiteCursor":
"""执行查询 SQL 并返回 SQLiteCursor。"""
query = SQLiteQuery(self._db, self._sql)
for idx, val in self._bindings.items():
query.bind(idx, val)
return SQLiteCursor(self._db, query)
# ═══════════════════════════════════════════════════════════════
# SQLiteQuery
@@ -313,10 +349,17 @@ class SQLiteCursor(AbstractCursor):
def moveToPosition(self, position: int) -> bool:
self._load()
if position < -1 or position >= len(self._rows):
count = len(self._rows)
if position >= count:
self._pos = count
self._current_row = None
return False
if position < -1:
self._pos = -1
self._current_row = None
return False
self._pos = position
if 0 <= position < len(self._rows):
if 0 <= position < count:
self._current_row = self._rows[position]
else:
self._current_row = None
@@ -499,6 +542,39 @@ def _map_sqlite_error(msg: str, sql: str = "") -> SQLiteException:
return SQLiteException(msg)
def _extract_value_pairs(values: Any) -> List[Tuple[str, Any]]:
"""从 ContentValues / dict / 类似对象中提取 (列名, 值) 列表。
注意: 本实现中 ContentValues.valueSet() 返回的是键集合而非 (键, 值) 对,
因此需要通过 get() 取值。
"""
if values is None:
return []
if isinstance(values, dict):
return list(values.items())
# ContentValues 内部使用 _values dict
inner = getattr(values, "_values", None)
if isinstance(inner, dict):
return list(inner.items())
# ContentValues.valueSet() 在本实现中返回键集合
if hasattr(values, "valueSet") and hasattr(values, "get"):
try:
return [(str(k), values.get(k)) for k in values.valueSet()]
except Exception:
pass
if hasattr(values, "keySet") and hasattr(values, "get"):
try:
return [(str(k), values.get(k)) for k in values.keySet()]
except Exception:
pass
if hasattr(values, "items"):
try:
return [(str(k), v) for k, v in values.items()]
except Exception:
pass
return []
class SQLiteDatabase(SQLiteClosable):
"""SQLiteDatabase — 数据库操作类"""
@@ -536,10 +612,10 @@ class SQLiteDatabase(SQLiteClosable):
try:
db._conn = _sqlite3.connect(path)
db._conn.execute("PRAGMA journal_mode=WAL")
conn_cursor = db._conn.execute("PRAGMA schema_version")
conn_cursor = db._conn.execute("PRAGMA user_version")
row = conn_cursor.fetchone()
if row:
db._version = row[0]
db._version = int(row[0])
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e))
SQLiteDatabase._db_registry[path] = db
@@ -610,23 +686,37 @@ class SQLiteDatabase(SQLiteClosable):
self._ensure_open()
if values is None:
return -1
cols = []
vals = []
if hasattr(values, "valueSet"):
items = list(values.valueSet())
elif hasattr(values, "key_set"):
items = [(k, getattr(values, f"get{k[0].upper()}{k[1:]}", lambda: None)())
for k in values.key_set()]
elif isinstance(values, dict):
items = list(values.items())
else:
return -1
for k, v in items:
cols.append(str(k))
vals.append(v)
if len(cols) == 0:
items = _extract_value_pairs(values)
if not items:
cols = ["_id"]
vals = [None]
vals: List[Any] = [None]
else:
cols = [str(k) for k, _ in items]
vals = [v for _, v in items]
col_str = ", ".join(cols)
placeholders = ", ".join(["?"] * len(vals))
sql = f"INSERT INTO {table} ({col_str}) VALUES ({placeholders})"
try:
conn = self._acquire_connection()
cursor = conn.execute(sql, vals)
if not self._in_transaction:
conn.commit()
return cursor.lastrowid
except _sqlite3.DatabaseError:
return -1
def insertOrThrow(self, table: str, null_column_hack: Optional[str],
values: Any) -> int:
self._ensure_open()
if values is None:
raise SQLiteException("null values not allowed")
items = _extract_value_pairs(values)
if not items:
cols = ["_id"]
vals: List[Any] = [None]
else:
cols = [str(k) for k, _ in items]
vals = [v for _, v in items]
col_str = ", ".join(cols)
placeholders = ", ".join(["?"] * len(vals))
sql = f"INSERT INTO {table} ({col_str}) VALUES ({placeholders})"
@@ -639,23 +729,41 @@ class SQLiteDatabase(SQLiteClosable):
except _sqlite3.DatabaseError as e:
raise _map_sqlite_error(str(e), sql)
def replace(self, table: str, null_column_hack: Optional[str],
values: Any) -> int:
self._ensure_open()
if values is None:
return -1
items = _extract_value_pairs(values)
if not items:
cols = ["_id"]
vals: List[Any] = [None]
else:
cols = [str(k) for k, _ in items]
vals = [v for _, v in items]
col_str = ", ".join(cols)
placeholders = ", ".join(["?"] * len(vals))
sql = f"INSERT OR REPLACE INTO {table} ({col_str}) VALUES ({placeholders})"
try:
conn = self._acquire_connection()
cursor = conn.execute(sql, vals)
if not self._in_transaction:
conn.commit()
return cursor.lastrowid
except _sqlite3.DatabaseError:
return -1
def update(self, table: str, values: Any,
where_clause: Optional[str] = None,
where_args: Optional[List[Any]] = None) -> int:
self._ensure_open()
if values is None:
return 0
set_pairs = []
vals = []
if isinstance(values, dict):
items = list(values.items())
elif hasattr(values, "valueSet"):
items = list(values.valueSet())
else:
items = _extract_value_pairs(values)
if not items:
return 0
for k, v in items:
set_pairs.append(f"{k} = ?")
vals.append(v)
set_pairs = [f"{k} = ?" for k, _ in items]
vals: List[Any] = [v for _, v in items]
set_str = ", ".join(set_pairs)
sql = f"UPDATE {table} SET {set_str}"
if where_clause:
@@ -748,13 +856,24 @@ class SQLiteDatabase(SQLiteClosable):
return self._path
def getVersion(self) -> int:
if self._conn:
try:
cursor = self._conn.execute("PRAGMA user_version")
row = cursor.fetchone()
if row:
self._version = int(row[0])
return self._version
except _sqlite3.DatabaseError:
pass
return self._version
def setVersion(self, version: int):
self._version = version
self._version = int(version)
if self._conn:
try:
self._conn.execute(f"PRAGMA schema_version = {version}")
self._conn.execute(f"PRAGMA user_version = {int(version)}")
if not self._in_transaction:
self._conn.commit()
except _sqlite3.DatabaseError:
pass
@@ -784,20 +903,54 @@ class SQLiteDatabase(SQLiteClosable):
return self._enable_wal
def getMaximumSize(self) -> int:
if self._conn:
try:
page_size = self.getPageSize()
if page_size <= 0:
page_size = 4096
cursor = self._conn.execute("PRAGMA max_page_count")
row = cursor.fetchone()
if row:
self._max_size = int(row[0]) * page_size
return self._max_size
except _sqlite3.DatabaseError:
pass
return self._max_size
def getPageSize(self) -> int:
if self._conn:
try:
cursor = self._conn.execute("PRAGMA page_size")
row = cursor.fetchone()
if row:
self._page_size = int(row[0])
return self._page_size
except _sqlite3.DatabaseError:
pass
return self._page_size
def setMaximumSize(self, size: int) -> int:
self._max_size = size
return size
def setPageSize(self, size: int):
self._page_size = size
self._max_size = int(size)
if self._conn:
try:
self._conn.execute(f"PRAGMA page_size = {size}")
page_size = self.getPageSize()
if page_size <= 0:
page_size = 4096
max_pages = max(1, int(size) // page_size)
cursor = self._conn.execute(f"PRAGMA max_page_count = {max_pages}")
row = cursor.fetchone()
if row:
self._max_size = int(row[0]) * page_size
return self._max_size
except _sqlite3.DatabaseError:
pass
return self._max_size
def setPageSize(self, size: int):
self._page_size = int(size)
if self._conn:
try:
self._conn.execute(f"PRAGMA page_size = {int(size)}")
except _sqlite3.DatabaseError:
pass