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:
1 parent
39b1da37c9
commit
4235f8692c
13 files changed
+2248
-163
No files matched your search
@@ -620,6 +620,9 @@ class GnssStatus(Stub):
|
||||
return 0.0
|
||||
|
||||
def getBasebandCn0DbHz(self, index: int) -> float:
|
||||
"""返回指定卫星的基带载噪比(dB-Hz)。"""
|
||||
if 0 <= index < len(self._satellites):
|
||||
return self._satellites[index].get("baseband_cn0", 0.0)
|
||||
return 0.0
|
||||
|
||||
def getCn0DbHz(self, index: int) -> float:
|
||||
@@ -873,6 +876,42 @@ class Address(Stub):
|
||||
def setFeatureName(self, name: str):
|
||||
self._feature_name = name
|
||||
|
||||
def setAdminArea(self, area: str):
|
||||
self._admin_area = area
|
||||
|
||||
def setSubAdminArea(self, area: str):
|
||||
self._sub_admin_area = area
|
||||
|
||||
def setLocality(self, locality: str):
|
||||
self._locality = locality
|
||||
|
||||
def setSubLocality(self, sub_locality: str):
|
||||
self._sub_locality = sub_locality
|
||||
|
||||
def setPremises(self, premises: str):
|
||||
self._premises = premises
|
||||
|
||||
def setThoroughfare(self, thoroughfare: str):
|
||||
self._thoroughfare = thoroughfare
|
||||
|
||||
def setSubThoroughfare(self, sub_thoroughfare: str):
|
||||
self._sub_thoroughfare = sub_thoroughfare
|
||||
|
||||
def setPostalCode(self, postal_code: str):
|
||||
self._postal_code = postal_code
|
||||
|
||||
def setCountryName(self, country_name: str):
|
||||
self._country_name = country_name
|
||||
|
||||
def setCountryCode(self, country_code: str):
|
||||
self._country_code = country_code
|
||||
|
||||
def setPhone(self, phone: str):
|
||||
self._phone = phone
|
||||
|
||||
def setUrl(self, url: str):
|
||||
self._url = url
|
||||
|
||||
def setLatitude(self, latitude: float):
|
||||
self._latitude = latitude
|
||||
self._has_lat_lon = True
|
||||
@@ -898,29 +937,144 @@ class Address(Stub):
|
||||
class Geocoder(Stub):
|
||||
"""Geocoder — 地理编码/逆地理编码"""
|
||||
|
||||
# Nominatim (OpenStreetMap) 免费 API
|
||||
_NOMINATIM_URL = "https://nominatim.openstreetmap.org"
|
||||
_USER_AGENT = "Android-pyApi/1.0"
|
||||
|
||||
def __init__(self, context: Any = None, locale: Any = None):
|
||||
super().__init__()
|
||||
self._context = context
|
||||
self._locale = locale
|
||||
|
||||
def _get_locale_str(self) -> str:
|
||||
if self._locale is None:
|
||||
return "en"
|
||||
if hasattr(self._locale, "getLanguage"):
|
||||
lang = self._locale.getLanguage()
|
||||
country = self._locale.getCountry()
|
||||
return f"{lang}-{country}" if country else lang
|
||||
return str(self._locale)
|
||||
|
||||
@staticmethod
|
||||
def _http_get_json(url: str) -> Optional[Any]:
|
||||
"""使用 urllib 发送 GET 请求并解析 JSON。"""
|
||||
try:
|
||||
import urllib.request
|
||||
import json
|
||||
req = urllib.request.Request(url, headers={
|
||||
"User-Agent": Geocoder._USER_AGENT,
|
||||
"Accept-Language": "en",
|
||||
})
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def getFromLocation(self, latitude: float, longitude: float,
|
||||
max_results: int = 1) -> List[Address]:
|
||||
"""逆地理编码:根据经纬度获取地址。优先使用 Nominatim API。"""
|
||||
results: List[Address] = []
|
||||
# 尝试在线逆地理编码
|
||||
try:
|
||||
url = (f"{self._NOMINATIM_URL}/reverse?"
|
||||
f"lat={latitude}&lon={longitude}&format=jsonv2"
|
||||
f"&addressdetails=1&limit={max_results}")
|
||||
data = self._http_get_json(url)
|
||||
if data and isinstance(data, dict) and "address" in data:
|
||||
addr = self._parse_nominatim_reverse(data)
|
||||
results.append(addr)
|
||||
except Exception:
|
||||
pass
|
||||
# 回退到默认地址
|
||||
if not results:
|
||||
addr = Address()
|
||||
addr.setLatitude(latitude)
|
||||
addr.setLongitude(longitude)
|
||||
addr.setFeatureName("Unknown Location")
|
||||
addr.setLocality("Unknown")
|
||||
addr.setCountryName("Unknown")
|
||||
results.append(addr)
|
||||
return results[:max_results] if max_results > 0 else []
|
||||
|
||||
def _parse_nominatim_reverse(self, data: dict) -> Address:
|
||||
"""解析 Nominatim 逆地理编码响应。"""
|
||||
addr = Address()
|
||||
addr.setLatitude(latitude)
|
||||
addr.setLongitude(longitude)
|
||||
addr.setFeatureName("Unknown Location")
|
||||
addr.setLocality("Unknown")
|
||||
addr.setCountryName("Unknown")
|
||||
return [addr] if max_results > 0 else []
|
||||
address = data.get("address", {})
|
||||
lat = data.get("lat")
|
||||
lon = data.get("lon")
|
||||
if lat is not None:
|
||||
addr.setLatitude(float(lat))
|
||||
if lon is not None:
|
||||
addr.setLongitude(float(lon))
|
||||
addr.setFeatureName(address.get("road") or address.get("building")
|
||||
or data.get("name") or "Unknown")
|
||||
addr.setLocality(address.get("city") or address.get("town")
|
||||
or address.get("village") or address.get("county") or "Unknown")
|
||||
addr.setAdminArea(address.get("state") or "")
|
||||
addr.setSubAdminArea(address.get("state_district") or "")
|
||||
addr.setCountryName(address.get("country") or "Unknown")
|
||||
addr.setCountryCode(address.get("country_code", "").upper())
|
||||
addr.setPostalCode(address.get("postcode") or "")
|
||||
addr.setAddressLine(0, data.get("display_name", ""))
|
||||
return addr
|
||||
|
||||
def getFromLocationName(self, location_name: str, max_results: int = 1,
|
||||
lower_left_lat: Optional[float] = None,
|
||||
lower_left_lon: Optional[float] = None,
|
||||
upper_right_lat: Optional[float] = None,
|
||||
upper_right_lon: Optional[float] = None) -> List[Address]:
|
||||
"""地理编码:根据地名获取经纬度。优先使用 Nominatim API。"""
|
||||
results: List[Address] = []
|
||||
# 尝试在线地理编码
|
||||
try:
|
||||
import urllib.parse
|
||||
params = {
|
||||
"q": location_name,
|
||||
"format": "jsonv2",
|
||||
"addressdetails": "1",
|
||||
"limit": str(max_results),
|
||||
}
|
||||
# 添加边界框
|
||||
if all(v is not None for v in (lower_left_lat, lower_left_lon,
|
||||
upper_right_lat, upper_right_lon)):
|
||||
params["viewbox"] = f"{lower_left_lon},{upper_right_lat},{upper_right_lon},{lower_left_lat}"
|
||||
params["bounded"] = "1"
|
||||
query = urllib.parse.urlencode(params)
|
||||
url = f"{self._NOMINATIM_URL}/search?{query}"
|
||||
data = self._http_get_json(url)
|
||||
if data and isinstance(data, list):
|
||||
for item in data[:max_results]:
|
||||
addr = self._parse_nominatim_search(item)
|
||||
results.append(addr)
|
||||
except Exception:
|
||||
pass
|
||||
# 回退到默认地址
|
||||
if not results:
|
||||
addr = Address()
|
||||
addr.setFeatureName(location_name)
|
||||
addr.setLocality(location_name)
|
||||
results.append(addr)
|
||||
return results[:max_results] if max_results > 0 else []
|
||||
|
||||
def _parse_nominatim_search(self, item: dict) -> Address:
|
||||
"""解析 Nominatim 搜索响应。"""
|
||||
addr = Address()
|
||||
addr.setFeatureName(location_name)
|
||||
addr.setLocality(location_name)
|
||||
return [addr] if max_results > 0 else []
|
||||
lat = item.get("lat")
|
||||
lon = item.get("lon")
|
||||
if lat is not None:
|
||||
addr.setLatitude(float(lat))
|
||||
if lon is not None:
|
||||
addr.setLongitude(float(lon))
|
||||
address = item.get("address", {})
|
||||
addr.setFeatureName(item.get("name") or address.get("road") or "Unknown")
|
||||
addr.setLocality(address.get("city") or address.get("town")
|
||||
or address.get("village") or address.get("county") or "Unknown")
|
||||
addr.setAdminArea(address.get("state") or "")
|
||||
addr.setCountryName(address.get("country") or "Unknown")
|
||||
addr.setCountryCode(address.get("country_code", "").upper())
|
||||
addr.setPostalCode(address.get("postcode") or "")
|
||||
addr.setAddressLine(0, item.get("display_name", ""))
|
||||
return addr
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
@@ -956,6 +1110,9 @@ class LocationManager(Stub):
|
||||
self._last_known_locations: Dict[str, Location] = {}
|
||||
self._enabled_providers = {self.GPS_PROVIDER, self.NETWORK_PROVIDER,
|
||||
self.PASSIVE_PROVIDER, self.FUSED_PROVIDER}
|
||||
self._test_providers: Dict[str, LocationProvider] = {}
|
||||
self._test_locations: Dict[str, Location] = {}
|
||||
self._proximity_alerts: List[Dict[str, Any]] = []
|
||||
|
||||
def getLastKnownLocation(self, provider: str) -> Optional[Location]:
|
||||
if _USE_LINUX:
|
||||
@@ -1036,19 +1193,42 @@ class LocationManager(Stub):
|
||||
|
||||
def addProximityAlert(self, latitude: float, longitude: float,
|
||||
radius: float, expiration: int, intent: Any):
|
||||
pass
|
||||
"""添加接近警报。记录警报信息,在位置更新时检查是否进入/离开区域。"""
|
||||
import time as _time
|
||||
alert = {
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
"radius": radius,
|
||||
"expiration": expiration,
|
||||
"intent": intent,
|
||||
"created_at": _time.time(),
|
||||
"last_state": None, # None=未触发, True=在区域内, False=在区域外
|
||||
}
|
||||
self._proximity_alerts.append(alert)
|
||||
|
||||
def sendExtraCommand(self, provider: str, command: str, extras: Any) -> bool:
|
||||
"""向位置提供者发送额外命令。桌面端无实际效果,返回成功。"""
|
||||
return True
|
||||
|
||||
def clearTestProviderLocation(self, provider: str):
|
||||
pass
|
||||
"""清除测试提供者的位置数据。"""
|
||||
self._test_locations.pop(provider, None)
|
||||
|
||||
def setTestProviderLocation(self, provider: str, location: Location):
|
||||
pass
|
||||
"""设置测试提供者的位置。"""
|
||||
self._test_locations[provider] = location
|
||||
# 通知该提供者的监听器
|
||||
if provider in self._listeners:
|
||||
for listener in self._listeners[provider]:
|
||||
try:
|
||||
listener.onLocationChanged(location)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def removeTestProvider(self, provider: str):
|
||||
pass
|
||||
"""移除测试提供者。"""
|
||||
self._test_providers.pop(provider, None)
|
||||
self._test_locations.pop(provider, None)
|
||||
|
||||
def addTestProvider(self, name: str, requires_network: bool, requires_satellite: bool,
|
||||
requires_cell: bool, has_monetary_cost: bool, supports_altitude: bool,
|
||||
|
||||
Reference in new issue
Block a user