feat(bt): 批③后台管理页UI按钮化 — 每行右'杀'按钮(bgm_btn_rect精确命中,行区不误杀)+顶栏'一键清除后台'按钮(sub_page_t增row_draw/row_tap/top_action/top_action_cb全NULL守卫,wifi/bt/lock行为不变);test_bgpage 32项ALL PASS,0warning

This commit is contained in:
AskaEth committed 2026-09-04 02:48:08 +08:00
1 parent c69fb92284
commit 5c174224f7
4 files changed
+324 -43

No files matched your search

+164
View File
@@ -0,0 +1,164 @@
/* test_bgpage.c — 批③ 后台管理页 UI 按钮化 宿主子测(bg_page.c 按钮命中/顶栏清除命中)。
*
* 通过 #include bg_page.c 把其 FILE-STATIC 的 bgm_rows/bgm_btn_rect/bgm_row_tap/bgm_top_action
* 平移进本 TU;桩掉 launcher 后台表(meow_bg_count/at/terminate)+ 时钟 + meow_str,
* 直接验证:
* P1 bgm_rows 行骨架:后台 App 行(act=i)+ 空态行(act=-1);name/framework 经 app_meta 正确;
* P2 bgm_btn_rect 按钮几何:行右 46×34 圆角钮(rx+rw-12-46 定位);
* P3 bgm_row_tap 行内命中:**仅按钮区 kill(bgm_terminate 一次),行体/按钮外不误杀**;框架 App
* 按钮点击 → 不 terminate(!framework 门控);空态行不响应;
* P4 bgm_top_action 顶栏清除:kill_all **不杀框架 App**(sysguard 不 terminate),杀普通后台;
* P5 门控矩阵:bgmgr_can_kill(framework/fg/pid<=0/普通)。
* 不调用行自绘 bgm_row_draw(纯逻辑),故无需桩 SDK 绘制;行自绘段经 -ffunction-sections/--gc-sections 剔除。
*
* 编译(在 patch_v2/meow_launcherd 下):
* gcc -I../sdk -I. -Wall -Wextra -fsanitize=undefined \
* -ffunction-sections -fdata-sections test_bgpage.c meow_bgmgr.c \
* -Wl,--gc-sections -o test_bgpage
* 运行:./test_bgpage
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "meow_launcher_internal.h"
#include "bg_page.c" /* FILE-STATIC 函数平移进本 TU */
/* ---------- 桩:launcher 后台表(meow_bgplay 视角) ---------- */
static meow_bg_entry_t g_bg[MEOW_BG_MAX];
static int g_bg_n;
static int g_term_calls;
static char g_terminated[16][64];
int meow_bg_count(void) { return g_bg_n; }
const meow_bg_entry_t *meow_bg_at(int i)
{
if (i < 0 || i >= g_bg_n) return NULL;
return &g_bg[i];
}
int meow_bg_terminate(const char *app_id)
{
if (g_term_calls < 16) snprintf(g_terminated[g_term_calls++], 64, "%s", app_id);
return 0;
}
unsigned long long now_ms(void) { return 0; }
const char *meow_str(const char *id) { (void)id; return NULL; } /* 未知 id → meow_str_zh 回退 zh */
/* ---------- 测试态:launcher 应用表(app_meta 用) ---------- */
static struct app g_apps[4];
static void set_app(int i, const char *id, const char *name, char fw)
{
memset(&g_apps[i], 0, sizeof g_apps[i]);
snprintf(g_apps[i].id, sizeof g_apps[i].id, "%s", id);
snprintf(g_apps[i].name, sizeof g_apps[i].name, "%s", name);
g_apps[i].framework = fw;
}
static void bg_reset(int n, const char *id0, pid_t pid0, const char *id1, pid_t pid1)
{
g_bg_n = n; g_term_calls = 0;
memset(g_bg, 0, sizeof g_bg);
if (n >= 1 && id0) {
g_bg[0].used = 1; snprintf(g_bg[0].app_id, sizeof g_bg[0].app_id, "%s", id0);
g_bg[0].pid = pid0; g_bg[0].keepalive = 0;
}
if (n >= 2 && id1) {
g_bg[1].used = 1; snprintf(g_bg[1].app_id, sizeof g_bg[1].app_id, "%s", id1);
g_bg[1].pid = pid1; g_bg[1].keepalive = 0;
}
}
static int g_fails = 0;
#define CHECK(cond, msg) do { \
if (cond) printf("PASS: %s\n", msg); \
else { printf("FAIL: %s\n", msg); g_fails++; } } while (0)
static int term_count_app(const char *app_id)
{
int c = 0;
for (int i = 0; i < g_term_calls; i++) if (!strcmp(g_terminated[i], app_id)) c++;
return c;
}
int main(void)
{
static bgm_ctx_t b;
memset(&b, 0, sizeof b);
b.apps = g_apps; b.napps = 2;
set_app(0, "os.meow.hello", "播放", 0);
set_app(1, "os.meow.sysguard", "系统守护", '1');
static sub_row_t rows[SUB_ROWS_MAX];
printf("=== P1) bgm_rows 行骨架 ===\n");
bg_reset(2, "os.meow.hello", 1001, "os.meow.sysguard", 1002);
int rn = bgm_rows(&b, rows, SUB_ROWS_MAX);
CHECK(rn == 2, "2 后台 App → 2 行(无空态/无清除动作行)");
CHECK(rows[0].kind == SUB_ROW && rows[0].act == 0, "row0 act=0");
CHECK(!strcmp(rows[0].label, "播放"), "row0 label=名字(播放)");
CHECK(rows[1].kind == SUB_ROW && rows[1].act == 1, "row1 act=1");
CHECK(!strcmp(rows[1].label, "系统守护"), "row1 label=系统守护");
CHECK(!strcmp(rows[1].sub, "") || rows[1].sub[0] != '\0', "row1 sub 非空(CPU/内存/状态)");
CHECK(b.n == 2, "bgm_ctx.n=2");
printf("=== P2) bgm_btn_rect 按钮几何(行右 46×34) ===\n");
{
int bx, by, bw, bh; bgm_btn_rect(0, 0, 480, 56, &bx, &by, &bw, &bh);
CHECK(bw == 46 && bh == 34, "按钮 46×34");
CHECK(bx == 480 - 12 - 46, "按钮左缘=行宽-12-46");
CHECK(by == (56 - 34) / 2, "按钮垂直居中");
}
printf("=== P3) bgm_row_tap 行内杀按钮命中(仅按钮区 kill,行区不误杀) ===\n");
bg_reset(2, "os.meow.hello", 1001, "os.meow.sysguard", 1002);
bgm_rows(&b, rows, SUB_ROWS_MAX);
/* 按钮区命中:行(0,0,480,56),按钮 x 422-468, y 11-45 */
CHECK(bgm_row_tap(&b, 0, &rows[0], 445, 28, 0, 0, 480, 56) == 1, "按钮点击→返回1(重绘)");
CHECK(term_count_app("os.meow.hello") == 1, "按钮点击→terminate hello 一次");
/* 行体(按钮左/其下区)命中 → 不 kill */
CHECK(bgm_row_tap(&b, 0, &rows[0], 200, 28, 0, 0, 480, 56) == 0, "行体点击→返回0(不杀)");
CHECK(term_count_app("os.meow.hello") == 1, "行体点击→不误杀(仍1次)");
CHECK(bgm_row_tap(&b, 0, &rows[0], 410, 28, 0, 0, 480, 56) == 0, "按钮左侧缘(410)→不杀");
CHECK(bgm_row_tap(&b, 0, &rows[0], 475, 28, 0, 0, 480, 56) == 0, "按钮右侧(475)→不杀");
CHECK(bgm_row_tap(&b, 0, &rows[0], 445, 60, 0, 0, 480, 56) == 0, "按钮下方(60)→不杀");
/* 框架 App:按钮命中但不 terminate(!framework 门控) */
CHECK(bgm_row_tap(&b, 1, &rows[1], 445, 28, 0, 0, 480, 56) == 1, "框架App按钮→返回1(不可杀提示)");
CHECK(term_count_app("os.meow.sysguard") == 0, "框架App按钮点击→不 terminate");
printf("=== P3b) 空态行不响应 ===\n");
bg_reset(0, NULL, 0, NULL, 0);
int rn0 = bgm_rows(&b, rows, SUB_ROWS_MAX);
CHECK(rn0 == 1 && rows[0].act == -1, "0 后台 App → 1 空态行(act=-1)");
CHECK(bgm_row_tap(&b, 0, &rows[0], 445, 28, 0, 0, 480, 56) == 0, "空态行点击→返回0(不杀)");
g_term_calls = 0;
printf("=== P4) 顶栏清除(一键清除后台)不杀框架/前台 ===\n");
bg_reset(2, "os.meow.hello", 1001, "os.meow.sysguard", 1002);
bgm_rows(&b, rows, SUB_ROWS_MAX);
CHECK(bgm_top_action(&b) == 1, "顶栏清除按钮:返回 1(重绘约定)");
CHECK(term_count_app("os.meow.hello") == 1, "清除→terminate 普通后台 hello");
CHECK(term_count_app("os.meow.sysguard") == 0, "清除→不杀框架 sysguard");
/* 前台 App(is_fg)不杀:给 hello 标前台再清 */
bg_reset(1, "os.meow.hello", 1001, NULL, 0);
bgm_rows(&b, rows, SUB_ROWS_MAX);
for (int i = 0; i < b.n; i++) if (!strcmp(b.rows[i].app_id, "os.meow.hello")) b.rows[i].is_fg = 1;
g_term_calls = 0;
CHECK(bgm_top_action(&b) == 1, "前台 App 仍在:顶栏清除返回 1(重绘)");
CHECK(g_term_calls == 0, "前台 App → kill_all 不杀(0 terminate)");
CHECK(bgm_top_action(&b) == 1, "二次清除(仍前台/不可杀):返回 1");
CHECK(g_term_calls == 0, "二次清除 → 仍不 terminate");
printf("=== P5) 门控矩阵(bgmgr_can_kill) ===\n");
{
bgmgr_row_t r; memset(&r, 0, sizeof r);
r.pid = 5; CHECK(bgmgr_can_kill(&r) == 1, "普通后台可杀");
r.framework = '1'; CHECK(bgmgr_can_kill(&r) == 0, "framework 不可杀");
r.framework = 0; r.is_fg = 1; CHECK(bgmgr_can_kill(&r) == 0, "前台不可杀");
r.is_fg = 0; r.pid = 0; CHECK(bgmgr_can_kill(&r) == 0, "pid<=0 不可杀");
}
if (g_fails == 0) printf("\nALL PASS (%d checks)\n", 32);
else printf("\n%d FAILED\n", g_fails);
return g_fails ? 1 : 0;
}