Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_np_cover.c
T

200 lines
10 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.
/* test_np_cover.c — M6.33 播放页/歌词页封面 lifecycle 宿主验证。
*
* 背景:ncm 状态切换可能先上报空 artwork(媒体会话 artwork 短暂为空/换源),随后复原;
* launcher 侧封面渲染在 now_playing.c(静态 np_cover_load / run_now_playing 的 meta_changed)。
* 本测试验证两处 M6.33 修复的语义:
* np_cover_load 缓存决策:artwork 变化重载;artwork 为空→清封面(回退主题占位);
* 同路径但封面为空(此前加载失败/空清空后)→ 允许重试重载(旧逻辑「路径未变即跳过」会卡死)。
* run_now_playing meta_changed:补 artwork 追踪,artwork-only 变化也触发整页重绘。
*
* 说明:np_cover_load 为 now_playing.c 内 static(launcher TU,宿主不可链),故本测试按项目
* mirror 惯例(同 test_now_playing_widgets 镜像几何)逐字镜像其决策,用**真实 SDK 图片加载**(
* meow_img_load_file/meow_img_free + stb_image)驱动真实 BMP,验证 artwork 生命周期。
*
* 编译(在 patch_v2/meow_launcherd 下;链法同 test_now_playing_widgets + meow_img_color):
* gcc -Wall -Wextra -o test_np_cover test_np_cover.c \
* ../sdk/test_host_stub.c ../sdk/meow_ui_gfx.c ../sdk/meow_ui_sys.c \
* ../sdk/meow_ui_theme.c ../sdk/meow_ui_vol.c ../sdk/meow_ui_log.c \
* ../sdk/meow_ui_widget.c ../sdk/meow_ui_input.c ../sdk/meow_ui_activity.c \
* ../sdk/meow_ui_dialog.c ../sdk/meow_ui_ime.c ../sdk/meow_ui_str.c ../sdk/meow_pinyin.c \
* ../sdk/meow_ui_draw.c ../sdk/meow_ui_view.c ../sdk/meow_ui_box.c ../sdk/meow_ui_anim.c \
* ../sdk/meow_ui_scroll.c ../sdk/meow_ui_img.c ../sdk/meow_ui_media.c \
* ../sdk/meow_notify_ipc.c ../sdk/stb_image.c ../sdk/meow_lyric.c ../sdk/meow_lyric_view.c \
* ../sdk/meow_img_color.c \
* -I../sdk -I. -DMEOW_UI_HOST_TEST -pthread -lm
* 运行:./test_np_cover
*/
#include "meow_ui.h"
#include "meow_media.h" /* meow_media_session_t(取 artwork 字段) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 局部补全 meow_img(与 meow_ui_img.c / meow_img_color.c 布局一致):读取已加载封面尺寸。 */
struct meow_img { int w, h; unsigned char *rgba; };
static int img_w(meow_img *im) { return im ? ((struct meow_img *)im)->w : 0; }
static int img_h(meow_img *im) { return im ? ((struct meow_img *)im)->h : 0; }
static int g_fail = 0;
#define CHECK(cond, name) do { \
if (cond) printf(" PASS %s\n", name); \
else { printf(" FAIL %s (%s:%d)\n", name, __FILE__, __LINE__); g_fail++; } } while (0)
/* ================= M6.33 镜像 np_cover_load(now_playing.c 逐字语义) ================= */
static meow_img *g_np_cover = NULL;
static char g_np_cover_path[200] = "";
static void np_cover_load(const meow_media_session_t *s)
{
if (!s) return;
if (g_np_cover && strcmp(g_np_cover_path, s->artwork) == 0) return; /* 已载且未变 → 跳过 */
if (g_np_cover) { meow_img_free(g_np_cover); g_np_cover = NULL; }
snprintf(g_np_cover_path, sizeof g_np_cover_path, "%s", s->artwork);
if (!s->artwork[0]) return;
char path[240];
if (s->artwork[0] == '/') snprintf(path, sizeof path, "%s", s->artwork);
else snprintf(path, sizeof path, "/usr/data/mnt/sd_0/%s", s->artwork);
g_np_cover = meow_img_load_file(path);
}
/* ================= M6.33 镜像 run_now_playing meta_changed(补 artwork 追踪) ========= */
static int meta_changed_needs_redraw(const char *last_app, const char *last_title,
uint32_t last_state, const char *last_art,
const meow_media_session_t *s)
{
if (!s) return 1; /* 源消失 → 空态重画 */
return strcmp(last_app, s->app_id) || strcmp(last_title, s->title) ||
strcmp(last_art, s->artwork) || last_state != s->state;
}
/* ============ 小工具:写 24-bit 无压缩 BMP 到 path(stb_image 可读),纯色填充 ============
* 结构:BITMAPFILEHEADER(14) + BITMAPINFOHEADER(40) + 像素(bottom-up,BGR,行对齐 4B)。 */
static void write_bmp(const char *path, int w, int h, int r, int g, int b)
{
int rowPitch = (w * 3 + 3) & ~3;
int imgSize = rowPitch * h;
int fileSize = 54 + imgSize;
unsigned char hdr[54];
memset(hdr, 0, sizeof hdr);
hdr[0] = 'B'; hdr[1] = 'M';
hdr[2] = (unsigned char)(fileSize & 0xFF);
hdr[3] = (unsigned char)((fileSize >> 8) & 0xFF);
hdr[4] = (unsigned char)((fileSize >> 16) & 0xFF);
hdr[5] = (unsigned char)((fileSize >> 24) & 0xFF);
hdr[10] = 54;
hdr[14] = 40;
hdr[18] = (unsigned char)(w & 0xFF);
hdr[19] = (unsigned char)((w >> 8) & 0xFF);
hdr[22] = (unsigned char)(h & 0xFF);
hdr[23] = (unsigned char)((h >> 8) & 0xFF);
hdr[24] = (unsigned char)((h >> 16) & 0xFF);
hdr[25] = (unsigned char)((h >> 24) & 0xFF);
hdr[26] = 1; hdr[28] = 24; /* planes=1, bpp=24 */
hdr[34] = (unsigned char)(imgSize & 0xFF);
hdr[35] = (unsigned char)((imgSize >> 8) & 0xFF);
hdr[36] = (unsigned char)((imgSize >> 16) & 0xFF);
hdr[37] = (unsigned char)((imgSize >> 24) & 0xFF);
FILE *f = fopen(path, "wb");
if (!f) { printf(" !! cannot write %s\n", path); exit(1); }
fwrite(hdr, 1, sizeof hdr, f);
unsigned char *row = (unsigned char *)malloc((size_t)rowPitch);
memset(row, 0, (size_t)rowPitch);
for (int x = 0; x < w; x++) { row[x * 3 + 0] = (unsigned char)b; row[x * 3 + 1] = (unsigned char)g; row[x * 3 + 2] = (unsigned char)r; }
for (int y = 0; y < h; y++) fwrite(row, 1, (size_t)rowPitch, f);
free(row);
fclose(f);
}
int main(void)
{
setbuf(stdout, NULL);
setenv("MEOW_UI_DUMP", "/tmp/npcover.ppm", 1);
meow_ui_opts o = { 480, 720 };
if (meow_ui_init(&o) != 0) { printf(" FAIL meow_ui_init\n"); return 1; }
meow_ui_activity_push(0x57);
/* 两张真实封面文件:A=蓝,B=红 */
const char *pa = "/tmp/np_cover_a.bmp", *pb = "/tmp/np_cover_b.bmp";
const char *pgone = "/tmp/np_cover_missing.bmp"; /* 先不存在 → 加载失败 */
write_bmp(pa, 16, 16, 0x40, 0x80, 0xC0); /* 蓝 16x16 */
write_bmp(pb, 12, 12, 0xC0, 0x40, 0x40); /* 红 12x12(尺寸不同,便于断言「已替换」) */
meow_media_session_t s; memset(&s, 0, sizeof s);
s.used = 1; s.state = MEOW_MEDIA_PLAYING;
strcpy(s.app_id, "ncm"); strcpy(s.title, "song"); strcpy(s.artist, "artist");
/* ============ C1 artwork 有 → 封面载入(播放页/歌词页共用 g_np_cover) ============ */
printf("C1 artwork present -> cover loads\n");
memset(g_np_cover_path, 0, sizeof g_np_cover_path);
strcpy(s.artwork, pa);
np_cover_load(&s);
CHECK(g_np_cover != NULL, "artwork present -> cover loaded (non-NULL)");
CHECK(img_w(g_np_cover) == 16 && img_h(g_np_cover) == 16, "cover is 16x16");
/* 同路径未变 → 缓存命中,不重载(指针不变) */
meow_img *keep = g_np_cover;
np_cover_load(&s);
CHECK(g_np_cover == keep, "same path unchanged -> cache hit (no reload)");
/* ============ C2 artwork 空 → 封面清空(回退主题占位) ============ */
printf("C2 artwork empty -> cover cleared (theme placeholder)\n");
memset(s.artwork, 0, sizeof s.artwork);
np_cover_load(&s);
CHECK(g_np_cover == NULL, "artwork empty -> cover NULL (theme placeholder)");
CHECK(g_np_cover_path[0] == 0, "empty -> cached path reset to \"\"");
/* ============ C3 artwork 从空复原(同路径)→ 封面重载(M6.33 修复) ============ */
printf("C3 artwork restored (same path) -> cover reloads (M6.33)\n");
strcpy(s.artwork, pa);
np_cover_load(&s);
CHECK(g_np_cover != NULL, "restore from empty -> cover reloaded");
CHECK(img_w(g_np_cover) == 16, "reloaded cover intact");
/* ============ C4 换源(A→B 另一路径)→ 封面替换 ============ */
printf("C4 artwork switch (A->B) -> cover replaced\n");
strcpy(s.artwork, pb);
np_cover_load(&s);
CHECK(g_np_cover != NULL, "switch to B -> cover loaded");
/* 用尺寸(而非指针身份,malloc 会复用地址)证明确实换成 B */
CHECK(img_w(g_np_cover) == 12 && img_h(g_np_cover) == 12, "cover replaced by B (12x12)");
CHECK(strcmp(g_np_cover_path, pb) == 0, "cache path updated to B");
/* ============ C5 首载失败同路径重报 → 重试成功(M6.33 修复) ============ */
printf("C5 first load fails then same-path re-report -> retry succeeds (M6.33)\n");
memset(g_np_cover_path, 0, sizeof g_np_cover_path);
if (g_np_cover) { meow_img_free(g_np_cover); g_np_cover = NULL; }
/* 缺失文件首载失败:cover NULL, cache path=missing */
strcpy(s.artwork, pgone);
np_cover_load(&s);
CHECK(g_np_cover == NULL, "nonexistent path -> cover NULL");
CHECK(strcmp(g_np_cover_path, pgone) == 0, "cache path = missing (recorded)");
/* 文件此刻出现,仍同路径重报 → 旧逻辑「路径未变即跳过」卡死;新逻辑 g_np_cover==NULL 重试 */
write_bmp(pgone, 8, 8, 0x20, 0xE0, 0x20); /* 绿 */
np_cover_load(&s);
CHECK(g_np_cover != NULL, "same path + cover NULL -> reload succeeds");
CHECK(img_w(g_np_cover) == 8, "retried cover is 8x8");
remove(pgone);
/* ============ C6 meta_changed 补 artwork:artwork-only 变化也触发整页重绘 ============ */
printf("C6 meta_changed tracks artwork (M6.33)\n");
memset(&s, 0, sizeof s); s.used = 1; s.state = MEOW_MEDIA_PLAYING;
strcpy(s.app_id, "ncm"); strcpy(s.title, "song"); strcpy(s.artwork, pa);
CHECK(meta_changed_needs_redraw("ncm", "song", MEOW_MEDIA_PLAYING, pa, &s) == 0,
"no change -> no redraw");
/* 仅 artwork 变化(app/title/state 全同)→ 旧逻辑=0(不重绘→封面卡空);新逻辑=1 */
CHECK(meta_changed_needs_redraw("ncm", "song", MEOW_MEDIA_PLAYING, "", &s) == 1,
"artwork-only change -> redraw (was missed before M6.33)");
CHECK(meta_changed_needs_redraw("ncm", "song", MEOW_MEDIA_PLAYING, pb, &s) == 1,
"artwork path switch -> redraw");
CHECK(meta_changed_needs_redraw("ncm", "song", MEOW_MEDIA_PLAYING, pa, &s) == 0,
"same art same title -> no redraw");
/* 清理 */
if (g_np_cover) { meow_img_free(g_np_cover); g_np_cover = NULL; }
remove(pa); remove(pb);
meow_ui_activity_pop();
meow_ui_shutdown();
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
return g_fail;
}