/* now_playing.c — 阶段D附录B:Now Playing 大页(主界面横划进入;左缘右滑返回)。 * * 定案(用户):Now Playing = 通知中心媒体卡片 + 主界面横划进入的播放页,两者都做。 * 本文件实现后者:封面大图 + 元数据 + 进度 + 控制按钮 + 歌词占位;返回手势回主界面。 * 数据源:meow_media 会话(最近活跃媒体源);空态=占位。参照 SDK §5.2 横向分页模板的 * 手势分流(左缘返回 / 顶部下滑通知中心 / 中部横滑内容)——本页只接管「中部/右缘向左滑进、 * 左缘右滑返回」,与全局手势不冲突。 * * 性能:封面解码缓存(按 artwork 路径变化重载,不每帧解码);整页 1s 刷新进度(墙钟推进), * 元数据/源变化立即整页重画;交互只重绘按钮/进度带。 */ #include "meow_launcher_internal.h" #define NP_COVER 300 /* 封面边长(方,居中) */ #define NP_COVER_X ((fb_xres - NP_COVER) / 2) #define NP_COVER_Y 60 #define NP_TITLE_Y 412 #define NP_ARTIST_Y 450 #define NP_ALBUM_Y 480 #define NP_PROG_X 40 #define NP_PROG_W (fb_xres - 80) #define NP_PROG_Y 518 #define NP_TIME_Y 492 #define NP_BTN_Y 568 /* 控制按钮中心 y */ #define NP_PLAY_CX (fb_xres / 2) #define NP_PREV_CX (NP_PLAY_CX - 78) #define NP_NEXT_CX (NP_PLAY_CX + 78) #define NP_PLAY_R 30 #define NP_PREV_R 22 #define NP_LYRIC_Y 640 static meow_img *g_np_cover = NULL; static char g_np_cover_path[200] = ""; /* 封面解码缓存(artwork 路径变化才重载)。 */ static void np_cover_load(const meow_media_session_t *s) { if (!s) return; if (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[200]; 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); } #if 0 /* ================================================================ * M7.0b 退役:Now Playing 手绘控制钮/进度条改走 SDK 控件(meow_iconbtn + * meow_progress),命中/状态/进度全由 SDK 接管;保留作回退位(删除 #if 0 行恢复旧手绘)。 * ================================================================ */ /* 实心三角(dir=+1 右向 / -1 左向)。 */ static void np_tri(int cx, int cy, int size, int dir, uint32_t col) { int half = size / 2; for (int dy = -half; dy <= half; dy++) { int w = half + 1 - (dy < 0 ? -dy : dy); if (w <= 0) continue; int x0 = cx + (dir > 0 ? -w / 2 : w / 2 - w); fill_rect(x0, cy + dy, w, 1, col); } } /* 圆形控制按钮(kind:0=prev 1=play 2=next 3=pause)。 */ static void np_btn(int cx, int cy, int r, int kind, const meow_ui_theme_t *th) { meow_gfx_fill_round(cx - r, cy - r, r * 2, r * 2, r, th->primary); uint32_t fg = 0xFFFFFF; if (kind == 0) { np_tri(cx + 5, cy, r - 5, -1, fg); fill_rect(cx - 4, cy - (r - 7), 4, (r - 7) * 2, fg); } else if (kind == 1) { np_tri(cx + 3, cy, r - 3, 1, fg); } else if (kind == 2) { np_tri(cx - 5, cy, r - 5, 1, fg); fill_rect(cx + 2, cy - (r - 7), 4, (r - 7) * 2, fg); } else { int bw = (r - 8) / 2; if (bw < 2) bw = 2; fill_rect(cx - 8, cy - (r - 7), bw, (r - 7) * 2, fg); fill_rect(cx + 8 - bw, cy - (r - 7), bw, (r - 7) * 2, fg); } } #endif /* M7.0b 退役:Now Playing 旧手绘控制钮 */ /* 居中 + 按宽截断(UTF-8 安全),防超长标题溢出屏外。(M7.0b 保留:封面/歌名/艺术家仍 SD) */ static void np_center_text(int y, const char *s, int size, uint32_t color, int maxw) { if (!s) s = ""; int W = fb_xres; if (ui_width(s, size) <= maxw) { ui_draw((W - ui_width(s, size)) / 2, y, s, color, size); return; } /* 近似截断:实际按字节长度比例切(title/artist 罕见超长,够用不裂屏) */ char buf[160]; int keep = (int)(strlen(s) * maxw / (ui_width(s, size) + 1)); if (keep < 0) keep = 0; if (keep > (int)sizeof buf - 4) keep = (int)sizeof buf - 4; memcpy(buf, s, (size_t)keep); buf[keep] = 0; strcat(buf, "..."); ui_draw((W - ui_width(buf, size)) / 2, y, buf, color, size); } /* ================================================================== * M7.0b Now Playing 控件化(launcher 无 meow_ui_run,手动驱动 SDK 控件): * - 进度条 → meow_progress(线性,SDK 主题 track/fill); * - 播放控制三钮 → meow_iconbtn(PREV / PLAY_ARROW|PAUSE / NEXT;按下=PAUSE、暂停=PLAY_ARROW, * 同位置叠两钮、按当前状态只画其一); * - 命中走 meow_widget_hit(圆形,owner==哨兵 + enabled 闸门)→ meow_media_playctl 分发; * - 封面(meow_img contain)与歌名/艺术家(meow_font)不动(本就 SD),仅文案走 meow_str。 * 控件 lazy 创建一次(owner=NP_SENTINEL_ACT),跨多次进入复用;run_now_playing() 进入 push * 哨兵、退出 pop(owner 闸门使控件命中生效)。 * ================================================================== */ #define NP_SENTINEL_ACT 0x51 /* Now Playing 哨兵 activity */ static meow_widget *g_np_prog = NULL; static meow_widget *g_np_prev = NULL, *g_np_play = NULL, *g_np_pause = NULL, *g_np_next = NULL; static int g_np_init = 0; static void np_widgets_create(void) { meow_ui_activity_push(NP_SENTINEL_ACT); g_np_prog = meow_progress_create(NP_PROG_X, NP_PROG_Y, NP_PROG_W, 6, 0); g_np_prev = meow_iconbtn_create(NP_PREV_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R, NP_PREV_R * 2, MEOW_ICON_SKIP_PREV); g_np_play = meow_iconbtn_create(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R, NP_PLAY_R * 2, MEOW_ICON_PLAY_ARROW); g_np_pause = meow_iconbtn_create(NP_PLAY_CX - NP_PLAY_R, NP_BTN_Y - NP_PLAY_R, NP_PLAY_R * 2, MEOW_ICON_PAUSE); g_np_next = meow_iconbtn_create(NP_NEXT_CX - NP_PREV_R, NP_BTN_Y - NP_PREV_R, NP_PREV_R * 2, MEOW_ICON_SKIP_NEXT); /* 主播放钮保持「强调动作」观感:底色=primary、图标=onPrimary;其余两钮默认 surfaceContainerLow。 */ const meow_theme *th = meow_theme_get(); meow_widget_opts op; memset(&op, 0, sizeof op); op.bg = th->primary; op.fg = th->onPrimary; if (g_np_play) meow_widget_set_opts(g_np_play, &op); if (g_np_pause) meow_widget_set_opts(g_np_pause, &op); meow_ui_activity_pop(); g_np_init = 1; } /* 主题刷新:播放钮底色/图标随当前主题(明暗/风格切换后跟手)。 */ static void np_refresh_theme(void) { if (!g_np_init) return; const meow_theme *th = meow_theme_get(); meow_widget_opts op; memset(&op, 0, sizeof op); op.bg = th->primary; op.fg = th->onPrimary; if (g_np_play) meow_widget_set_opts(g_np_play, &op); if (g_np_pause) meow_widget_set_opts(g_np_pause, &op); } /* 绘制播放控制三钮(prev/next 固定;play/pause 按会话状态只画其一——两钮同位,改画时 * 上一帧残留被新画圆底盖掉)。 */ static void np_draw_ctl(const meow_media_session_t *s) { np_refresh_theme(); if (g_np_prev) { meow_widget_set_selected(g_np_prev, 0); meow_widget_draw(g_np_prev); } if (g_np_next) { meow_widget_set_selected(g_np_next, 0); meow_widget_draw(g_np_next); } int playing = (s && s->state == MEOW_MEDIA_PLAYING); meow_widget *pb = playing ? g_np_pause : g_np_play; if (pb) { meow_widget_set_selected(pb, 0); meow_widget_draw(pb); } } /* 进度带(进度条 + 时间)绘制;pos = 当前显示位置。进度条走 SDK meow_progress。 */ static void np_draw_progress(const meow_media_session_t *s, uint32_t pos, const meow_ui_theme_t *th) { int pct = (s->dur_ms > 0) ? (int)((uint64_t)pos * 100 / s->dur_ms) : 0; if (pct > 100) pct = 100; if (g_np_prog) { meow_progress_set(g_np_prog, pct); meow_widget_draw(g_np_prog); } /* 时间(左=当前,右=总长;MM:SS) */ char l[16], rbuf[16]; unsigned lm = pos / 60000u, ls = (pos % 60000u) / 1000u; unsigned dm = (s->dur_ms ? s->dur_ms : 0) / 60000u, ds = (s->dur_ms ? s->dur_ms : 0) % 60000u / 1000u; snprintf(l, sizeof l, "%u:%02u", lm, ls); snprintf(rbuf, sizeof rbuf, "%u:%02u", dm, ds); ui_draw(NP_PROG_X, NP_TIME_Y, l, th->on_surface_variant, 16); ui_draw(NP_PROG_X + NP_PROG_W - ui_width(rbuf, 16), NP_TIME_Y, rbuf, th->on_surface_variant, 16); } /* 整页绘制(空态占位)。redraw_sb=1 时喂/标脏状态栏(打开/主题变化),否则保留上次顶条。 */ static void np_draw_page(int redraw_sb) { const meow_ui_theme_t *th = s_ui_theme(); int W = fb_xres, H = fb_yres; if (!g_np_init) np_widgets_create(); /* M7.0b:lazy 建控件(跨进入复用) */ if (redraw_sb) fill_rect(0, 0, W, SB_BAR_H, th->surface); fill_rect(0, SB_BAR_H, W, H - SB_BAR_H, th->surface); const meow_media_session_t *s = meow_media_current(); if (!s || s->state == MEOW_MEDIA_STOPPED) { /* 空态占位(M7.0b 文案走 meow_str,未知 id 回退中文) */ const char *t1 = meow_str_zh("np.not_playing", "未在播放"); ui_draw((W - ui_width(t1, 26)) / 2, 300, t1, th->on_surface_variant, 26); const char *t2 = meow_str_zh("np.open_app_hint", "打开播放 App 以显示正在播放"); ui_draw((W - ui_width(t2, 18)) / 2, 348, t2, th->on_surface_variant, 18); const char *t3 = meow_str_zh("np.edge_back", "左缘右滑返回"); ui_draw((W - ui_width(t3, 16)) / 2, 396, t3, th->on_surface_variant, 16); if (redraw_sb) draw_statusbar(); return; } np_cover_load(s); /* 封面:解码缓存 + 圆角裁方;无封面回退主题色占位 + 首字 */ if (g_np_cover) { meow_gfx_fill_round(NP_COVER_X - 6, NP_COVER_Y - 6, NP_COVER + 12, NP_COVER + 12, 18, th->surface_container); meow_ui_img_cover(NP_COVER_X, NP_COVER_Y, NP_COVER, g_np_cover); } else { meow_gfx_fill_round(NP_COVER_X - 6, NP_COVER_Y - 6, NP_COVER + 12, NP_COVER + 12, 18, th->surface_container); meow_gfx_fill_round(NP_COVER_X, NP_COVER_Y, NP_COVER, NP_COVER, 14, th->primary); const char *t = s->title[0] ? s->title : s->app_id; int cw = ui_width(t, 22); ui_draw(NP_COVER_X + (NP_COVER - cw) / 2, NP_COVER_Y + (NP_COVER - meow_font_line_height(22)) / 2, t, meow_theme_get()->onPrimary, 22); } /* 元数据 */ np_center_text(NP_TITLE_Y, s->title, 26, th->on_surface, W - 40); np_center_text(NP_ARTIST_Y, s->artist, 18, th->on_surface_variant, W - 60); if (s->album[0]) np_center_text(NP_ALBUM_Y, s->album, 16, th->on_surface_variant, W - 80); /* 进度(SDK meow_progress) */ uint32_t pos = meow_media_display_pos(s); np_draw_progress(s, pos, th); /* 控制按钮(SDK meow_iconbtn,命中/状态走 SDK) */ np_draw_ctl(s); /* 歌词占位(M7.0b 文案走 meow_str) */ const char *ly = meow_str_zh("np.lyric_placeholder", "歌词(占位)"); ui_draw((W - ui_width(ly, 16)) / 2, NP_LYRIC_Y, ly, th->on_surface_variant, 16); if (redraw_sb) draw_statusbar(); } /* 仅重绘进度带 + 按钮(元数据/源变化时整页;纯进度变化时局部)。 */ static void np_repaint_progress(void) { const meow_ui_theme_t *th = s_ui_theme(); const meow_media_session_t *s = meow_media_current(); if (!s || s->state == MEOW_MEDIA_STOPPED) return; uint32_t pos = meow_media_display_pos(s); /* 清进度带 + 控制带,再重绘(只脏这两带,不整屏)。 */ fill_rect(0, NP_TIME_Y, fb_xres, NP_BTN_Y + NP_PLAY_R - NP_TIME_Y, th->surface); np_draw_progress(s, pos, th); np_draw_ctl(s); meow_dirty_add(0, NP_TIME_Y, fb_xres, NP_BTN_Y + NP_PLAY_R - NP_TIME_Y); meow_ui_flush(); } /* 控制按钮命中:返回 cmd(1-4),0=未命中。走 SDK 圆形命中(owner==哨兵 + enabled 闸门)。 * 播放/暂停两钮同位:命中任一(同矩形)→ 按会话状态分派 play(1)/pause(2)。 */ static int np_btn_tap(int tx, int ty) { const meow_media_session_t *s = meow_media_current(); if (g_np_prev && meow_widget_hit(g_np_prev, tx, ty)) return 3; if (g_np_play && meow_widget_hit(g_np_play, tx, ty)) return (s && s->state == MEOW_MEDIA_PLAYING) ? 2 : 1; if (g_np_next && meow_widget_hit(g_np_next, tx, ty)) return 4; return 0; } /* 进度 seek 命中(拖动/点按进度带):返回 seek_ms(>0),0=未中(或 dur=0)。 */ static int64_t np_progress_seek(int tx, int ty) { const meow_media_session_t *s = meow_media_current(); if (!s || !s->dur_ms) return 0; if (tx >= NP_PROG_X && tx <= NP_PROG_X + NP_PROG_W && ty >= NP_PROG_Y - 14 && ty <= NP_PROG_Y + 20) { int frac = (tx - NP_PROG_X) * 1000 / NP_PROG_W; return (int64_t)s->dur_ms * frac / 1000; } return 0; } void run_now_playing(struct app *apps, int napps) { int tfd = open(DEV_TOUCH, O_RDONLY | O_NONBLOCK); if (tfd >= 0) { unsigned char ev[16]; while (read(tfd, ev, sizeof ev) == 16) {} } unsigned long long touch_cooldown_until = now_ms() + 300; struct keypoll kp_keys; kp_open(&kp_keys, DEV_KEYS); struct keypoll kp_power; /* M2.92:NP 页接管电源键(修「页内电源键无反应」) */ kp_open(&kp_power, DEV_POWER); struct kd_state kd_play; memset(&kd_play, 0, sizeof kd_play); /* 读播放键按住态(用于边沿) */ int m_prev_play = 0; for (int w = 0; w < KEYBUF_WORDS; w++) if (kp_keys.cur[w] & (1UL << (KEY_PLAYPAUSE % 32))) m_prev_play = 1; int np_prev_power = 0; /* 电源键边沿跟踪 */ for (int w = 0; w < KEYBUF_WORDS; w++) if (kp_power.cur[w] & (1UL << (KEY_POWER % 32))) np_prev_power = 1; unsigned long long np_last_input = now_ms(); /* 自动息屏计时(M2.92:NP 页也遵守 display.screen_off_timeout) */ int td = 0, td_ok = 0, tdx = -1, tdy = -1, tlx = -1, tly = -1; unsigned long long last_prog = now_ms(); unsigned long long np_last_status_tick = now_ms(); /* M6.20:播放页状态栏时钟 1s 刷新(主界面同语义) */ int need_redraw = 1; int np_exit = 0; /* M6.22:返回手势命中 → 置位退出外层主循环。触摸内的 break 只跳出内层 * 读事件 while,不退出外层 while(!sigterm_flag),故必须靠标志跳出(根因:返回「没反应」)。 */ char last_title[128] = ""; uint32_t last_state = 0xFFFFFFFFu; char last_app[MEOW_APP_ID_MAX] = ""; meow_ui_activity_push(NP_SENTINEL_ACT); /* M7.0b:进入 push 哨兵(与函数尾 449 行 pop 配对)。 * 控件 owner 一直钉哨兵,命中要走 meow_widget_hit 的 * owner==active 闸门——漏 push 则 active()!=0x51, * 三钮 meow_widget_hit 恒 false(「播放页三键无效」根因)。 */ np_draw_page(1); meow_dirty_full(); meow_ui_flush(); while (!sigterm_flag) { if (np_exit) break; /* M6.22:返回手势已命中 → 退出本页,走尾部收尾回主界面 */ meow_ipc_process(); meow_media_tick(); unsigned long long now = now_ms(); /* 触摸 */ if (tfd >= 0 && meow_screen_on) { struct pollfd pfd = { tfd, POLLIN, 0 }; if (poll(&pfd, 1, 0) > 0) { unsigned char ev[16]; while (read(tfd, ev, sizeof ev) == 16) { uint16_t type = *(uint16_t *)(ev + 8); uint16_t code = *(uint16_t *)(ev + 10); int32_t val = *(int32_t *)(ev + 12); if (type == EV_ABS) { if (code == ABS_X || code == ABS_MT_POSITION_X) tlx = val; else if (code == ABS_Y || code == ABS_MT_POSITION_Y) tly = val; if (td && !td_ok && tlx >= 0 && tly >= 0) { tdx = tlx; tdy = tly; td_ok = 1; } } else if (type == EV_KEY && code == BTN_TOUCH) { if (val && !td) { if (now_ms() >= touch_cooldown_until) { td = 1; td_ok = 0; tlx = tly = -1; np_last_input = now_ms(); } } else if (!val && td) { td = 0; if (td_ok) { int dx = tlx - tdx, dy = tly - tdy; int adx = dx < 0 ? -dx : dx, ady = dy < 0 ? -dy : dy; /* M6.21 诊断:打印该次抬手手势的完整输入与各判定结果(真机定位 * 「返回滑不出」根因——状态栏/通知中心已生效,惟返回未触发)。 */ int np_is_top = mnp_top_swipe_down(tdx, tdy, dx, dy, SB_BAR_H, 65); int np_edge = meow_edge_back(tdx, dx, dy); int np_anyright = (dx >= 40 && adx > ady); logmsg("np up: down=(%d,%d) d=(%d,%d) adx=%d ady=%d top=%d edge=%d anyright=%d", tdx, tdy, dx, dy, adx, ady, np_is_top, np_edge, np_anyright); /* 顶部热区下滑 → 打开通知中心(与主界面同语义;mnp_top_swipe_down * 内部已排除左缘 down_x<24,与下方返回手势互斥)。run_notif_center * 为阻塞模态,返回后整页重画播放页。 */ if (np_is_top) { notif_click_t click; memset(&click, 0, sizeof click); click.app_idx = -1; click.status = NOTIF_CLICK_STATUS_NONE; run_notif_center(apps, napps, &click, 0, 0, 0); need_redraw = 1; meow_dirty_full(); meow_ui_flush(); } /* 左缘右滑返回(全局手势语义),或任意横向右滑返回——与主界面 * 「左滑进入 Now Playing」对称。返回阈值 65→40 放宽(防用户右滑 * 幅度不足 65 判不中);播放页无横向分页内容、无进度条拖动 * (进度=点按,幅度<60 走 tap 分支),故任意位置横向右滑恒判返回。 */ else if (np_edge || np_anyright) { logmsg("np: BACK break (edge=%d anyright=%d dx=%d)", np_edge, np_anyright, dx); np_exit = 1; break; /* 仅跳出内层读事件 while;外层主循环靠 np_exit 退出 */ } if (adx < 60 && ady < 60) { int cmd = np_btn_tap(tlx, tly); if (cmd) { meow_media_playctl((uint32_t)cmd, 0); need_redraw = 1; } else { int64_t seek = np_progress_seek(tlx, tly); if (seek > 0) meow_media_playctl(5, seek); } } tdx = tdy = -1; } else { tdx = tdy = -1; } } } } } } /* 播放键边沿 → 播放/暂停切换 */ kp_poll(&kp_keys, NULL, NULL); int play = 0; for (int w = 0; w < KEYBUF_WORDS; w++) if (kp_keys.cur[w] & (1UL << (KEY_PLAYPAUSE % 32))) play = 1; if (play && !m_prev_play) { const meow_media_session_t *s = meow_media_current(); if (s) meow_media_playctl((s->state == MEOW_MEDIA_PLAYING) ? 2u : 1u, 0); np_last_input = now_ms(); } m_prev_play = play; /* M2.92:NP 页电源键接管——单击边沿 = 息屏/亮屏(与主界面语义一致; * 修「NP 页电源键无反应」。3s 电源菜单仍由 watchdog→/tmp 标记→主循环消费, * NP 退出后生效(可接受偏差,记日志)。 */ kp_poll(&kp_power, NULL, NULL); int pwr = 0; for (int w = 0; w < KEYBUF_WORDS; w++) if (kp_power.cur[w] & (1UL << (KEY_POWER % 32))) pwr = 1; if (pwr && !np_prev_power) { np_last_input = now_ms(); if (meow_screen_on) { meow_panel_off(); logmsg("nowplaying: power tap -> panel off"); } else { meow_panel_on(); need_redraw = 1; logmsg("nowplaying: power tap -> panel on"); } } np_prev_power = pwr; /* M2.92:NP 页自动息屏(与主界面同超时;页面无触摸/按键计时器不走主循环) */ if (screen_off_timeout > 0 && meow_screen_on && now_ms() - np_last_input >= (unsigned long long)screen_off_timeout * 1000) { meow_panel_off(); meow_auto_slept = 1; logmsg("nowplaying: idle %ds -> auto panel off", screen_off_timeout); } /* 息屏期只低频轮询按键(唤醒用),不重画不读触摸(FBIOBLANK 已挂起 goodix) */ if (!meow_screen_on) { usleep(100 * 1000); continue; } /* 媒体变化检测(元数据/源/状态):立即整页重画 */ const meow_media_session_t *s = meow_media_current(); int meta_changed = !s || strcmp(last_app, s->app_id) || strcmp(last_title, s->title) || last_state != s->state; if (meta_changed) { if (s) { snprintf(last_app, sizeof last_app, "%s", s->app_id); snprintf(last_title, sizeof last_title, "%s", s->title); last_state = s->state; } else { last_app[0] = 0; last_title[0] = 0; last_state = 0xFFFFFFFFu; } need_redraw = 1; } /* M2.92 修死循环:空态/停止态只在「变化」时画一次(meta_changed 已覆盖 * NULL↔会话切换),不再每 10ms 整页重画(旧行为 = 100% CPU 忙刷 → 卡死观感)。 */ if (need_redraw) { np_draw_page(0); meow_dirty_add(0, SB_BAR_H, fb_xres, fb_yres - SB_BAR_H); meow_ui_flush(); need_redraw = 0; last_prog = now; } else if (s && (now - last_prog >= 1000)) { /* 进度推进:仅重绘进度带 + 按钮 */ last_prog = now; np_repaint_progress(); } /* M6.20:播放页状态栏时钟 1s 刷新(与主界面/子页同语义;draw_clock 喂 SDK 全局 * 状态栏 + 标脏顶条,SDK present() 重绘——否则时间冻结在进入播放页那一刻)。 */ if (now - np_last_status_tick >= 1000) { np_last_status_tick = now; draw_clock(); } usleep(10000); } meow_ui_activity_pop(); /* M7.0b:退出 Now Playing,回主 activity(控件 owner 仍钉哨兵,复用) */ if (tfd >= 0) close(tfd); kp_close(&kp_keys); kp_close(&kp_power); if (g_np_cover) { meow_img_free(g_np_cover); g_np_cover = NULL; } g_np_cover_path[0] = 0; }