mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 17:10:43 +00:00
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
299 lines
12 KiB
Python
299 lines
12 KiB
Python
# -*- 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())
|