Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/wifi_page.c
T
MeowOS f2786552d5 feat(launcher): 蓝牙/WiFi 独立子页面(安卓风)— 新增 subpage.c 统一脚手架(顶栏+分组列表+跟手滚动+左缘返回) + wifi_page.c(开关/当前连接详情/已保存/附近,BSSID去重+中文SSID) + bt_page.c(开关/已连接/已配对/附近扫描配对);SMENU 网络组收敛为 2 入口行 (agent-178)
launcher bd37c8b0→d10c0e8a; 改动文件 -Wall -Wextra 0 warning; 真机待验证: 蓝牙 pair/connect、开关联动、触摸几何
出入: 中文SSID/BSSID去重复用 net.c 既有实现; 模态复用 s_dd_modal(SDK 模态层未上收, 未改 SDK); s_net_open 旧分支留作死代码未删
2026-08-31 03:41:51 +08:00

204 lines
8.1 KiB
C
Raw 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.
/* wifi_page.c — MeowOS 系统设置「WiFi 独立子页面」(安卓风,M2.76)。
*
* 页面(sub_page_t 脚手架 subpage.c 驱动):
* - 顶栏:返回 + 标题「WiFi」 + 右上开关(network.wifi_enabled)
* - 当前连接:SSID 行,点开 → 详情(SSID/AP MAC/本机 MAC/AP IP/本机 IP/频道)
* - 已保存网络:每项点 → wpa_cli select_network 连接;当前连接的项标「已连接」
* - 附近网络:扫描结果(按 BSSID 去重——修复"AP 的 MAC 被当成单独设备列出";
* 中文 SSID 经 wpa_decode_ssid 还原 \xNN 原始字节 → UTF-8 显示)点开 → 详情(SSID/AP MAC)
*
* 均复用 net.c 既有读取(net_wifi_saved / net_wifi_scan / net_wifi_info / net_wifi_ssid /
* wlan_connected),写入只走 meow_settings_*;本机 MAC 等详情读 wpa_cli status。
*/
#include "meow_launcher_internal.h"
/* action code 判位(act 回调据 act 值定位网络) */
#define WF_ACT_CURR (-1) /* 当前连接(SUB_ROW,detail) */
#define WF_ACT_SAVED 0 /* 已保存网络 idx(SUB_ACT,connect) */
#define WF_ACT_SCAN_BASE 1000 /* 附近网络 1000+idx(SUB_ROW,detail) */
typedef struct {
meow_net_t saved[S_NET_MAX];
meow_net_t scan[S_NET_MAX];
int saved_n, scan_n;
char ssid[64];
int connected; /* wlan_connected() */
int wifi_on; /* network.wifi_enabled */
long last_scan_ms; /* 扫描触发节流(net_wifi_scan_trigger 间隔) */
} wifi_ctx_t;
/* 顶栏开关当前值 */
static int wifi_top_sw(void *ctx, int *on)
{
(void)ctx;
int v = 1;
if (meow_settings_get_bool("network.wifi_enabled", &v) != 0) v = 1;
*on = v;
return 1;
}
/* 顶栏开关切换:写设置 + 开/关网卡 + 触发重扫 + 同步状态栏 */
static void wifi_top_sw_set(void *ctx, int on)
{
wifi_ctx_t *c = ctx;
meow_settings_set_bool("network.wifi_enabled", on);
s_net_toggle_wifi(on);
g_sys.wifi_on = on;
paint_sb_right(); /* 状态栏 WiFi 图标随开关即时刷新 */
meow_settings_save();
if (on) { net_wifi_scan_trigger(); c->last_scan_ms = now_ms(); }
}
/* 触发一次 WiFi 扫描(节流:1.5s 内不重复 spawn wpa_cli scan) */
static void wifi_scan(void *ctx)
{
wifi_ctx_t *c = ctx;
if (!c->connected) return;
long t = (long)now_ms();
if (c->last_scan_ms && t - c->last_scan_ms < 1500) return;
c->last_scan_ms = t;
net_wifi_scan_trigger();
}
/* 填行:刷新数据后构建分组列表 */
static int wifi_rows(void *ctx, sub_row_t *rbuf, int max)
{
wifi_ctx_t *c = ctx;
/* 刷新数据(popen 读列表;节流触发扫描) */
c->connected = wlan_connected();
if (c->connected) {
net_wifi_ssid(c->ssid, sizeof c->ssid);
wifi_scan(c);
} else {
c->ssid[0] = 0;
}
c->saved_n = net_wifi_saved(c->saved, S_NET_MAX);
c->scan_n = net_wifi_scan(c->scan, S_NET_MAX);
if (c->saved_n < 0) c->saved_n = 0;
if (c->scan_n < 0) c->scan_n = 0;
int n = 0;
/* 当前连接 */
if (n < max) { rbuf[n].kind = SUB_HDR; rbuf[n].label = "当前连接"; rbuf[n].sub = NULL; rbuf[n].on = 0; rbuf[n].act = 0; n++; }
if (n < max) {
rbuf[n].kind = SUB_ROW;
rbuf[n].label = c->connected && c->ssid[0] ? "已连接" : "未连接";
rbuf[n].sub = c->connected && c->ssid[0] ? c->ssid : "";
rbuf[n].on = 0; rbuf[n].act = WF_ACT_CURR;
n++;
}
/* 已保存网络 */
if (n < max) { rbuf[n].kind = SUB_HDR; rbuf[n].label = "已保存网络"; rbuf[n].sub = NULL; rbuf[n].on = 0; rbuf[n].act = 0; n++; }
if (c->saved_n == 0) {
if (n < max) { rbuf[n].kind = SUB_ROW; rbuf[n].label = "无已保存网络"; rbuf[n].sub = ""; rbuf[n].on = 0; rbuf[n].act = -2; n++; }
} else for (int i = 0; i < c->saved_n && n < max; i++) {
rbuf[n].kind = SUB_ACT;
rbuf[n].label = c->saved[i].name[0] ? c->saved[i].name : "<未命名>";
/* 当前连接的 SSID 标记「已连接」;否则显示 BSSID(若有) */
rbuf[n].sub = (c->connected && c->ssid[0] && !strcmp(c->saved[i].name, c->ssid)) ? "已连接"
: (c->saved[i].mac[0] ? c->saved[i].mac : "");
rbuf[n].on = 0; rbuf[n].act = WF_ACT_SAVED + i;
n++;
}
/* 附近网络 */
if (n < max) { rbuf[n].kind = SUB_HDR; rbuf[n].label = "附近网络"; rbuf[n].sub = NULL; rbuf[n].on = 0; rbuf[n].act = 0; n++; }
if (c->scan_n == 0) {
if (n < max) { rbuf[n].kind = SUB_ROW; rbuf[n].label = "未扫描到附近网络"; rbuf[n].sub = ""; rbuf[n].on = 0; rbuf[n].act = -2; n++; }
} else for (int i = 0; i < c->scan_n && n < max; i++) {
rbuf[n].kind = SUB_ROW;
rbuf[n].label = c->scan[i].name[0] ? c->scan[i].name : "(隐藏网络)";
rbuf[n].sub = c->scan[i].mac[0] ? c->scan[i].mac : "";
rbuf[n].on = 0; rbuf[n].act = WF_ACT_SCAN_BASE + i;
n++;
}
return n;
}
/* 附近网络详情(只读):SSID / AP MAC / 提示 */
static int wifi_nearby_detail_cb(wifi_ctx_t *c, int scan_idx)
{
if (scan_idx < 0 || scan_idx >= c->scan_n) return 0;
char line[S_NET_MAX][48];
const char *txt[S_NET_MAX];
int n = 0;
snprintf(line[n], sizeof line[0], "SSID: %s", c->scan[scan_idx].name[0] ? c->scan[scan_idx].name : "(隐藏网络)"); txt[n] = line[n]; n++;
if (c->scan[scan_idx].mac[0]) { snprintf(line[n], sizeof line[n], "AP MAC: %s", c->scan[scan_idx].mac); txt[n] = line[n]; n++; }
snprintf(line[n], sizeof line[n], "密码/连接由 HibyOS 处理"); txt[n] = line[n]; n++;
s_dd_modal(c->scan[scan_idx].name[0] ? c->scan[scan_idx].name : "附近网络", txt, n, -1);
return 1;
}
/* 普通行(SUB_ROW)点击:当前连接详情 / 附近网络详情 */
static int wifi_detail(void *ctx, int idx, int act)
{
(void)idx;
wifi_ctx_t *c = ctx;
if (act == WF_ACT_CURR) {
/* 当前连接详情(wpa_cli status + 网关):SSID/AP MAC/本机 MAC/AP IP/本机 IP/频道 */
char info[S_NET_MAX][48];
const char *txt[S_NET_MAX];
int n = net_wifi_info(info, S_NET_MAX);
if (n == 0) {
snprintf(info[0], sizeof info[0], "%s", c->connected ? "已连接(无详情)" : "未连接");
txt[0] = info[0]; n = 1;
} else {
for (int i = 0; i < n; i++) txt[i] = info[i];
}
s_dd_modal(c->ssid[0] ? c->ssid : "当前连接", txt, n, -1);
return 1;
}
if (act >= WF_ACT_SCAN_BASE) return wifi_nearby_detail_cb(c, act - WF_ACT_SCAN_BASE);
return 0;
}
/* 动作行(SUB_ACT)点击:已保存网络 → 连接 */
static int wifi_act(void *ctx, int idx, int act)
{
(void)idx;
wifi_ctx_t *c = ctx;
if (act >= WF_ACT_SCAN_BASE) return 0; /* 附近是 detail,不走这里 */
int sidx = act - WF_ACT_SAVED;
if (sidx < 0 || sidx >= c->saved_n) return 0;
if (c->saved[sidx].id < 0) return 0;
char cmd[192];
snprintf(cmd, sizeof cmd,
"PATH=/bin:/sbin:/usr/bin:/usr/sbin wpa_cli -i wlan0 select_network %d 2>/dev/null",
c->saved[sidx].id);
system(cmd);
net_wifi_scan_trigger();
c->last_scan_ms = now_ms();
logmsg("wifi_page: select_network %d", c->saved[sidx].id);
return 1; /* 重绘 + 重填行 */
}
/* 运行 WiFi 独立子页面(阻塞到返回) */
int run_wifi_page(void)
{
static wifi_ctx_t c; /* static:行次指针稳定 */
memset(&c, 0, sizeof c);
sub_page_t p;
memset(&p, 0, sizeof p);
p.title = "WiFi";
p.top_sw = wifi_top_sw;
p.top_sw_set = wifi_top_sw_set;
p.rows = wifi_rows;
p.act = wifi_act;
p.detail = wifi_detail;
p.live = 0; /* WiFi 列表在动作/开关时重扫即可,避免驻留 popen 轮询 */
p.ctx = &c;
/* 打开页面立即触发一次扫描,附近列表更贴近最新 */
net_wifi_scan_trigger();
c.last_scan_ms = now_ms();
bt_role_refresh(0); /* 顺带刷新网络缓存(不影响本页) */
return meow_subpage_run(&p);
}