Files
MeowOS-For-R3P2/patch_v2/hello_app/hello.c
T

266 lines
11 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.
/* hello.c — MeowOS SDK 版示例应用(链 meow_ui.a,B1)。
*
* 契约(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);
* - 左缘左滑(抬手触发)→ 请求退出(回应用列表);滑动过程顶部出现随位移增长的进度条;
* - 空闲时 on_tick 每秒刷新一行状态(含运行秒数)。
*
* 宿主/qemu 离屏:设 MEOW_UI_DUMP=<ppm 路径> 时,首帧 flush 即把 back_buf 写成
* PPM 截图供检查;设备上无副作用。
*
* Build(见 build_hello.sh):
* zig-mipsel-cc -Os -static hello.c meow_ui.a libz.a -lpthread -o hello
*/
#include "meow_ui.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
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";
/* M2.51:统一日志改用 SDK meow_log()(按 app 分离 + 级别过滤 + 降级),
* 删除自造轮子的 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 + icon(SDK 结构含 icon 字段;NULL/空=用 app 默认图标) */
label = "TGT";
n.cat = MEOW_NOTIFY_CAT_MESSAGE;
n.title = "测试-跳转Activity";
n.body = "点击跳转 target_activity=main";
n.timeout_ms = 6000;
n.target_activity = "main";
n.icon = NULL; /* 空 → launcher 用 app 默认图标(app.json icon) */
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, 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);
/* 重建按钮标签(release 旧控件,重新 create 保持几何) */
meow_widget_free(g_btn);
g_btn = meow_btn_create(120, 300, 240, 64, g_btn_label);
redraw();
}
}
static void on_key(int keycode, int is_down)
{
/* §3.4.1:物理键语义由系统统一管理,APP 禁映射(电源=息屏/亮屏、音量=调音量、播放=媒体)。
* 这里仅记录日志,不做任何 exit/confirm 行为。 */
(void)keycode; (void)is_down;
meow_log(MEOW_LOG_DEBUG, "key"); /* 不处理:SDK 内部消化系统键语义 */
}
static void on_swipe_progress(int x_start, int dx)
{
/* 左滑过程实时回调:SDK 已自动画顶部进度条;这里演示 app 侧接入(画同长度条,幂等——
* 长度=当前 X=x_start+dx,与 SDK 自动画一致,不会误清条)。
* 抬手达标时 SDK 清条 + 触发 on_swipe(LEFT)→退出。 */
meow_ui_swipe_hint(x_start + dx);
}
static void on_swipe(int dir, int dx, int dy)
{
(void)dx; (void)dy;
if (dir == MEOW_SWIPE_LEFT) { meow_log(MEOW_LOG_INFO, "exit:swipe"); meow_ui_request_exit(); }
}
static void on_tick(void)
{
/* 每秒刷新一次状态行(避免 16ms 高频重绘) */
static uint64_t last = 0;
uint64_t now = meow_ui_time_ms();
if (now - last >= 1000) {
last = now;
g_secs++;
redraw();
}
}
int main(void)
{
meow_log(MEOW_LOG_INFO, "start");
meow_ui_opts o = { 480, 720 };
if (meow_ui_init(&o) != 0) { meow_log(MEOW_LOG_ERROR, "init failed"); return 1; }
/* M2.46 不再强制 set_mode 深色——主题跟随系统 display.theme/theme_mode(manual/auto+时段),
* 与 launcher s_ui_theme() 判定对齐(meow_theme_get() 已读 settings.conf)。 */
meow_theme_add_listener(NULL); /* noop: 预留主题变化重绘 */
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");
return 0;
}