diff --git a/hello b/hello index f83ff87..d770cf4 100755 Binary files a/hello and b/hello differ diff --git a/hello.c b/hello.c index 5178d91..396fd7e 100644 --- a/hello.c +++ b/hello.c @@ -3,12 +3,15 @@ * 契约(MEOW_APP_SDK.md §1/§3/§6):应用只调 meow_ui API —— 屏幕(back_buf + * flush 上屏)与输入(meow_ui_run 事件循环)由框架接管;不再 open/mmap/ioctl * /dev/fb0、不再读 /dev/input/event*。本应用验证「清屏 + 画文本 + 画按钮 + - * 响应触摸」这一最小工作闭环。 + * 响应触摸」这一最小工作闭环,并集成了通知触发按钮(meow_notify_send,§9.1) + * 用于端到端测试通知链路(SDK → IPC → launcher 中央存储 → 10s TTL 落盘)。 * * 交互: * - 点按钮 → tap 计数 +1(按钮标签实时更新); + * - 通知触发行(6 个按钮):每个点击 meow_notify_send() 发一条不同参数的通知, + * 覆盖 普通INFO / 媒体(单例) / HIGH紧急度 / 进度(40%) / 常驻 / 跳转Activity; + * - CANCEL LAST 按钮:meow_notify_cancel(最近一次 send 的 id); * - 左缘左滑(抬手触发)→ 请求退出(回应用列表);滑动过程顶部出现随位移增长的进度条; - * - 物理键 POWER 不再映射 exit(§3.4.1:物理键系统统一管理,电源键=纯息屏/亮屏); * - 空闲时 on_tick 每秒刷新一行状态(含运行秒数)。 * * 宿主/qemu 离屏:设 MEOW_UI_DUMP= 时,首帧 flush 即把 back_buf 写成 @@ -26,6 +29,12 @@ #include static meow_widget *g_btn; +static meow_widget *g_nbtn[6]; /* 通知触发按钮行 */ +static meow_widget *g_cancel; /* 取消最近一条通知 */ +static meow_widget *g_fs_btn; /* FULLSCREEN 进入按钮(主界面) */ +static int g_fullscreen = 0; /* 1=处于全屏视图(点任意处退出回主界面) */ +static const char *g_notif_labels[6] = { "INFO", "MEDIA", "HIGH", "PROG", "ONGO", "TGT" }; +static uint32_t g_last_notif = 0; /* 最近一次 send 返回的 id,供 cancel */ static int g_taps = 0; static int g_secs = 0; static char g_btn_label[32] = "TAP ME"; @@ -34,23 +43,152 @@ static char g_btn_label[32] = "TAP ME"; * 删除自造轮子的 hellolog()(自读 MEOW_LOG_DIR + snprintf + fopen/fprintf)。 */ static void on_sigterm(int s) { (void)s; meow_ui_request_exit(); } +/* 通知触发:对应第 which 个按钮(0..5)。SDK 端 meow_notify_send() 自动注册未声明 + * 类型(本应用用到 4 种:GENERAL / MEDIA / PROGRESS / MESSAGE,均在 4 种上限内), + * 超时语义见 meow_ui.h §9.1;媒体类型为单例(重发替换)。 */ +static void notif_send(int which) +{ + meow_notify n; + memset(&n, 0, sizeof n); + n.progress = -1; /* 缺省不显示进度条 */ + n.timeout_ms = MEOW_NOTIFY_TIMEOUT_NEVER; + n.urgency = MEOW_NOTIFY_URG_NORMAL; + const char *label = "?"; + + switch (which) { + case 0: /* 普通 INFO */ + label = "INFO"; + n.cat = MEOW_NOTIFY_CAT_GENERAL; + n.title = "测试-普通通知"; + n.body = "普通 INFO 通知,timeout=5000ms"; + n.timeout_ms = 5000; + break; + case 1: /* 媒体单例(ongoing,不自动过期) */ + label = "MEDIA"; + n.cat = MEOW_NOTIFY_CAT_MEDIA; + n.urgency = MEOW_NOTIFY_URG_LOW; + n.title = "测试-媒体通知"; + n.body = "媒体单例,正在播放,timeout=-1 常驻"; + n.timeout_ms = MEOW_NOTIFY_TIMEOUT_ONGOING; + break; + case 2: /* HIGH 紧急度 */ + label = "HIGH"; + n.cat = MEOW_NOTIFY_CAT_GENERAL; + n.urgency = MEOW_NOTIFY_URG_HIGH; + n.title = "测试-紧急度HIGH"; + n.body = "高紧急度:顶部横幅+提示音"; + n.timeout_ms = 3000; + break; + case 3: /* 进度通知 */ + label = "PROG"; + n.cat = MEOW_NOTIFY_CAT_PROGRESS; + n.title = "测试-进度通知"; + n.body = "下载进度 40%"; + n.timeout_ms = 8000; + n.progress = 40; + break; + case 4: /* 常驻(timeout=-1,不自动过期,需手动取消) */ + label = "ONGO"; + n.cat = MEOW_NOTIFY_CAT_GENERAL; + n.title = "测试-常驻通知"; + n.body = "常驻不自动过期(timeout=-1),需手动取消"; + n.timeout_ms = MEOW_NOTIFY_TIMEOUT_ONGOING; + break; + case 5: /* 带 target_activity(SDK 结构暂无 icon 字段,故只填跳转目标) */ + label = "TGT"; + n.cat = MEOW_NOTIFY_CAT_MESSAGE; + n.title = "测试-跳转Activity"; + n.body = "点击跳转 target_activity=main"; + n.timeout_ms = 6000; + n.target_activity = "main"; + break; + default: + return; + } + + uint32_t id = meow_notify_send(&n); + g_last_notif = id; + meow_log(MEOW_LOG_INFO, + "notify btn=%s id=%u cat=%s urg=%s tmo=%d prog=%d target=%s title=%s", + label, (unsigned)id, meow_notify_category_str(n.cat), + meow_notify_urgency_str(n.urgency), n.timeout_ms, n.progress, + n.target_activity ? n.target_activity : "-", + n.title ? n.title : "-"); +} + +static void notif_cancel(void) +{ + int r = meow_notify_cancel(g_last_notif); + meow_log(MEOW_LOG_INFO, "notify cancel id=%u result=%d", (unsigned)g_last_notif, r); + g_last_notif = 0; +} + +/* 进入/退出全屏视图(MeowOS 全屏机制,§3.1): + * - fullscreen(1) + collapsed(1):状态栏「上收出屏只留提示线」(不完全沉浸,inset=4px), + * 顶部提示线热区仍可下拉,左缘返回手势(app 已注册 on_swipe)仍生效——SDK 自动处理,非 app 拦截; + * - fullscreen(0) + collapsed(0):恢复整条状态栏主界面。 + * SDK 基座默认瞬切(g_sbar_collapse_anim_ms=0);如需过渡动画可先 meow_ui_statusbar_animate(ms)。 */ +static void set_fullscreen(int on) +{ + g_fullscreen = on ? 1 : 0; + meow_ui_set_fullscreen(g_fullscreen); + meow_ui_statusbar_set_collapsed(g_fullscreen); + meow_log(MEOW_LOG_INFO, g_fullscreen ? "fullscreen ON (collapsed)" : "fullscreen OFF (restore)"); +} + static void redraw(void) { const meow_theme *th = meow_theme_get(); int sb = meow_ui_statusbar_height(); /* A-0 全局状态栏 inset:内容下移避免被盖 */ + if (g_fullscreen) { + /* 全屏页:纯色占满 + 居中提示;点任意处 / 左缘左滑(SDK on_swipe)返回 */ + meow_ui_clear(th->accent); + meow_ui_text_center(240, 330, "FULLSCREEN ACTIVE", 28, 0xFFFFFF); + meow_ui_text_center(240, 366, "tap anywhere = back to home", 20, 0xFFFFFF); + meow_ui_text_center(240, 394, "(left-edge swipe also returns)", 20, 0xFFFFFF); + meow_ui_flush(); + return; + } meow_ui_clear(th->bg); meow_ui_text_center(240, sb + 8, "MEOWOS HELLO", 28, th->fg); meow_ui_text_center(240, sb + 38, "SDK: meow_ui.a", 20, th->dim); meow_widget_draw(g_btn); + meow_ui_text_center(240, 372, "tap = send notification (see log)", 20, th->dim); + for (int i = 0; i < 6; i++) meow_widget_draw(g_nbtn[i]); + meow_widget_draw(g_cancel); + meow_widget_draw(g_fs_btn); char line[64]; snprintf(line, sizeof line, "taps=%d uptime=%ds", g_taps, g_secs); - meow_ui_text_center(240, 500, line, 20, th->dim); + meow_ui_text_center(240, 516, line, 20, th->dim); meow_ui_text(20, 660, "left-swipe = exit", 20, th->dim); meow_ui_flush(); } static void on_tap(int x, int y) { + if (g_fullscreen) { + /* 全屏页:点任意处退出回主界面(左缘左滑由 SDK on_swipe 处理,见下) */ + set_fullscreen(0); + redraw(); + return; + } + for (int i = 0; i < 6; i++) { + if (meow_widget_hit(g_nbtn[i], x, y)) { + notif_send(i); + redraw(); + return; + } + } + if (meow_widget_hit(g_cancel, x, y)) { + notif_cancel(); + redraw(); + return; + } + if (meow_widget_hit(g_fs_btn, x, y)) { + set_fullscreen(1); + redraw(); + return; + } if (meow_widget_hit(g_btn, x, y)) { g_taps++; snprintf(g_btn_label, sizeof g_btn_label, "TAPPED x%d", g_taps); @@ -107,11 +245,18 @@ int main(void) signal(SIGTERM, on_sigterm); /* 看门狗返回键 → 干净退出 */ g_btn = meow_btn_create(120, 300, 240, 64, g_btn_label); + for (int i = 0; i < 6; i++) + g_nbtn[i] = meow_btn_create(3 + i * 80, 400, 74, 56, g_notif_labels[i]); + g_cancel = meow_btn_create(36, 464, 200, 42, "CANCEL LAST"); + g_fs_btn = meow_btn_create(244, 464, 200, 42, "FULLSCREEN"); redraw(); meow_ui_events ev = { on_key, on_tap, on_swipe, on_tick, on_swipe_progress }; meow_ui_run(&ev); + for (int i = 0; i < 6; i++) meow_widget_free(g_nbtn[i]); + meow_widget_free(g_cancel); + meow_widget_free(g_fs_btn); meow_widget_free(g_btn); meow_ui_shutdown(); meow_log(MEOW_LOG_INFO, "exit");