feat(launcher): M3导航栈+M5通知点击跳转 (agent-202) — nav_stack(≤16深)+MSG_NAV REPORT/EXIT+launch_activity链路注入(MEOW_ACTIVITY/MEOW_CHAIN)+栈根退出回主屏; 通知点击按route_status(0拉起/1 NO ROUTE/2 SOURCE NOT FOUND/-1 NONE关面板不动作); picker协议位预留(0x0070/0x0071); 裸App兼容

launcher 4fe4103a→a42171a1; qemu实测 declare/query/nav report/exit/notify+querynotif 全过
发现: §10.5 App前台通知中心叠加会话(MSG_NOTIF_OPEN)实际未实现,文档超前,待补
This commit is contained in:
MeowOS committed 2026-08-31 06:27:10 +08:00
1 parent 955dbe1228
commit 85b4aea24f
9 files changed
+321 -39

No files matched your search

+42 -17
View File
@@ -69,6 +69,7 @@ static int ncp_collect_cb(const meow_notif_t *n, void *ctx)
memset(r, 0, sizeof *r);
r->id = n->id;
ncp_strncpy(r->app_id, n->app_id, sizeof r->app_id);
ncp_strncpy(r->category, n->category, sizeof r->category);
ncp_strncpy(r->summary, n->summary, sizeof r->summary);
ncp_strncpy(r->body, n->body, sizeof r->body);
ncp_strncpy(r->icon, n->app_icon, sizeof r->icon);
@@ -713,32 +714,56 @@ static int ncp_slider_apply(int which, int tx, int save_now)
}
/* 通知点击:dismiss(标记阅读)+ 若 app 有 entry 记录则请求启动。返回 1=应关闭面板。 */
static int ncp_row_tap(int tx, int ty, int scroll, int *want_launch)
/* 通知点击:dismiss(标记阅读)+ 按 route_status(FRAMEWORK_DESIGN §4)产出 notif_click_t *click。
* status 0=OK 跳转(chain 解析出链路;媒体无 target 也 status=0,chain 置空=裸启动主屏);
* status 1=NO ROUTE(源 app 在,但无 target_activity / 路由未注册);
* status 2=SOURCE NOT FOUND(源 app 不在 apps[] 或 exec 不可用)。
* 返回 1=应关闭面板(点击即关;status 1/2 由 run_menu 弹 toast,不崩)。 */
static int ncp_row_tap(int tx, int ty, int scroll, notif_click_t *click)
{
(void)tx; /* 行命中仅依赖 ty/scroll;tx 保留作接口一致(0-warning) */
int eff = ty - NCP_LIST_TOP + scroll;
int row = mnp_row_at(eff, 0, g_nrows * NCP_ROW_H, NCP_ROW_H);
if (row < 0 || row >= g_nrows) return 0;
const ncp_row_t *r = &g_rows[row];
meow_notif_dismiss(r->id); /* 点击 = 阅读,撤下 */
/* 跳转:app entry 记录(apps[] 内且 ok)→ 记 want_launch(run_menu 走标准启动)。
* target_activity 为后续 M3 导航预留下的跳转目标(activity 级路由后置)。 */
if (want_launch) *want_launch = -1;
if (click) {
click->app_idx = -1;
click->status = NOTIF_CLICK_STATUS_NOROUTE;
click->chain[0] = 0;
}
/* 源 app 定位(apps[] 内且 exec ok):找不到 → SOURCE NOT FOUND(不崩,toast) */
int src = -1;
if (g_ncp_apps)
for (int i = 0; i < g_ncp_napps; i++)
if (!strcmp(g_ncp_apps[i].id, r->app_id) && g_ncp_apps[i].ok) {
if (want_launch) *want_launch = i;
break;
}
return 1; /* 点击即关(启动由 run_menu 执行;无记录则仅关闭) */
if (!strcmp(g_ncp_apps[i].id, r->app_id) && g_ncp_apps[i].ok) { src = i; break; }
if (src < 0) {
if (click) click->status = NOTIF_CLICK_STATUS_NOSRC;
return 1;
}
/* 跳转判定:M5 接 M3 —— target_activity 解析出链路则跳;媒体通知(无 target)整 app 拉起主屏;
* 其余无路由 → NO ROUTE(不崩,toast)。 */
int depth = 0;
char chain[MEOW_CHAIN_MAX] = "";
if (r->target[0] && resolve_chain(r->app_id, r->target, chain, &depth) == MEOW_OK) {
if (click) { click->app_idx = src; click->status = NOTIF_CLICK_STATUS_OK;
strncpy(click->chain, chain, MEOW_CHAIN_MAX - 1);
click->chain[MEOW_CHAIN_MAX - 1] = 0; }
} else if (!strcmp(r->category, MEOW_NOTIF_MEDIA_CAT)) {
if (click) { click->app_idx = src; click->status = NOTIF_CLICK_STATUS_OK;
click->chain[0] = 0; } /* 媒体:整 app 前台(无 activity 链则进主屏) */
} else {
if (click) click->status = NOTIF_CLICK_STATUS_NOROUTE;
}
return 1; /* 点击即关(status 0 由 run_menu 走 launch_activity/launch_app;1/2 弹 toast) */
}
/* ---- 通知中心面板主循环(阻塞;参照 run_settings_page 交互惯用法)---- */
void run_notif_center(struct app *apps, int napps, int *want_launch,
void run_notif_center(struct app *apps, int napps, notif_click_t *click,
int live_open, int lox, int loy)
{
if (want_launch) *want_launch = -1;
if (click) { click->app_idx = -1; click->status = NOTIF_CLICK_STATUS_NONE; click->chain[0] = 0; }
int list_scroll = 0;
unsigned char evbuf16[16];
g_ncp_apps = apps; g_ncp_napps = napps;
@@ -759,7 +784,7 @@ void run_notif_center(struct app *apps, int napps, int *want_launch,
if (tfd >= 0) { unsigned char ev[16]; while (read(tfd, ev, sizeof ev) == 16) {} }
unsigned long long touch_cooldown_until = now_ms() + 300;
unsigned long long last_tick = now_ms();
unsigned long long last_act = now_ms();
unsigned long long last_act = now_ms(); (void)last_act; /* 预留 idle 计时;当前未读(0-warning) */
unsigned long long last_listchk = now_ms();
int td = 0, td_ok = 0, tdx = -1, tdy = -1, tlx = -1, tly = -1;
@@ -928,10 +953,10 @@ void run_notif_center(struct app *apps, int napps, int *want_launch,
if (meow_auto_slept && !meow_screen_on) pwr_woke = 1;
}
if (pwr && pwr_hold_at) {
if (now - pwr_hold_at >= power_forceoff_ms && !pwr_menu_state) {
if (now - pwr_hold_at >= (unsigned long long)power_forceoff_ms && !pwr_menu_state) {
if (sim_no_exec) logmsg("notif-center pm: [sim-no-exec] hold %dms -> would forceoff", power_forceoff_ms);
else { logmsg("notif-center pm: hold %dms -> force poweroff", power_forceoff_ms); meow_power_action(POWER_SHUTDOWN); }
} else if (now - pwr_hold_at >= power_longpress_menu_ms && !pwr_menu_state) {
} else if (now - pwr_hold_at >= (unsigned long long)power_longpress_menu_ms && !pwr_menu_state) {
pwr_menu_state = 1;
logmsg("notif-center pm: hold %dms -> power menu", power_longpress_menu_ms);
show_power_menu();
@@ -951,7 +976,7 @@ void run_notif_center(struct app *apps, int napps, int *want_launch,
if (!pwr && m_prev_pwr) {
if (pwr_suppress_click)
logmsg("notif-center pm: release after menu -> no toggle");
else if (pwr_hold_at && (now - pwr_hold_at < power_longpress_menu_ms) && !pwr_menu_state && !pwr_woke) {
else if (pwr_hold_at && (now - pwr_hold_at < (unsigned long long)power_longpress_menu_ms) && !pwr_menu_state && !pwr_woke) {
logmsg("notif-center pm: single-click -> toggle panel");
meow_toggle_panel(); meow_auto_slept = 0; last_act = now_ms(); need_paint = 1;
} else if (pwr_woke) {
@@ -1197,7 +1222,7 @@ void run_notif_center(struct app *apps, int napps, int *want_launch,
hit = 1; need_paint = 1;
}
if (!hit && ty >= NCP_LIST_TOP && ty < NCP_LIST_BOT) {
if (ncp_row_tap(tx, ty, list_scroll, want_launch)) {
if (ncp_row_tap(tx, ty, list_scroll, click)) {
hit = 1;
if (anim_ok) anim_target = 0; /* 点击通知:dismiss + 记录启动 → 滑出收回 */
else closed = 1;