Files
stc32g128k/App/app_manager.c

191 lines
4.8 KiB
C
Raw Normal View History

#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;
}
// 供遗留代码兼容性引用的 APIStartApp 映射至 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);
}