sync(SDK): 增量同步主仓 M6.37–M6.39 至公开 SDK 仓

sdk/:
- 同步 meow_ui_widget/input/gfx/lazygrid/audio/media/img 等源码与头
  (SDK 默认列表/容器控件默认 MD3 — meow_list_set_container 可回退;
   全局 App 内底部上滑回桌面 — meow_ui_input_is_home_swipe 系统保留手势;
   LazyGrid/LazyColumn/LazyRow MD3 化;叠加让位自抑改 app_id 判定;
   DSD 音频格式等)
- 新增独立模块源码 meow_img_color / meow_lyric / meow_lyric_view 及对应宿主 test_*.c
- 保留公开仓自包含适配:vendored meow_font.c/meow_font.h/meow_notif.h 不动;
  build_sdk.sh 自包含版本不动;meow_ui_gfx.c 仅改 meow_font.h include 路径;
  meow_ui_internal.h 去除 FreeType 内部声明
- meow_ipc.h 同步到主仓 launcher 版本(含 AUDIO_FMT_DOP/媒体歌词/蓝牙输出协议)
- 不含 FreeType 矢量字 meow_ft_*(需 freetype vendor,公开仓以位图 meow_font
  自包含);不含 mipsel 二进制 / .o / .a / 固件 / 密钥 / devdocs

examples/hello/:
- 新增 ui/demo/sdk2/sdk2.c;build_hello.sh 纳入该文件(保持自包含)

docs / README / .gitignore:
- docs/MEOW_APP_SDK.md 补 §12.5(默认 MD3 容器 + 底部上滑回桌面 + 两个新 API)
- README 能力清单补「默认 MD3 容器」与「底部上滑回桌面」
- .gitignore 补新增宿主测试二进制

验证:sdk/meow_ui.a 与 examples/hello/hello 交叉编译均 0 warning;工作区无生成物。
This commit is contained in:
AskaEth committed 2026-09-04 18:05:36 +08:00
1 parent a1687486bc
commit c0396e40ce
45 files changed
+4665 -175

No files matched your search

+75 -10
View File
@@ -12,7 +12,7 @@
#include "meow_ui_internal.h"
#include "meow_ui_sys.h"
#include "sb_icons.h"
#include "meow_font.h" /* 公开 SDK 仓内 vendored(include/meow_font.h),不再引主仓 launcher 头 */
#include "meow_font.h"
#include <stdio.h>
#include <stdlib.h>
@@ -830,6 +830,17 @@ int meow_ui_text_height(int size)
return 7 * fallback_scale(size);
}
/* ================= 矢量字(FreeType)渲染薄封装(§10.1) =================
* meow_ft_text 在 meow_ui_ft.c(独立 .o,App 显式调 meow_ft_* 才拉取整条 FreeType 依赖),
* 它经本处两个薄封装写进 back_buf:blend 一个灰度像素(过 clip)、标一块脏区。
* 这两函数在 gfx.o 里(任何 App 本就拉取 gfx.o),ft.o 引用它们不引入新的未拉入成员,
* 从而保证「不调 meow_ft_* 的 App 零增量」(freetype .o 不会被拉入)。 */
void meow_gfx_ft_blend_px(int x, int y, uint32_t color, int alpha)
{ put_px_blend(x, y, color, alpha); }
void meow_gfx_ft_dirty(int x, int y, int w, int h)
{ dirty_add(x, y, w, h); }
/* ================= RGBA blit(图片层用) ================= */
void meow_gfx_blit_rgba(int x, int y, int w, int h, const uint8_t *rgba, int alpha)
{
@@ -963,13 +974,33 @@ static int statusbar_touched(void)
return 0;
}
/* ---- §10.5 叠加让位自抑(present 层)----
* /tmp/meow_notif_active 存在 = 通知中心叠加会话进行中(launcher 正在 fb 上渲染面板)。
* App 进程(非系统 UI 渲染者)此时不上屏;200ms 节流缓存存在性(别每帧 stat)。
/* ---- §10.5 叠加让位自抑(present / input 共用判定)----
* /tmp/meow_notif_active = 前台屏幕归属标记,**内容=当前前台 app_id**(空=菜单/叠加层覆盖/
* 无前台单元,即「抑制全部 App」)。App 进程(非系统 UI 渲染者)据此判「我是否前台」:
* - 内容==本进程 app_id(env MEOW_LOG_APP)→ 前台 → 照常上屏 / 收输入;
* - 内容为空 → 菜单前台或被叠加层覆盖 → 全抑制(含自身);
* - 内容为其它 app_id → 后台常驻(批①多 App)/非前台 → 自抑上屏 + 排空输入。
* 200ms 节流缓存存在性+内容(别每帧 open/stat)。
* 计数 g_overlay_suppressed 供宿主单测断言(meow_gfx_overlay_suppressed_count)。 */
static unsigned long long g_overlay_suppressed = 0;
/* §后台化保活-残帧:记录「上一次 present 是否处于叠加自抑态」,用于在抑制→不抑制的恢复边沿
* 强制整帧重画(盖掉 launcher 在后台化期间画进 buffer0 的桌面/主界面帧)。 */
static int g_was_overlay_suppressed = 0;
static int overlay_present_suppressed(void)
/* 本进程 app_id(env MEOW_LOG_APP,launcher 注入)= 判「我是否前台」的身份锚。 */
static const char *overlay_own_app(void)
{
static const char *s = NULL;
if (!s) {
const char *e = getenv("MEOW_LOG_APP");
s = (e && e[0]) ? e : "";
}
return s;
}
/* §批①多 App 后台常驻:present 层与 input 层共用的「是否自抑」判定(单一实现,防两端漂移)。
* 系统 UI(launcher 渲染面板/主界面)恒 0。返回 1=本进程应自抑上屏+排空输入。 */
int meow_ui_overlay_suppressed_active(void)
{
if (meow_ui_sys_render_enabled()) return 0; /* launcher(系统 UI)渲染面板,照常上屏 */
static char s_path[108];
@@ -984,7 +1015,29 @@ static int overlay_present_suppressed(void)
unsigned long long now = now_ms();
if (s_last_chk && now - s_last_chk < MEOW_OVERLAY_CHK_MS) return s_last_res;
s_last_chk = now;
s_last_res = (access(s_path, F_OK) == 0) ? 1 : 0;
{
char owner[48];
int have = 0;
owner[0] = 0;
int fd = open(s_path, O_RDONLY);
if (fd >= 0) {
ssize_t n = read(fd, owner, sizeof(owner) - 1);
close(fd);
if (n > 0) owner[n] = 0;
have = 1; /* 文件存在(无论内容)→ 处于抑制管控 */
} else {
have = 0; /* 文件不存在 → 无抑制 */
}
if (!have) {
s_last_res = 0;
} else if (owner[0] == 0) {
s_last_res = 1; /* 空内容=全抑制(菜单前台/叠加层覆盖) */
} else {
const char *me = overlay_own_app();
/* 内容==本进程 app_id → 前台不抑制;否则(后台常驻/非前台)→ 抑制 */
s_last_res = (strcmp(owner, me) == 0) ? 0 : 1;
}
}
return s_last_res;
}
@@ -995,10 +1048,22 @@ static void present(void)
if (!g_init_ok || !g_back_buf) return;
if (!(g_dirty_full || g_ndirty > 0)) return;
/* §10.5 叠加让位自抑(仅 App 进程):App 前台播放中唤起通知中心时 launcher 不 SIGSTOP
* (保 PCM 供流,App 播放线程同进程),改由 App 进程在此自抑上屏——绘制照常进 back_buf,
* 只是不 present 到 fb,防 App 重绘穿透 launcher 叠加层。系统 UI 进程(launcher 渲染面板)
* 不抑制。抑制期脏区保留累积(超上限自然升级整帧),标记消失后下一次 present 一次上屏。 */
if (overlay_present_suppressed()) { g_overlay_suppressed++; return; }
* (保 PCM 供流,ncm 播放线程同进程),改由 App 进程在此自抑上屏——绘制照常进 back_buf,
* 只是不 present 到 fb,防 App 重绘穿透 launcher 叠加层;后台常驻(批①)App 同判据自抑。
* 系统 UI 进程(launcher 渲染面板)不抑制。抑制期脏区保留累积(超上限自然升级整帧),
* 判定为「回到前台」后下一次 present 一次上屏。 */
if (meow_ui_overlay_suppressed_active()) { g_overlay_suppressed++; g_was_overlay_suppressed = 1; return; }
/* §后台化保活-残帧:抑制→不抑制的**恢复边沿**强制整帧重画。App 被 launcher 转后台保活
* (/tmp/meow_notif_active 存在)期间 present 被自抑,back_buf 仍保留 App 自己的完整帧;
* 但 launcher 已把桌面/主界面整帧画进 buffer0 盖在 App 残帧上。恢复前台时若只 present
* 抑制期累积的小脏区(时钟/状态栏),launcher 的桌面帧会在 App 未重画区域透出(真机
* 「桌面叠在 ncm UI 下面/旧播放界面层叠」。标记由有→无即「回到前台」,强制 dirty_full
* 让下一次 present 把 App 完整 back_buf 一次上屏,盖掉桌面帧。仅真实 App 进程(launcher
* 系统 UI 恒不抑制,本边沿不触发)。 */
if (g_was_overlay_suppressed) {
g_was_overlay_suppressed = 0;
dirty_full();
}
/* 帧率门控(A-1/A-2,从 launcher 迁入):present 距上次 ≥ period(1000/eff_rate) 才呈现;
* 未满周期则保留脏区(不 dirty_reset),下一轮再试。refresh_always_max=1 时跳过门控(恒满速)。 */
unsigned long long now = now_ms();