feat: Linux 真实实现层 — 从存根库变为可用生产力工具

新增 _linux_impl.py (800+行):
- LinuxNetwork: 真实IP/接口/DNS/网关/MAC (ip命令+/proc/net)
- LinuxBluetooth: 真实蓝牙状态/扫描/配对/连接 (bluetoothctl)
- LinuxSensors: 真实温度/CPU频率/风扇 (/sys/class/hwmon)
- LinuxAudio: 真实音量控制/静音 (amixer)
- LinuxClipboard: 真实剪贴板读写 (xclip+tkinter回退)
- LinuxPower: 真实CPU/内存/电池 (psutil+/sys/class/power_supply)
- LinuxLocation: 真实IP地理定位 (ip-api.com)
- LinuxNotify: 真实桌面通知 (notify-send)
- LinuxDisplay: 真实屏幕尺寸/截屏/鼠标位置 (xdotool+X11)
- LinuxUIAutomation: 真实点击/输入/按键/滚动 (xdotool)
- LinuxCamera: 真实摄像头拍照 (opencv/V4L2)
- LinuxProcess: 真实进程列表/系统信息/应用管理 (psutil+/proc)
- LinuxShell: 真实命令执行 (subprocess)

改造10+核心类使用Linux真实实现:
- BluetoothAdapter/SensorManager/AudioManager
- ConnectivityManager/WifiManager/TelephonyManager
- LocationManager/PowerManager/BatteryManager/Build
- ActivityManager/Activity/Toast/Display/ClipboardManager
- NotificationManager

15项真实行为测试全部通过:
- 真实IP: 10.60.218.244
- 真实位置: 北京 39.9042, 116.407
- 真实主机名: work-41-vci-g427c
- 真实内核: 5.15.120.byteatom-ck.14
- 真实内存: 1.8GB/3.8GB
- 真实进程列表
This commit is contained in:
shuiyu1123 committed 2026-06-24 15:40:49 +00:00
1 parent 8c3bd3c415
commit 690022cea3
17 files changed
+2083 -8

No files matched your search

+74 -1
View File
@@ -18,6 +18,13 @@ from .._core import Stub, AndroidOnlyError, _app_data_dir
from ..java.lang import RuntimeException
# Linux 真实实现导入
try:
from .._linux_impl import IS_LINUX, LinuxPower, LinuxProcess, HAS_PSUTIL as _HAS_PSUTIL
_USE_LINUX = IS_LINUX
except ImportError:
_USE_LINUX = False
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
@@ -505,6 +512,54 @@ class BatteryManager(Stub):
self._discharge_time_remaining = -1
self._is_capacity_estimated = False
self._capacity_percentage = 100.0
if _USE_LINUX:
self._refresh_from_linux()
_LINUX_STATUS_MAP = {
"charging": BATTERY_STATUS_CHARGING,
"discharging": BATTERY_STATUS_DISCHARGING,
"not charging": BATTERY_STATUS_NOT_CHARGING,
"full": BATTERY_STATUS_FULL,
"unknown": BATTERY_STATUS_UNKNOWN,
}
def _get_linux_battery_info(self) -> dict:
"""从 LinuxPower 获取真实电池信息"""
try:
return LinuxPower.get_battery_info() or {}
except Exception:
return {}
def _refresh_from_linux(self):
"""用 Linux 真实电池信息刷新内部状态"""
info = self._get_linux_battery_info()
if not info:
return
self._present = bool(info.get("present", False))
level = info.get("level", -1)
if self._present and isinstance(level, (int, float)) and level >= 0:
self._battery_level = int(level)
self._capacity_percentage = float(level)
# BATTERY_PROPERTY_CAPACITY 在 Android 中返回百分比 (0-100)
self._capacity = int(level)
else:
# 无电池或电量未知
self._battery_level = -1
self._capacity_percentage = 0.0
self._capacity = -1
status_str = str(info.get("status", "unknown")).lower()
self._status = self._LINUX_STATUS_MAP.get(status_str, BATTERY_STATUS_UNKNOWN)
voltage = info.get("voltage", 0)
if isinstance(voltage, (int, float)):
self._voltage = int(voltage * 1000) # V -> mV
temperature = info.get("temperature", 0)
if isinstance(temperature, (int, float)):
self._temperature = temperature # 摄氏度
self._technology = info.get("technology", "") or "Li-ion"
if self._status == BATTERY_STATUS_CHARGING:
self._plugged = BATTERY_PLUGGED_AC
else:
self._plugged = 0
@staticmethod
def getInstance(context: Any) -> "BatteryManager":
@@ -513,6 +568,8 @@ class BatteryManager(Stub):
return BatteryManager._instance
def getIntProperty(self, id: int) -> int:
if _USE_LINUX:
self._refresh_from_linux()
properties = {
BATTERY_PROPERTY_CAPACITY: self._capacity,
BATTERY_PROPERTY_CHARGE_COUNTER: self._charge_counter,
@@ -521,6 +578,9 @@ class BatteryManager(Stub):
BATTERY_PROPERTY_ENERGY_COUNTER: self._energy_counter,
BATTERY_PROPERTY_CHARGE_TIME_REMAINING: self._charge_time_remaining,
BATTERY_PROPERTY_DISCHARGE_TIME_REMAINING: self._discharge_time_remaining,
BATTERY_PROPERTY_STATUS: self._status,
BATTERY_PROPERTY_TEMPERATURE: int(self._temperature),
BATTERY_PROPERTY_VOLTAGE: self._voltage,
}
return properties.get(id, 0)
@@ -528,9 +588,13 @@ class BatteryManager(Stub):
return self.getIntProperty(id)
def isCharging(self) -> bool:
if _USE_LINUX:
self._refresh_from_linux()
return self._status == BATTERY_STATUS_CHARGING or self._status == BATTERY_STATUS_FULL
def getBatteryLevel(self) -> int:
if _USE_LINUX:
self._refresh_from_linux()
return self._battery_level
def getInt(intent: Any, key: str, defaultValue: int) -> int:
@@ -687,9 +751,11 @@ class PowerManager(Stub):
self._shutdown_requested = False
self._thermal_status = THERMAL_STATUS_NONE
self._power_save_state = PowerSaveState()
self._current_wake_up_reason = WAKE_REASON_UNKNOWN
self._current_wake_up_reason = PowerManager.WAKE_REASON_UNKNOWN
def isInteractive(self) -> bool:
if _USE_LINUX:
return self.isScreenOn()
return self._is_interactive
def isPowerSaveMode(self) -> bool:
@@ -705,6 +771,13 @@ class PowerManager(Stub):
return True
def isScreenOn(self) -> bool:
if _USE_LINUX:
import os as _os_mod
display = _os_mod.environ.get("DISPLAY", "")
if display:
return True
wayland = _os_mod.environ.get("WAYLAND_DISPLAY", "")
return bool(wayland)
return self._is_screen_on
def isWakeLockLevelSupported(self, level: int) -> bool: