ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性

被控端
- 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%)
- 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败)
- 每分钟回头找局域网,自动切回快 400 倍的路径
- 画面心跳帧:静止时省流量,客户端仍知道流是活的
- 锁屏时给出可操作的提示

手表端
- 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException
- 连接错误翻译成人话(证书/时间/解析/超时分别提示)
- 经中转连上后用服务器报的地址刷新已配对记录
- 新增局域网连接页面、服务器延迟检测

服务器端
- 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502)
- 网络调优脚本 net-tune.sh(开机自动应用)
- 管理页:批量删除、网络体检、下载区
- 隧道改 HTTP/2 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
xmz7891
2026-10-06 19:01:05 +08:00
commit b62ac865ea
3195 changed files with 203292 additions and 0 deletions
+207
View File
@@ -0,0 +1,207 @@
# -*- coding: utf-8 -*-
"""手表屏幕适配校验。
分两部分:
1. **真机参数**(来自用户实测的诊断报告)—— 这是最该保证的
2. 一组常见 density 的覆盖,防止别的设备上按钮被挤爆
把 MainActivity.adaptGridToScreen() 的布局计算原样搬过来核算。
注意:这是**布局数学核算**,不是真机渲染测试。
没有可用设备/模拟器时,它能提前发现"screensize 一变按钮就挤爆"这类问题。
"""
from __future__ import annotations
import sys
PANEL_PADDING_DP = 8.0 # controlPanel 左右 padding
CELL_MARGIN_DP = 3.0 # 每个按钮的外边距
BUTTON_PADDING_DP = 4.0 # 按钮内部左右 padding
MIN_TOUCH_DP = 48.0 # Android 无障碍最小点击高度
# 现在手表端分 6 页,每页按钮数不一样。
# 关键指标变成「每一页都能一屏放下、不用滚动」。
# 现在分 10 页:功能页已删除,14 个分组散到各页。
# 括号里只统计**固定快捷按钮**;功能分组是滚动区,会显示在下面。
# 现在分 10 页:功能页已删除,14 个分组散到各页。
# 括号里只统计**固定快捷按钮**;功能分组是滚动区,会显示在下面。
# 每页最多 3 行(9 个),超了会滚动。
TABS = {
"媒体": ["播放/暂停", "停止", "上一曲", "下一曲", "音量 +", "音量 -", "静音"],
"屏幕": ["关掉画面", "屏幕镜像", "截屏", "投图到电脑", "放音到电脑"],
"文件": ["发送文件", "接收文件", "剪贴板→电脑", "取电脑剪贴板"],
"语音": ["语音播报", "音色", "朗读剪贴板", "电脑音乐", "弹通知"],
"电脑": ["快捷命令", "打开网址", "进程管理", "性能", "磁盘", "电量"],
"网络": ["本机监听端口", "确认能连上"],
"系统": ["回退上一步", "回退全部", "看能回退什么",
"锁屏", "睡眠", "关机", "重启", "取消定时关机", "定时关机"],
"教室": ["屏蔽游戏网站", "结束游戏进程", "一键恢复全部", "看有哪些限制"],
"效率": ["加待办", "看所有待办"],
"娱乐": ["掷骰子", "抽奖", "抛硬币"],
}
# 每页还挂着哪些功能分组(这些在滚动区里)
TAB_GROUPS = {
"媒体": ["音量", "媒体"],
"屏幕": ["显示"],
"文件": ["文件"],
"语音": ["静默"],
"电脑": ["查看", "工具"],
"网络": ["网络", "极客"],
"系统": ["系统"],
"教室": ["教室", "教学"],
"效率": ["效率"],
"娱乐": ["娱乐"],
}
LABELS = [label for group in TABS.values() for label in group]
# 用户实测的设备(来自遥控诊断报告)
REAL_DEVICE = {
"name": "M60T (hesc, Android 9 / API 28)",
"width_px": 492,
"height_px": 602,
"density": 1.4125,
"density_dpi": 226,
}
PASSED = 0
FAILED = 0
def check(name: str, ok: bool, detail: str = "") -> None:
global PASSED, FAILED
if ok:
PASSED += 1
print(f" [PASS] {name}")
else:
FAILED += 1
print(f" [FAIL] {name} {detail}")
def adapt(width_dp: float, height_dp: float):
"""与 Java 端 adaptGridToScreen() 一致。"""
if width_dp < 200:
return 1, 64.0, 16.0
if width_dp < 300:
columns, height, text = 2, 60.0, 14.0
elif width_dp < 330:
columns, height, text = 2, 64.0, 15.0
else:
columns, height, text = 3, 58.0, 13.0
if height_dp < 320 and columns == 2:
height = 56.0
return columns, height, text
def label_width_dp(label: str, text_sp: float) -> float:
"""估算文字宽度:中日韩字符约 1em,其余约 0.55em。"""
total = 0.0
for ch in label:
total += 1.0 if ord(ch) > 0x2E80 else 0.55
return total * text_sp
def report_one(tag: str, width_px: float, height_px: float, density: float) -> float:
"""核算一台设备,返回最紧的文字余量。"""
width_dp = width_px / density
height_dp = height_px / density
columns, cell_h, text_sp = adapt(width_dp, height_dp)
content_dp = width_dp - PANEL_PADDING_DP * 2
# 每行 columns 个按钮,每个按钮左右各一个 3dp 外边距
cell_w = (content_dp - CELL_MARGIN_DP * 2 * columns) / columns
text_area = cell_w - BUTTON_PADDING_DP * 2
print(f"\n{tag}")
print(f" {width_px:.0f}x{height_px:.0f}px density={density} -> "
f"{width_dp:.0f}x{height_dp:.0f} dp")
print(f" 列数={columns} 按钮高={cell_h:.0f}dp 字号={text_sp:.0f}sp "
f"按钮宽={cell_w:.1f}dp 可用文字宽={text_area:.1f}dp")
check(f"{tag} 按钮高度 >= {MIN_TOUCH_DP:.0f}dp", cell_h >= MIN_TOUCH_DP,
f"实际 {cell_h}dp")
longest = max(LABELS, key=lambda s: label_width_dp(s, text_sp))
need = label_width_dp(longest, text_sp)
lines = 1 if need <= text_area else 2
needed_h = lines * text_sp * 1.3 + 6
check(f"{tag} 最长文字「{longest}」放得下", needed_h <= cell_h,
f"需 {need:.0f}dp 宽 / {needed_h:.0f}dp 高,可用 {text_area:.0f}dp / {cell_h:.0f}dp")
print(f" 「{longest}」{need:.1f}dp -> {lines} 行,需高 {needed_h:.1f}dp")
margin = text_area / need
check(f"{tag} 文字余量 >= 95%", margin >= 0.95, f"余量 {margin * 100:.0f}%")
print(f" 文字余量 {margin * 100:.0f}%")
rows = (len(LABELS) + columns - 1) // columns
scroll_dp = rows * (cell_h + CELL_MARGIN_DP * 2)
print(f" 按钮 {len(LABELS)} 个 -> {rows} 行,总高约 {scroll_dp:.0f}dp"
f"(屏高 {height_dp:.0f}dp,需滚动 {max(0, scroll_dp - height_dp + 60):.0f}dp)")
return margin
def main() -> int:
print("=" * 74)
print("一、真机参数(来自用户实测的遥控诊断报告)")
print("=" * 74)
dev = REAL_DEVICE
report_one(f"实测设备: {dev['name']}", dev["width_px"], dev["height_px"],
dev["density"])
# ---- 分页:每页都要能一屏放下 ----
print()
print("=" * 74)
print("三、分页布局(每页不超过 7 个按钮)")
print("=" * 74)
width_dp = dev["width_px"] / dev["density"]
height_dp = dev["height_px"] / dev["density"]
columns, cell_h, text_sp = adapt(width_dp, height_dp)
# 顶栏 42dp + 标签栏 42dp + 日志约 60dp + 边距
chrome_dp = 42 + 42 + 62 + 20
available = height_dp - chrome_dp
for name, labels in TABS.items():
rows = (len(labels) + columns - 1) // columns
need = rows * (cell_h + 6)
fits = need <= available
check(f"「{name}」{len(labels)} 个按钮 / {rows} 行,一屏放得下",
fits, f"需要 {need:.0f}dp,可用 {available:.0f}dp")
print(f" {name}: {len(labels)} 个 / {rows} 行 / {need:.0f}dp"
f"(可用 {available:.0f}dp)")
real_cols = adapt(dev["width_px"] / dev["density"], dev["height_px"] / dev["density"])[0]
check(f"真机走 {real_cols} 列布局(348dp 宽应走三列以减少滚动)", real_cols == 3,
f"实际 {real_cols} 列")
# 报告里的 densityDpi 与 density 换算是否自洽
implied = dev["density"] * 160
check(f"density 与 densityDpi 自洽({dev['density']} x 160 = {implied:.0f},"
f"报告值 {dev['density_dpi']})",
abs(implied - dev["density_dpi"]) <= 2,
f"差 {abs(implied - dev['density_dpi']):.1f}")
print("\n" + "=" * 74)
print("二、同一分辨率下不同 density 的覆盖")
print("=" * 74)
worst = 1e9
two_col = 0
for density in [1.0, 1.25, 1.4125, 1.5, 1.75, 2.0, 2.5, 3.0]:
margin = report_one(f"density={density}",
dev["width_px"], dev["height_px"], density)
worst = min(worst, margin)
if adapt(dev["width_px"] / density, dev["height_px"] / density)[0] >= 2:
two_col += 1
print("\n" + "=" * 74)
print(f"最紧的一档文字余量: {worst * 100:.0f}%")
check("常见 density 下不会退化成单列", two_col >= 6,
f"多列档数 {two_col}")
print("\n" + "=" * 74)
print(f"通过 {PASSED} 项,失败 {FAILED} 项")
return 1 if FAILED else 0
if __name__ == "__main__":
sys.exit(main())