Files
ykxmz/_build/patch_watch_features_tab.py
xmz7891 b62ac865ea 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 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
2026-10-06 19:01:05 +08:00

299 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""手表端接上电脑功能注册表。
新增「功能」分页:显示 / 音量 / 系统 / 查看 / 效率 / 文件 六个分组,
点进去是这一组的功能列表,按 kind 决定怎么执行:
toggle 直接切换
value 弹档位选择(亮度 10~100 分 5 档)
input 弹输入框(有的要两个字段)
action 直接执行;删除类先确认
"""
from __future__ import annotations
import sys
from pathlib import Path
MAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\android\src"
r"\com\lanremote\watch\MainActivity.java")
# ---- 1. 加一个「功能」分页 ----
TAB_OLD = ''' new TabDef("系统", new Act[]{'''
TAB_NEW = ''' new TabDef("功能", new Act[]{
act("显示", new Runnable() {
public void run() { pickFeatureGroup("显示"); }
}),
act("音量", new Runnable() {
public void run() { pickFeatureGroup("音量"); }
}),
act("系统", new Runnable() {
public void run() { pickFeatureGroup("系统"); }
}),
act("查看", new Runnable() {
public void run() { pickFeatureGroup("查看"); }
}),
act("效率", new Runnable() {
public void run() { pickFeatureGroup("效率"); }
}),
act("文件", new Runnable() {
public void run() { pickFeatureGroup("文件"); }
}),
}),
new TabDef("系统", new Act[]{'''
# ---- 2. 方法 ----
ANCHOR = " private Button bigButton(String text, int color, float sizeSp) {"
METHODS = ''' // ==================================================================
// 电脑功能(由电脑端声明,这里只负责拉列表和调用)
// ==================================================================
private List<Map<String, Object>> featureCache = null;
/** 按分组列出电脑端的功能。 */
private void pickFeatureGroup(final String group) {
appendLog("正在获取「" + group + "」功能…");
io.execute(new Runnable() {
@Override
public void run() {
try {
if (featureCache == null) {
Map<String, Object> reply =
client.call(Json.obj("cmd", "feature_list"), 20000);
featureCache = mapList(reply, "features");
}
final List<Map<String, Object>> items =
new ArrayList<Map<String, Object>>();
List<String> labels = new ArrayList<String>();
for (Map<String, Object> item : featureCache) {
if (!group.equals(Json.str(item, "group", ""))) {
continue;
}
items.add(item);
labels.add(Json.str(item, "label", "?"));
}
final List<String> finalLabels = labels;
ui.post(new Runnable() {
@Override
public void run() {
if (finalLabels.isEmpty()) {
toast("这一组暂时没有功能");
return;
}
showChooser("电脑功能 · " + group, finalLabels, new Chooser() {
@Override
public void onPick(int index) {
dispatchFeature(items.get(index));
}
});
}
});
} catch (final IOException e) {
featureCache = null;
postError("获取功能列表", e);
}
}
});
}
/** 按功能类型决定怎么执行。 */
private void dispatchFeature(final Map<String, Object> feature) {
final String name = Json.str(feature, "name", "");
final String label = Json.str(feature, "label", name);
final String kind = Json.str(feature, "kind", "action");
if (name.isEmpty()) {
toast("功能名不对");
return;
}
if ("toggle".equals(kind)) {
boolean on = Json.bool(feature, "on", false);
runFeature(name, Json.obj("on", !on), (on ? "关闭 " : "开启 ") + label);
return;
}
if ("value".equals(kind)) {
int min = Json.integer(feature, "min", 0);
int max = Json.integer(feature, "max", 100);
final List<String> labels = new ArrayList<String>();
final List<Integer> values = new ArrayList<Integer>();
for (int step = 1; step <= 5; step++) {
int value = min + (max - min) * step / 5;
values.add(value);
labels.add(String.valueOf(value));
}
showChooser(label, labels, new Chooser() {
@Override
public void onPick(int index) {
runFeature(name, Json.obj("value", values.get(index)),
label + " = " + values.get(index));
}
});
return;
}
if ("input".equals(kind)) {
String hint = Json.str(feature, "hint", "输入");
final String key = Json.str(feature, "key", "text");
String hint2 = Json.str(feature, "hint2", "");
final String key2 = Json.str(feature, "key2", "");
if (!key2.isEmpty() && !hint2.isEmpty()) {
promptTwo(label, hint, hint2, new TwoHandler() {
@Override
public void onInput(String first, String second) {
Map<String, Object> params = Json.obj(key, first);
params.put(key2, second);
runFeature(name, params, label);
}
});
return;
}
promptInput(label, hint, "", new InputHandler() {
@Override
public void onInput(String text) {
if (!text.isEmpty()) {
runFeature(name, Json.obj(key, text), label);
}
}
});
return;
}
// action:删除类的先确认
if (name.startsWith("delete_") || name.equals("empty_recycle")
|| name.equals("clear_clip") || name.equals("restart_explorer")) {
new AlertDialog.Builder(this)
.setTitle(label)
.setMessage("确定要执行「" + label + "」吗?")
.setPositiveButton("执行", new android.content.DialogInterface.OnClickListener() {
@Override
public void onClick(android.content.DialogInterface d, int w) {
runFeature(name, Json.obj(), label);
}
})
.setNegativeButton("取消", null)
.show();
return;
}
runFeature(name, Json.obj(), label);
}
private void runFeature(final String name, final Map<String, Object> params,
final String label) {
appendLog("执行:" + label);
io.execute(new Runnable() {
@Override
public void run() {
try {
Map<String, Object> request = Json.obj("cmd", "feature_run",
"name", name);
request.put("params", params);
final Map<String, Object> reply = client.call(request, 30000);
final boolean ok = Json.bool(reply, "ok", false);
final String note = ok
? Json.str(reply, "note", "已执行")
: Json.str(reply, "error", "执行失败");
ui.post(new Runnable() {
@Override
public void run() {
appendLog(label + ":" + firstLine(note));
// 查看类的结果比较长,用对话框显示
if (note.length() > 40 || note.contains("\\n")) {
new AlertDialog.Builder(MainActivity.this)
.setTitle(label)
.setMessage(note)
.setPositiveButton("知道了", null)
.show();
} else {
toast(note);
}
}
});
} catch (final IOException e) {
postError(label, e);
}
}
});
}
private static String firstLine(String text) {
int cut = text.indexOf('\\n');
return cut > 0 ? text.substring(0, cut) : text;
}
/** 两个输入框的对话框。 */
private interface TwoHandler {
void onInput(String first, String second);
}
private void promptTwo(String title, String hint1, String hint2,
final TwoHandler handler) {
LinearLayout box = new LinearLayout(this);
box.setOrientation(LinearLayout.VERTICAL);
box.setPadding(dp(14), dp(8), dp(14), 0);
final EditText first = new EditText(this);
first.setHint(hint1);
first.setSingleLine(true);
box.addView(first);
final EditText second = new EditText(this);
second.setHint(hint2);
second.setSingleLine(true);
box.addView(second);
new AlertDialog.Builder(this)
.setTitle(title)
.setView(box)
.setPositiveButton("确定", new android.content.DialogInterface.OnClickListener() {
@Override
public void onClick(android.content.DialogInterface d, int w) {
handler.onInput(first.getText().toString().trim(),
second.getText().toString().trim());
}
})
.setNegativeButton("取消", null)
.show();
}
/** 把回复里的对象数组取出来。 */
@SuppressWarnings("unchecked")
private static List<Map<String, Object>> mapList(Map<String, Object> reply, String key) {
List<Map<String, Object>> out = new ArrayList<Map<String, Object>>();
try {
Object raw = reply == null ? null : reply.get(key);
if (raw instanceof List) {
for (Object item : (List<Object>) raw) {
if (item instanceof Map) {
out.add((Map<String, Object>) item);
}
}
}
} catch (Exception ignored) {
// 结构不对就返回空
}
return out;
}
private Button bigButton(String text, int color, float sizeSp) {'''
def main() -> int:
text = MAIN.read_text(encoding="utf-8")
ok = True
for old, new, tag in ((TAB_OLD, TAB_NEW, "功能分页"),
(ANCHOR, METHODS, "功能方法")):
if old not in text:
print(f" [失败] {tag} 锚点未匹配")
ok = False
else:
text = text.replace(old, new, 1)
print(f" {tag}: OK")
if ok:
MAIN.write_text(text, encoding="utf-8")
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())