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:
1 parent
4235f8692c
commit
fbb8263b13
13 files changed
+1373
-146
No files matched your search
@@ -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):
|
||||
|
||||
Reference in new issue
Block a user