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
+261
View File
@@ -0,0 +1,261 @@
# -*- coding: utf-8 -*-
"""液态玻璃 第二步:动态效果
* Tab 栏:玻璃容器 + 一个会"滑过去"的指示器(宽高和位置一起动)
* 切页:内容淡入 + 轻微上移
* 浮层面板(镜像/诊断):从底部滑入、滑出
* 顶栏 / 日志 / 连接面板:换成玻璃材质
注意:这个脚本**无条件写盘**。之前因为一处锚点失败就整体不写,
白白丢了一整轮改动 —— 现在失败的只跳过那一处。
"""
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 栏:玻璃 + 滑动指示器 ----------------
TABBAR_OLD = ''' // ---- 分页标签 ----
HorizontalScrollView tabScroll = new HorizontalScrollView(this);
tabScroll.setHorizontalScrollBarEnabled(false);
tabBar = new LinearLayout(this);
tabBar.setOrientation(LinearLayout.HORIZONTAL);
tabBar.setPadding(0, 0, 0, 0);
tabScroll.addView(tabBar);
controlPanel.addView(tabScroll, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, dp(42)));'''
TABBAR_NEW = ''' // ---- 分页标签(玻璃容器 + 滑动指示器)----
HorizontalScrollView tabScroll = new HorizontalScrollView(this);
tabScroll.setHorizontalScrollBarEnabled(false);
FrameLayout tabWrap = new FrameLayout(this);
tabWrap.setBackground(glass(18));
tabWrap.setPadding(dp(4), dp(4), dp(4), dp(4));
tabIndicator = new View(this);
tabIndicator.setBackground(glassButton(C_ACCENT, 14));
tabIndicator.setLayoutParams(new FrameLayout.LayoutParams(dp(60), dp(34)));
tabWrap.addView(tabIndicator);
tabBar = new LinearLayout(this);
tabBar.setOrientation(LinearLayout.HORIZONTAL);
tabWrap.addView(tabBar, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
tabScroll.addView(tabWrap);
controlPanel.addView(tabScroll, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, dp(48)));'''
# ---------------- 2. 标签按钮:透明底 ----------------
TABITEM_OLD = ''' tab.setPadding(dp(14), dp(8), dp(14), dp(8));
tab.setOnClickListener(new View.OnClickListener() {'''
TABITEM_NEW = ''' tab.setPadding(dp(14), dp(8), dp(14), dp(8));
tab.setBackgroundColor(0x00000000);
tab.setOnClickListener(new View.OnClickListener() {'''
TABITEM_MARGIN_OLD = ''' LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT);
params.setMargins(0, 0, dp(6), 0);'''
TABITEM_MARGIN_NEW = ''' LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT);
params.setMargins(0, 0, 0, 0);'''
# ---------------- 3. selectTab ----------------
SELECT_OLD = ''' currentTab = index;
for (int i = 0; i < tabBar.getChildCount(); i++) {
View child = tabBar.getChildAt(i);
boolean on = (i == index);
child.setBackground(rounded(on ? C_ACCENT : C_CARD, 8));
if (child instanceof TextView) {
((TextView) child).setTextColor(on ? 0xFFFFFFFF : C_FG);
}
}'''
SELECT_NEW = ''' currentTab = index;
for (int i = 0; i < tabBar.getChildCount(); i++) {
View child = tabBar.getChildAt(i);
boolean on = (i == index);
child.setBackgroundColor(0x00000000);
if (child instanceof TextView) {
((TextView) child).setTextColor(on ? 0xFFFFFFFF : C_FG);
child.animate().alpha(on ? 1f : 0.72f).setDuration(200).start();
}
}
moveTabIndicator(tabBar.getChildAt(index));'''
SELECT_ANIM_OLD = ''' for (Act item : tabDefs[index].acts) {
addRow(tabContent, action(item.label, item.task), null);
}
flushGrid(tabContent);
}'''
SELECT_ANIM_NEW = ''' for (Act item : tabDefs[index].acts) {
addRow(tabContent, action(item.label, item.task), null);
}
flushGrid(tabContent);
// 切页时内容淡入 + 轻微上移,做出"流动"的感觉
animateIn(tabContent, 10f, 220);
}
/** 指示器滑到目标标签;宽度和位置一起动。 */
private void moveTabIndicator(final View target) {
if (tabIndicator == null || target == null) {
return;
}
if (target.getWidth() == 0) {
// 布局还没完成,等一帧再试
tabIndicator.post(new Runnable() {
@Override
public void run() {
moveTabIndicator(target);
}
});
return;
}
final int startX = (int) tabIndicator.getTranslationX();
final int startW = tabIndicator.getLayoutParams().width;
final int endX = tabBar.getLeft() + target.getLeft();
final int endW = target.getWidth();
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(300);
animator.setInterpolator(new android.view.animation.DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = (Float) animation.getAnimatedValue();
ViewGroup.LayoutParams params = tabIndicator.getLayoutParams();
params.width = (int) (startW + (endW - startW) * fraction);
tabIndicator.setLayoutParams(params);
tabIndicator.setTranslationX(startX + (endX - startX) * fraction);
}
});
animator.start();
}'''
# ---------------- 4. 字段 ----------------
FIELD_OLD = " private List<String> featureGroups = null;"
FIELD_NEW = (" private List<String> featureGroups = null;\n"
" private View tabIndicator;")
# ---------------- 5. 顶栏 / 日志 / 连接面板 ----------------
TOPBAR_OLD = ''' top.addView(disconnect);
controlPanel.addView(top);'''
TOPBAR_NEW = ''' top.addView(disconnect);
top.setBackground(glass(16));
top.setPadding(dp(10), dp(8), dp(8), dp(8));
controlPanel.addView(top);'''
LOG_OLD = " logView.setBackground(rounded(C_CARD, 6));"
LOG_NEW = " logView.setBackground(glass(GLASS_FILL_SOLID, 14, GLASS_EDGE_DIM));"
CONNECT_OLD = ''' ScrollView scroll = new ScrollView(this);
scroll.setBackgroundColor(C_BG);
LinearLayout box = new LinearLayout(this);
box.setOrientation(LinearLayout.VERTICAL);
box.setBackgroundColor(C_BG);'''
CONNECT_NEW = ''' ScrollView scroll = new ScrollView(this);
scroll.setBackgroundColor(0x00000000);
LinearLayout box = new LinearLayout(this);
box.setOrientation(LinearLayout.VERTICAL);
box.setBackgroundColor(0x00000000);'''
# ---------------- 6. 面板滑入滑出(用唯一锚点)----------------
MIRROR_OPEN_OLD = ''' mirrorPanel.setVisibility(View.VISIBLE);
mirrorPanel.bringToFront();'''
MIRROR_OPEN_NEW = ''' mirrorPanel.setVisibility(View.VISIBLE);
mirrorPanel.bringToFront();
animateIn(mirrorPanel, 24f, 260);'''
# 关闭镜像面板:只在 closeMirrorPanel() 里那一处(后面紧跟 mirrorImage 判空)
MIRROR_CLOSE_OLD = ''' mirrorPanel.setVisibility(View.GONE);
if (mirrorImage != null) {'''
MIRROR_CLOSE_NEW = ''' animateOut(mirrorPanel, 24f, 200, new Runnable() {
@Override
public void run() {
mirrorPanel.setVisibility(View.GONE);
}
});
if (mirrorImage != null) {'''
DIAG_OPEN_OLD = ''' diagPanel.setVisibility(View.VISIBLE);
diagPanel.bringToFront();'''
DIAG_OPEN_NEW = ''' diagPanel.setVisibility(View.VISIBLE);
diagPanel.bringToFront();
animateIn(diagPanel, 26f, 280);'''
DIAG_CLOSE_OLD = ''' if (diagPanel != null) {
diagPanel.setVisibility(View.GONE);
}'''
DIAG_CLOSE_NEW = ''' if (diagPanel != null) {
animateOut(diagPanel, 26f, 200, new Runnable() {
@Override
public void run() {
diagPanel.setVisibility(View.GONE);
}
});
}'''
PAIRS = [
(FIELD_OLD, FIELD_NEW, "tabIndicator 字段"),
(TABBAR_OLD, TABBAR_NEW, "Tab 栏玻璃容器"),
(TABITEM_OLD, TABITEM_NEW, "标签透明底"),
(TABITEM_MARGIN_OLD, TABITEM_MARGIN_NEW, "标签间距"),
(SELECT_OLD, SELECT_NEW, "selectTab 指示器"),
(SELECT_ANIM_OLD, SELECT_ANIM_NEW, "内容转场 + moveTabIndicator"),
(TOPBAR_OLD, TOPBAR_NEW, "顶栏玻璃"),
(LOG_OLD, LOG_NEW, "日志玻璃"),
(CONNECT_OLD, CONNECT_NEW, "连接面板透明"),
(MIRROR_OPEN_OLD, MIRROR_OPEN_NEW, "镜像面板滑入"),
(MIRROR_CLOSE_OLD, MIRROR_CLOSE_NEW, "镜像面板滑出"),
(DIAG_OPEN_OLD, DIAG_OPEN_NEW, "诊断面板滑入"),
(DIAG_CLOSE_OLD, DIAG_CLOSE_NEW, "诊断面板滑出"),
]
def main() -> int:
text = MAIN.read_text(encoding="utf-8")
failed = []
applied = 0
for old, new, tag in PAIRS:
if old not in text:
failed.append(tag)
print(f" [跳过] {tag} —— 锚点没找到")
continue
occurrences = text.count(old)
if occurrences > 1:
print(f" [注意] {tag} 匹配 {occurrences} 处,只改第一处")
text = text.replace(old, new, 1)
applied += 1
print(f" {tag}: OK")
# 无条件写盘:失败的只跳过那一处,不能整体丢
MAIN.write_text(text, encoding="utf-8")
print(f"\n 已写盘(成功 {applied}/{len(PAIRS)})")
if failed:
print(f" 未应用: {', '.join(failed)}")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())