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

+138
View File
@@ -108,6 +108,25 @@ class _SettingsBase(Stub):
data = _SettingsBase._load(name)
return data.get(key, default_value)
@staticmethod
def putBoolean(name: str, key: str, value: bool) -> bool:
data = _SettingsBase._load(name)
data[key] = bool(value)
_SettingsBase._save(name)
return True
@staticmethod
def getBoolean(name: str, key: str, default_value: bool = False) -> bool:
data = _SettingsBase._load(name)
val = data.get(key, default_value)
if isinstance(val, bool):
return val
if isinstance(val, str):
return val.lower() in ("true", "1", "yes")
if isinstance(val, (int, float)):
return bool(val)
return default_value
class SettingsSystem(_SettingsBase):
_NAME = "settings_system"
@@ -144,6 +163,14 @@ class SettingsSystem(_SettingsBase):
def getLong(key: str, default_value: int = 0) -> int:
return _SettingsBase.getLong(SettingsSystem._NAME, key, default_value)
@staticmethod
def putBoolean(key: str, value: bool) -> bool:
return _SettingsBase.putBoolean(SettingsSystem._NAME, key, value)
@staticmethod
def getBoolean(key: str, default_value: bool = False) -> bool:
return _SettingsBase.getBoolean(SettingsSystem._NAME, key, default_value)
class SettingsSecure(_SettingsBase):
_NAME = "settings_secure"
@@ -180,6 +207,14 @@ class SettingsSecure(_SettingsBase):
def getLong(key: str, default_value: int = 0) -> int:
return _SettingsBase.getLong(SettingsSecure._NAME, key, default_value)
@staticmethod
def putBoolean(key: str, value: bool) -> bool:
return _SettingsBase.putBoolean(SettingsSecure._NAME, key, value)
@staticmethod
def getBoolean(key: str, default_value: bool = False) -> bool:
return _SettingsBase.getBoolean(SettingsSecure._NAME, key, default_value)
class SettingsGlobal(_SettingsBase):
_NAME = "settings_global"
@@ -216,6 +251,14 @@ class SettingsGlobal(_SettingsBase):
def getLong(key: str, default_value: int = 0) -> int:
return _SettingsBase.getLong(SettingsGlobal._NAME, key, default_value)
@staticmethod
def putBoolean(key: str, value: bool) -> bool:
return _SettingsBase.putBoolean(SettingsGlobal._NAME, key, value)
@staticmethod
def getBoolean(key: str, default_value: bool = False) -> bool:
return _SettingsBase.getBoolean(SettingsGlobal._NAME, key, default_value)
class Settings(Stub):
"""Settings — 系统设置"""
@@ -236,6 +279,10 @@ class Settings(Stub):
class MediaStore(Stub):
"""MediaStore — 媒体存储"""
VOLUME_INTERNAL = "internal"
VOLUME_EXTERNAL = "external"
VOLUME_EXTERNAL_PRIMARY = "external_primary"
class MediaColumns(Stub):
_ID = 0
DATA = 1
@@ -259,16 +306,35 @@ class MediaStore(Stub):
EXTERNAL_CONTENT_URI = "content://media/external/images/media"
INTERNAL_CONTENT_URI = "content://media/internal/images/media"
@staticmethod
def getContentUri(volume_name: str) -> str:
return f"content://media/{volume_name}/images/media"
class Thumbnails(Stub):
EXTERNAL_CONTENT_URI = "content://media/external/images/thumbnails"
class Video(Stub):
class Media(Stub):
EXTERNAL_CONTENT_URI = "content://media/external/video/media"
INTERNAL_CONTENT_URI = "content://media/internal/video/media"
@staticmethod
def getContentUri(volume_name: str) -> str:
return f"content://media/{volume_name}/video/media"
class Audio(Stub):
class Media(Stub):
EXTERNAL_CONTENT_URI = "content://media/external/audio/media"
INTERNAL_CONTENT_URI = "content://media/internal/audio/media"
@staticmethod
def getContentUri(volume_name: str) -> str:
return f"content://media/{volume_name}/audio/media"
@staticmethod
def getMediaUri(volume_name: str) -> str:
"""返回指定卷的媒体 URI。"""
return f"content://media/{volume_name}"
@staticmethod
def getVersion(context: Any, uri: str) -> str:
@@ -337,22 +403,94 @@ class DocumentsContract(Stub):
class ContactsContract(Stub):
"""ContactsContract — 联系人合约"""
AUTHORITY = "com.android.contacts"
class Contacts(Stub):
CONTENT_URI = "content://com.android.contacts/contacts"
CONTENT_FILTER_URI = "content://com.android.contacts/contacts/filter"
CONTENT_TYPE = "vnd.android.cursor.dir/contact"
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact"
DISPLAY_NAME = "display_name"
PHOTO_URI = "photo_uri"
PHOTO_ID = "photo_id"
_ID = "_id"
HAS_PHONE_NUMBER = "has_phone_number"
LOOKUP_KEY = "lookup"
STARRED = "starred"
class CommonDataKinds(Stub):
class Email(Stub):
CONTENT_URI = "content://com.android.contacts/data/emails"
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2"
ADDRESS = "data1"
DISPLAY_NAME = "display_name"
TYPE = "data2"
TYPE_HOME = 1
TYPE_WORK = 2
TYPE_OTHER = 3
TYPE_MOBILE = 4
class Phone(Stub):
CONTENT_URI = "content://com.android.contacts/data/phones"
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2"
NUMBER = "data1"
DISPLAY_NAME = "display_name"
TYPE = "data2"
TYPE_HOME = 1
TYPE_MOBILE = 2
TYPE_WORK = 3
TYPE_FAX_WORK = 4
TYPE_FAX_HOME = 5
TYPE_PAGER = 6
TYPE_OTHER = 7
TYPE_CALLBACK = 8
TYPE_CAR = 9
TYPE_COMPANY_MAIN = 10
TYPE_ISDN = 11
TYPE_MAIN = 12
TYPE_OTHER_FAX = 13
TYPE_RADIO = 14
TYPE_TELEX = 15
TYPE_TTY_TDD = 16
TYPE_WORK_MOBILE = 17
TYPE_WORK_PAGER = 18
TYPE_ASSISTANT = 19
class StructuredName(Stub):
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name"
DISPLAY_NAME = "data1"
GIVEN_NAME = "data2"
FAMILY_NAME = "data3"
PREFIX = "data4"
MIDDLE_NAME = "data5"
SUFFIX = "data6"
class Organization(Stub):
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization"
COMPANY = "data1"
TYPE = "data2"
TITLE = "data4"
TYPE_WORK = 1
TYPE_OTHER = 2
class Data(Stub):
CONTENT_URI = "content://com.android.contacts/data"
CONTENT_TYPE = "vnd.android.cursor.dir/data"
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/data"
MIMETYPE = "mimetype"
_ID = "_id"
DISPLAY_NAME = "display_name"
RAW_CONTACT_ID = "raw_contact_id"
CONTACT_ID = "contact_id"
class RawContacts(Stub):
CONTENT_URI = "content://com.android.contacts/raw_contacts"
CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact"
CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact"
_ID = "_id"
CONTACT_ID = "contact_id"
ACCOUNT_NAME = "account_name"
ACCOUNT_TYPE = "account_type"
class ContactsContractContacts(ContactsContract.Contacts):