# -*- coding: utf-8 -*- """手表端修用户报的 3 条。 【1】点「连不上」显示"已打开",电脑上什么都没有 → 自检应答现在带回电脑的**诊断结论**,手表直接显示。 电脑保持零窗口。 【2】设备诊断从标签页挪到首页 用户原话:"我就是连不上才开设备诊断,连的上要设备诊断干嘛" 【3】程序不能自己退出 / 崩掉 → 装全局未捕获异常处理器:任何线程崩了都记录下来继续跑。 """ from __future__ import annotations import sys from pathlib import Path SRC = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\android\src" r"\com\lanremote\watch") MAIN = SRC / "MainActivity.java" CORE = SRC / "DiscoveryCore.java" FIXES = [ # ---------------- 1. 自检应答带回结论 ---------------- (CORE, ''' try { Map obj = Json.parseObject(text); String name = Json.str(obj, "name", ""); if (name != null && name.length() > 0) { return name; } } catch (Exception ignored) { // 解析失败就用来源 IP } return packet.getAddress().getHostAddress();''', ''' try { Map obj = Json.parseObject(text); String name = Json.str(obj, "name", ""); String note = Json.str(obj, "note", ""); if (name != null && name.length() > 0) { // 电脑那边现在会把诊断结论一起回过来(它自己不弹窗口), // 用换行分隔:第一行是电脑名,后面是结论。 return note != null && note.length() > 0 ? name + "\\n" + note : name; } } catch (Exception ignored) { // 解析失败就用来源 IP } return packet.getAddress().getHostAddress();''', "自检应答带回诊断结论"), # ---------------- 2. 首页按钮改成"设备诊断" ---------------- (MAIN, ''' // 连不上?让电脑端把网络自检窗口弹出来(走 UDP,TCP 被拦时也能到) Button selfCheck = bigButton("连不上?让电脑开自检", C_WARN, 14);''', ''' // 连不上?—— 直接在这里做设备诊断。 // 用户原话:"我就是连不上才开设备诊断,连的上要设备诊断干嘛", // 所以它属于首页,不属于功能标签页。 Button selfCheck = bigButton("连不上?点这里诊断", C_WARN, 15);''', "首页按钮改成设备诊断"), (MAIN, ''' selfCheck.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { requestPcSelfCheck(); } });''', ''' selfCheck.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { openDiagPanel(); } });'''), # ---------------- 2b. 标签页里去掉设备诊断 ---------------- (MAIN, ''' act("设备诊断", new Runnable() { public void run() { openDiagPanel(); } }),''', ''' act("电脑时间", new Runnable() { public void run() { sendCommand(Json.obj("cmd", "feature_run", "name", "world_clock", "params", Json.obj()), "电脑时间"); } }),'''), # ---------------- 1b. 显示电脑的结论 ---------------- (MAIN, ''' final String answer = Discovery.requestSelfCheck(MainActivity.this, 5000); runOnUiThread(new Runnable() { @Override public void run() { if (answer != null) { statusView.setText("电脑 " + answer + " 已打开网络自检"); toast("电脑 " + answer + " 已打开自检窗口"); appendLog("电脑 " + answer + " 已打开网络自检"); } else { statusView.setText("没收到电脑回应"); toast("没收到回应:广播可能也没通"); appendLog("自检请求无回应 —— 广播没到电脑"); } } });''', ''' final String answer = Discovery.requestSelfCheck(MainActivity.this, 5000); runOnUiThread(new Runnable() { @Override public void run() { if (answer == null) { statusView.setText("没收到电脑回应"); toast("没收到回应:广播可能也没通"); appendLog("自检请求无回应 —— 广播没到电脑"); return; } // 电脑会把诊断结论一起回过来(它自己不弹窗口) String name = answer; String note = ""; int cut = answer.indexOf('\\n'); if (cut > 0) { name = answer.substring(0, cut); note = answer.substring(cut + 1); } appendLog("电脑 " + name + " 的结论:" + note); if (note.length() == 0) { statusView.setText("电脑收到了请求,但没给结论"); toast("电脑收到了,但没给结论"); return; } statusView.setText("电脑 " + name + " 的诊断结论已收到"); new AlertDialog.Builder(MainActivity.this) .setTitle("电脑的诊断结论") .setMessage(note) .setPositiveButton("知道了", null) .setNeutralButton("复制", new android.content.DialogInterface.OnClickListener() { public void onClick(android.content.DialogInterface d, int w) { copyToWatchClipboard(answer); toast("已复制"); } }) .show(); } });''', "显示电脑的结论"), # ---------------- 3. 全局异常兜底 ---------------- (MAIN, ''' ui = new Handler(Looper.getMainLooper()); store = new DeviceStore(this); client = new RemoteClient();''', ''' ui = new Handler(Looper.getMainLooper()); installCrashGuard(); store = new DeviceStore(this); client = new RemoteClient();'''), (MAIN, " private void refreshDeviceList() {", ''' /** * 兜底:任何线程抛出未捕获异常都不让它把整个 App 干掉。 * * 用户的要求是「不管干嘛,程序都要开着」—— * 后台线程一个 NPE 就闪退,看起来就像"程序自己关了"。 */ private void installCrashGuard() { final Thread.UncaughtExceptionHandler previous = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler( new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, final Throwable error) { try { final String detail = String.valueOf(error); ui.post(new Runnable() { @Override public void run() { try { appendLog("已拦截内部错误:" + detail); if (logView != null) { logView.setTextColor(C_DANGER); } toast("出了点小问题,程序继续运行"); } catch (Throwable ignored) { // 兜底里再出错就彻底放弃提示 } } }); } catch (Throwable ignored) { // 忽略 } // 不调用 previous:调用它等于让系统按崩溃处理 if (previous != null && false) { previous.uncaughtException(thread, error); } } }); } private void refreshDeviceList() {'''), ] def apply(path: Path, old: str, new: str, tag: str) -> bool: text = path.read_text(encoding="utf-8") if old not in text: print(f" [跳过] {tag} —— 锚点没找到") return False text = text.replace(old, new, 1) path.write_text(text, encoding="utf-8") print(f" {tag}: OK") return True def main() -> int: ok = True for path, old, new, tag in FIXES: if not apply(path, old, new, tag): ok = False return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())