feat: 大规模扩充至212个模块/175K行代码 — 覆盖android/java/javax/org/dalvik全包
- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
This commit is contained in:
1 parent
506f9ac725
commit
a51854455b
128 files changed
+100571
-3
No files matched your search
@@ -0,0 +1,544 @@
|
||||
"""
|
||||
Java java.util.prefs standard library APIs implemented in Python.
|
||||
java.util.prefs package - Preferences, PreferencesFactory, etc.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .._core import Stub
|
||||
from ..java.lang import RuntimeException, Exception as _JavaException
|
||||
import typing as _typing
|
||||
import json as _json
|
||||
import os as _os
|
||||
import threading as _threading
|
||||
|
||||
__all__ = [
|
||||
"Preferences", "PreferencesFactory", "AbstractPreferences",
|
||||
"NodeChangeEvent", "NodeChangeListener",
|
||||
"PreferenceChangeEvent", "PreferenceChangeListener",
|
||||
"BackingStoreException", "InvalidPreferencesFormatException",
|
||||
]
|
||||
|
||||
# ============================================================
|
||||
# Exceptions
|
||||
# ============================================================
|
||||
|
||||
class BackingStoreException(_JavaException):
|
||||
"""java.util.prefs.BackingStoreException"""
|
||||
def __init__(self, message):
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
class InvalidPreferencesFormatException(_JavaException):
|
||||
"""java.util.prefs.InvalidPreferencesFormatException"""
|
||||
def __init__(self, message, cause=None):
|
||||
super().__init__(message)
|
||||
self._cause = cause
|
||||
|
||||
def getCause(self):
|
||||
return self._cause
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Event Classes
|
||||
# ============================================================
|
||||
|
||||
class NodeChangeEvent(Stub):
|
||||
"""java.util.prefs.NodeChangeEvent"""
|
||||
def __init__(self, parent, child):
|
||||
super().__init__()
|
||||
self._parent = parent
|
||||
self._child = child
|
||||
|
||||
def getParent(self):
|
||||
return self._parent
|
||||
|
||||
def getChild(self):
|
||||
return self._child
|
||||
|
||||
|
||||
class PreferenceChangeEvent(Stub):
|
||||
"""java.util.prefs.PreferenceChangeEvent"""
|
||||
def __init__(self, node, key, new_value):
|
||||
super().__init__()
|
||||
self._node = node
|
||||
self._key = key
|
||||
self._new_value = new_value
|
||||
|
||||
def getNode(self):
|
||||
return self._node
|
||||
|
||||
def getKey(self):
|
||||
return self._key
|
||||
|
||||
def getNewValue(self):
|
||||
return self._new_value
|
||||
|
||||
|
||||
class NodeChangeListener(Stub):
|
||||
"""java.util.prefs.NodeChangeListener"""
|
||||
def childAdded(self, evt):
|
||||
pass
|
||||
|
||||
def childRemoved(self, evt):
|
||||
pass
|
||||
|
||||
|
||||
class PreferenceChangeListener(Stub):
|
||||
"""java.util.prefs.PreferenceChangeListener"""
|
||||
def preferenceChange(self, evt):
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Preferences
|
||||
# ============================================================
|
||||
|
||||
class Preferences(Stub):
|
||||
"""java.util.prefs.Preferences"""
|
||||
MAX_KEY_LENGTH = 80
|
||||
MAX_VALUE_LENGTH = 8192
|
||||
MAX_NAME_LENGTH = 80
|
||||
|
||||
def __init__(self, name="", parent=None):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
self._parent = parent
|
||||
self._children = {}
|
||||
self._prefs = {}
|
||||
self._node_listeners = []
|
||||
self._pref_listeners = []
|
||||
self._absolute_path = self._build_path()
|
||||
|
||||
def _build_path(self):
|
||||
if self._parent is None:
|
||||
return "/" + self._name if self._name else "/"
|
||||
parent_path = self._parent._absolute_path
|
||||
if parent_path == "/":
|
||||
return "/" + self._name
|
||||
return parent_path + "/" + self._name
|
||||
|
||||
def put(self, key, value):
|
||||
if len(key) > Preferences.MAX_KEY_LENGTH:
|
||||
raise IllegalArgumentException(f"Key too long: {len(key)}")
|
||||
if len(value) > Preferences.MAX_VALUE_LENGTH:
|
||||
raise IllegalArgumentException(f"Value too long: {len(value)}")
|
||||
self._prefs[key] = value
|
||||
self._fire_preference_change(key, value)
|
||||
|
||||
def get(self, key, default_value):
|
||||
return self._prefs.get(key, default_value)
|
||||
|
||||
def remove(self, key):
|
||||
if key in self._prefs:
|
||||
old = self._prefs.pop(key)
|
||||
self._fire_preference_change(key, None)
|
||||
|
||||
def clear(self):
|
||||
self._prefs.clear()
|
||||
|
||||
def putInt(self, key, value):
|
||||
self.put(key, str(value))
|
||||
|
||||
def getInt(self, key, default_value):
|
||||
val = self.get(key, None)
|
||||
if val is None:
|
||||
return default_value
|
||||
try:
|
||||
return int(val)
|
||||
except ValueError:
|
||||
return default_value
|
||||
|
||||
def putLong(self, key, value):
|
||||
self.put(key, str(value))
|
||||
|
||||
def getLong(self, key, default_value):
|
||||
val = self.get(key, None)
|
||||
if val is None:
|
||||
return default_value
|
||||
try:
|
||||
return int(val)
|
||||
except ValueError:
|
||||
return default_value
|
||||
|
||||
def putFloat(self, key, value):
|
||||
self.put(key, str(value))
|
||||
|
||||
def getFloat(self, key, default_value):
|
||||
val = self.get(key, None)
|
||||
if val is None:
|
||||
return default_value
|
||||
try:
|
||||
return float(val)
|
||||
except ValueError:
|
||||
return default_value
|
||||
|
||||
def putDouble(self, key, value):
|
||||
self.put(key, str(value))
|
||||
|
||||
def getDouble(self, key, default_value):
|
||||
val = self.get(key, None)
|
||||
if val is None:
|
||||
return default_value
|
||||
try:
|
||||
return float(val)
|
||||
except ValueError:
|
||||
return default_value
|
||||
|
||||
def putBoolean(self, key, value):
|
||||
self.put(key, "true" if value else "false")
|
||||
|
||||
def getBoolean(self, key, default_value):
|
||||
val = self.get(key, None)
|
||||
if val is None:
|
||||
return default_value
|
||||
return val.lower() == "true"
|
||||
|
||||
def putByteArray(self, key, value):
|
||||
import base64
|
||||
self.put(key, base64.b64encode(value).decode())
|
||||
|
||||
def getByteArray(self, key, default_value):
|
||||
import base64
|
||||
val = self.get(key, None)
|
||||
if val is None:
|
||||
return default_value
|
||||
try:
|
||||
return base64.b64decode(val)
|
||||
except Exception:
|
||||
return default_value
|
||||
|
||||
def keys(self):
|
||||
return list(self._prefs.keys())
|
||||
|
||||
def childrenNames(self):
|
||||
return list(self._children.keys())
|
||||
|
||||
def parent(self):
|
||||
return self._parent
|
||||
|
||||
def node(self, path_name):
|
||||
if path_name.startswith("/"):
|
||||
return self._root()._node_path(path_name[1:])
|
||||
return self._node_path(path_name)
|
||||
|
||||
def nodeExists(self, path_name):
|
||||
try:
|
||||
self.node(path_name)
|
||||
return True
|
||||
except BackingStoreException:
|
||||
return False
|
||||
|
||||
def removeNode(self):
|
||||
if self._parent is not None:
|
||||
self._parent._remove_child(self._name)
|
||||
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def absolutePath(self):
|
||||
return self._absolute_path
|
||||
|
||||
def isUserNode(self):
|
||||
return False
|
||||
|
||||
def toString(self):
|
||||
return self._absolute_path
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def sync(self):
|
||||
pass
|
||||
|
||||
def addNodeChangeListener(self, listener):
|
||||
self._node_listeners.append(listener)
|
||||
|
||||
def removeNodeChangeListener(self, listener):
|
||||
if listener in self._node_listeners:
|
||||
self._node_listeners.remove(listener)
|
||||
|
||||
def addPreferenceChangeListener(self, listener):
|
||||
self._pref_listeners.append(listener)
|
||||
|
||||
def removePreferenceChangeListener(self, listener):
|
||||
if listener in self._pref_listeners:
|
||||
self._pref_listeners.remove(listener)
|
||||
|
||||
def exportNode(self, output_stream):
|
||||
data = self._to_dict()
|
||||
output_stream.write(_json.dumps(data, indent=2).encode())
|
||||
|
||||
def exportSubtree(self, output_stream):
|
||||
data = self._to_dict(recursive=True)
|
||||
output_stream.write(_json.dumps(data, indent=2).encode())
|
||||
|
||||
def _to_dict(self, recursive=False):
|
||||
result = {"prefs": dict(self._prefs)}
|
||||
if recursive:
|
||||
result["children"] = {
|
||||
name: child._to_dict(recursive=True)
|
||||
for name, child in self._children.items()
|
||||
}
|
||||
return result
|
||||
|
||||
def _root(self):
|
||||
if self._parent is None:
|
||||
return self
|
||||
return self._parent._root()
|
||||
|
||||
def _node_path(self, path):
|
||||
if not path:
|
||||
return self
|
||||
parts = path.split("/")
|
||||
current = self
|
||||
for part in parts:
|
||||
if not part:
|
||||
continue
|
||||
if part == "..":
|
||||
if current._parent is not None:
|
||||
current = current._parent
|
||||
continue
|
||||
if part not in current._children:
|
||||
current._children[part] = Preferences(part, current)
|
||||
current = current._children[part]
|
||||
return current
|
||||
|
||||
def _remove_child(self, name):
|
||||
if name in self._children:
|
||||
child = self._children.pop(name)
|
||||
evt = NodeChangeEvent(self, child)
|
||||
for listener in self._node_listeners:
|
||||
listener.childRemoved(evt)
|
||||
|
||||
def _fire_preference_change(self, key, value):
|
||||
evt = PreferenceChangeEvent(self, key, value)
|
||||
for listener in self._pref_listeners:
|
||||
listener.preferenceChange(evt)
|
||||
|
||||
@staticmethod
|
||||
def userRoot():
|
||||
if Preferences._user_root is None:
|
||||
Preferences._user_root = Preferences("")
|
||||
return Preferences._user_root
|
||||
|
||||
@staticmethod
|
||||
def systemRoot():
|
||||
if Preferences._system_root is None:
|
||||
Preferences._system_root = Preferences("")
|
||||
return Preferences._system_root
|
||||
|
||||
@staticmethod
|
||||
def importPreferences(input_stream):
|
||||
data = _json.loads(input_stream.read())
|
||||
root = Preferences("")
|
||||
root._prefs = data.get("prefs", {})
|
||||
return root
|
||||
|
||||
_user_root = None
|
||||
_system_root = None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AbstractPreferences
|
||||
# ============================================================
|
||||
|
||||
class AbstractPreferences(Preferences):
|
||||
"""java.util.prefs.AbstractPreferences"""
|
||||
def __init__(self, parent, name):
|
||||
super().__init__(name, parent)
|
||||
self._is_removed = False
|
||||
self._lock = _threading.RLock()
|
||||
|
||||
def put(self, key, value):
|
||||
with self._lock:
|
||||
if self._is_removed:
|
||||
raise BackingStoreException("Node has been removed")
|
||||
super().put(key, value)
|
||||
|
||||
def get(self, key, default_value):
|
||||
with self._lock:
|
||||
if self._is_removed:
|
||||
raise BackingStoreException("Node has been removed")
|
||||
return super().get(key, default_value)
|
||||
|
||||
def remove(self, key):
|
||||
with self._lock:
|
||||
super().remove(key)
|
||||
|
||||
def keys(self):
|
||||
with self._lock:
|
||||
return super().keys()
|
||||
|
||||
def childrenNames(self):
|
||||
with self._lock:
|
||||
return super().childrenNames()
|
||||
|
||||
def node(self, path_name):
|
||||
with self._lock:
|
||||
return super().node(path_name)
|
||||
|
||||
def removeNode(self):
|
||||
with self._lock:
|
||||
super().removeNode()
|
||||
self._is_removed = True
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def sync(self):
|
||||
pass
|
||||
|
||||
def isUserNode(self):
|
||||
return False
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PreferencesFactory
|
||||
# ============================================================
|
||||
|
||||
class PreferencesFactory(Stub):
|
||||
"""java.util.prefs.PreferencesFactory"""
|
||||
def systemRoot(self):
|
||||
return Preferences.systemRoot()
|
||||
|
||||
def userRoot(self):
|
||||
return Preferences.userRoot()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IllegalArgumentException
|
||||
# ============================================================
|
||||
|
||||
class IllegalArgumentException(RuntimeException):
|
||||
"""java.lang.IllegalArgumentException"""
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Preferences utility helpers
|
||||
# ============================================================
|
||||
|
||||
class _PreferencesService(Stub):
|
||||
"""Helper to manage Preferences with file-backed storage"""
|
||||
def __init__(self, root_path=None):
|
||||
super().__init__()
|
||||
if root_path is None:
|
||||
import os
|
||||
root_path = os.path.join(os.path.expanduser("~"), ".java", "prefs")
|
||||
self._root_path = root_path
|
||||
self._cache = {}
|
||||
|
||||
def loadPreferences(self, node_path):
|
||||
import os
|
||||
import json
|
||||
file_path = os.path.join(self._root_path, node_path.replace("/", "_") + ".json")
|
||||
prefs = Preferences(node_path)
|
||||
if os.path.exists(file_path):
|
||||
try:
|
||||
with open(file_path, "r") as f:
|
||||
data = json.load(f)
|
||||
for key, val in data.items():
|
||||
prefs.put(key, val)
|
||||
except Exception:
|
||||
pass
|
||||
self._cache[node_path] = prefs
|
||||
return prefs
|
||||
|
||||
def savePreferences(self, prefs):
|
||||
import os
|
||||
import json
|
||||
file_path = os.path.join(self._root_path,
|
||||
prefs.absolutePath().replace("/", "_") + ".json")
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
data = {}
|
||||
for key in prefs.keys():
|
||||
data[key] = prefs.get(key, None)
|
||||
with open(file_path, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
def clearCache(self):
|
||||
self._cache.clear()
|
||||
|
||||
|
||||
class _EventDispatchThread(Stub):
|
||||
"""Helper for dispatching preference change events"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._listeners = []
|
||||
import threading
|
||||
self._lock = threading.Lock()
|
||||
|
||||
def addListener(self, listener):
|
||||
with self._lock:
|
||||
self._listeners.append(listener)
|
||||
|
||||
def removeListener(self, listener):
|
||||
with self._lock:
|
||||
if listener in self._listeners:
|
||||
self._listeners.remove(listener)
|
||||
|
||||
def dispatchEvent(self, event):
|
||||
with self._lock:
|
||||
for listener in self._listeners:
|
||||
try:
|
||||
if hasattr(listener, 'preferenceChange'):
|
||||
listener.preferenceChange(event)
|
||||
elif callable(listener):
|
||||
listener(event)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def getListeners(self):
|
||||
with self._lock:
|
||||
return list(self._listeners)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileSystemPreferences - persistent Preferences backed by file
|
||||
# ============================================================
|
||||
|
||||
class FileSystemPreferences(AbstractPreferences):
|
||||
"""java.util.prefs.FileSystemPreferences - persistent file-backed preferences"""
|
||||
def __init__(self, parent, name, storage_path=None):
|
||||
super().__init__(parent, name)
|
||||
import os
|
||||
if storage_path is None:
|
||||
storage_path = os.path.join(os.path.expanduser("~"), ".java", "user_prefs")
|
||||
self._storage_path = os.path.join(
|
||||
storage_path, self.absolutePath().replace("/", "_") + ".xml"
|
||||
)
|
||||
self._loaded = False
|
||||
self._service = _PreferencesService(storage_path)
|
||||
|
||||
def _ensureLoaded(self):
|
||||
if not self._loaded:
|
||||
try:
|
||||
import os
|
||||
if os.path.exists(self._storage_path):
|
||||
node = self._service.loadPreferences(self.absolutePath())
|
||||
for key in node.keys():
|
||||
self._prefs[key] = node.get(key, "")
|
||||
self._loaded = True
|
||||
except Exception:
|
||||
self._loaded = True
|
||||
|
||||
def put(self, key, value):
|
||||
self._ensureLoaded()
|
||||
super().put(key, value)
|
||||
|
||||
def get(self, key, default_value):
|
||||
self._ensureLoaded()
|
||||
return super().get(key, default_value)
|
||||
|
||||
def keys(self):
|
||||
self._ensureLoaded()
|
||||
return super().keys()
|
||||
|
||||
def flush(self):
|
||||
self._service.savePreferences(self)
|
||||
super().flush()
|
||||
|
||||
def sync(self):
|
||||
self._ensureLoaded()
|
||||
self._service.savePreferences(self)
|
||||
Reference in new issue
Block a user