#include "app_manager.h" #include "event.h" #include "xtell.h" // 前台与后台应用的运行指针槽位 static WristbandApp *fg_app = NULL; static WristbandApp *bg_apps[3] = {NULL, NULL, NULL}; /** * @brief 判断某个应用是否正在后台挂载运行中 */ static bit IsAppInBackground(WristbandApp *app) { u8 i; if (app == NULL) return 0; for (i = 0; i < 3; i++) { if (bg_apps[i] == app) { return 1; } } return 0; } /** * @brief 初始化应用管理器 */ void AppManager_Init(void) { u8 i; fg_app = NULL; for (i = 0; i < 3; i++) { bg_apps[i] = NULL; } XTELL_LOG("[AM] AppManager Initialized.\r\n"); } /** * @brief 动态将一个应用切换至前台活跃运行 */ bit AppManager_SwitchToForeground(WristbandApp *app) { if (app == NULL) return 0; XTELL_LOG("[AM] Switch foreground to: "); XTELL_LOG(app->app_name); XTELL_LOG("\r\n"); // 1. 若当前有正在运行的前台应用,将其移出前台 if (fg_app != NULL) { WristbandApp *prev_app = fg_app; fg_app = NULL; // 物理断开,防止在 onClose 期间被重入轮询 // 若该应用没有在后台运行,需要彻底关闭它以清理外设 if (!IsAppInBackground(prev_app)) { if (prev_app->onClose != NULL) { prev_app->onClose(); } } } // 2. 挂载新的前台应用 fg_app = app; // 3. 启动新应用生命周期 // 若该应用之前在后台运行,不用重新执行 OnStart,直接接管前台显示即可; // 否则说明是初次运行,执行 OnStart 进行界面绘制与状态初始化。 if (!IsAppInBackground(app)) { if (app->OnStart != NULL) { app->OnStart(); } } return 1; } /** * @brief 动态将一个应用挂载到后台槽位 */ bit AppManager_AttachToBackground(WristbandApp *app) { u8 i; if (app == NULL) return 0; // 若已经存在于后台,直接返回成功 if (IsAppInBackground(app)) { return 1; } // 寻找空闲的后台槽位进行挂载 for (i = 0; i < 3; i++) { if (bg_apps[i] == NULL) { bg_apps[i] = app; XTELL_LOG("[AM] Attach to background slot ["); XTELL_LOG_HEX8(i); XTELL_LOG("]: "); XTELL_LOG(app->app_name); XTELL_LOG("\r\n"); // 若该应用既不处于前台,也没在后台初始化,执行其 OnStart() if (fg_app != app) { if (app->OnStart != NULL) { app->OnStart(); } } return 1; } } XTELL_LOG("[AM] ERROR: Background slots full!\r\n"); return 0; // 槽位满,挂载失败 } /** * @brief 动态将一个应用从后台卸载 */ void AppManager_DetachFromBackground(WristbandApp *app) { u8 i; if (app == NULL) return; for (i = 0; i < 3; i++) { if (bg_apps[i] == app) { bg_apps[i] = NULL; XTELL_LOG("[AM] Detach from background: "); XTELL_LOG(app->app_name); XTELL_LOG("\r\n"); // 如果该应用未在前台运行,需要彻底关闭它 if (fg_app != app) { if (app->onClose != NULL) { app->onClose(); } } return; } } } /** * @brief 向前台活跃应用派发事件 */ void AppManager_DispatchEvent(SystemEvent evt) { if (fg_app != NULL && fg_app->onEvent != NULL) { fg_app->onEvent(&evt); } } /** * @brief 主循环中轮询前后台所有应用 */ void AppManager_RunActiveApp(void) { u8 i; // 1. 轮询前台活跃应用 if (fg_app != NULL && fg_app->onRun != NULL) { fg_app->onRun(); } // 2. 轮询后台挂载的应用 for (i = 0; i < 3; i++) { if (bg_apps[i] != NULL && bg_apps[i]->onRun != NULL) { bg_apps[i]->onRun(); } } } /** * @brief 获取当前前台活跃应用的唯一 ID */ u8 AppManager_GetActiveAppID(void) { if (fg_app != NULL) { return fg_app->app_id; } return 0xFF; } // 供遗留代码兼容性引用的 API:StartApp 映射至 SwitchToForeground 动态方式 void AppManager_StartApp(AppID app_id) { if (app_id == APP_ID_HOME) AppManager_SwitchToForeground(&home_app); else if (app_id == APP_ID_MENU) AppManager_SwitchToForeground(&menu_app); else if (app_id == APP_ID_SET_CLOCK) AppManager_SwitchToForeground(&set_clock_app); else if (app_id == APP_ID_PAIR) AppManager_SwitchToForeground(&pair_app); else if (app_id == APP_ID_IPC_BIND) AppManager_SwitchToForeground(&ipc_bind_app); else if (app_id == APP_ID_ALARM) AppManager_SwitchToForeground(&alarm_app); else if (app_id == APP_ID_SOS) AppManager_SwitchToForeground(&sos_app); }