应用对接

一、说明

应用的构成分为三个部分:应用主体,应用子页,应用弹窗页。

二、应用主体

相关文件:
《app_tool_app.c》
《app_tool_app.h》

1.应用的创建和删除

1.1 创建

void sfat_app_register(void *data)
{
    sfat_manager_node_t *node  = (sfat_manager_node_t *)data;
    builtin_app_desc_t *desc = (builtin_app_desc_t *)app_malloc(sizeof(builtin_app_desc_t));
    rt_memcpy((void *)&desc->name, (const void *)&node, sizeof(sfat_manager_node_t *));
    rt_memcpy(desc->id, node->binary.header.st->id, GUI_APP_ID_MAX_LEN);
    desc->entry = app_main;
    desc->type = GUI_APP_TOOLS;
    desc->icon = (const void *)node;
    node->app_node = (void *)desc;
}

在解析工具应用文件的时候,会调用此函数进行应用注册。此时需要申请一个应用的节点,并且填写应用相关信息。
desc->entry:进入应用的回调函数接口。
desc->type: 应用的来源类型,标注为GUI工具。
desc->icon: 应用图标,在此填写了整个节点,需要在显示应用图标的地方再次解析。
node->app_node: 将应用节点记录到工具节点中,以供后续查找使用。

1.2 删除

void sfat_app_unregister(void *data)
{
    sfat_manager_node_t *node  = (sfat_manager_node_t *)data;
    if (node->app_node)
    {
        app_free(node->app_node);
        node->app_node = NULL;
    }
}

在删除工具应用文件的时候,会调用此函数进行应用注销。此时需要将注册时申请的应用节点释放。

2.应用列表的添加与显示

2.1 添加到应用菜单

相关文件:
《gui_app_fwk.c》\

static void app_load(const char *id, app_entity_info *p_app_info)
{
    const builtin_app_desc_t *item = NULL;
#ifdef APP_TOOL_SUPPORT
    if (item == NULL)
    {
        item = (const builtin_app_desc_t *)sfat_manager_get_app_next((void *)item);
        while (item != NULL)
        {
            if (0 == strcmp(item->id, id))
            {
                break;
            }
            item = (const builtin_app_desc_t *)sfat_manager_get_app_next((void *)item);
        }
    }
#endif
}

app_load这个函数用于实现从各个途径获取应用信息,示例代码段为获取GUI工具应用的信息。

2.2 显示应用图标

每个菜单样式都有自己的显示图片的函数,我们需要在对应的函数中去添加GUI工具应用图标显示流程.在此我们以蜂窝菜单为例:

void mainmenu_cell_item_create(builtin_app_desc_t *app_desc, mainmenu_ext_icons_t *table_elem, uint16_t index, void *user_data)
{
    if (app_desc && app_desc->type == GUI_APP_TOOLS)
    {
#ifdef APP_TOOL_SUPPORT
        sfat_manager_node_t *node = (sfat_manager_node_t *)img;
        lv_obj_t *menu_icon = lv_img_create(icon_btn);
        sfat_set_header_src(menu_icon, node->file_path, &node->binary);
        lv_obj_align(menu_icon, LV_ALIGN_CENTER, 0, 0);
        lv_obj_add_flag(menu_icon, LV_OBJ_FLAG_SCROLL_CHAIN | LV_OBJ_FLAG_EVENT_BUBBLE);
        lv_obj_refr_size(menu_icon);
#endif
    }
    else
    {
        lv_obj_t *menu_icon = lv_img_create(icon_btn);
        lv_img_set_src(menu_icon, img);
        lv_obj_align(menu_icon, LV_ALIGN_CENTER, 0, 0);
        lv_obj_add_flag(menu_icon, LV_OBJ_FLAG_SCROLL_CHAIN | LV_OBJ_FLAG_EVENT_BUBBLE);
        lv_obj_refr_size(menu_icon);
    }
}

通过type判断此应用信息是否为工具类型,并添加相应的处理流程。

根据第二章第一节的节点创建中的内容,我们给应用信息的icon赋值为GUI工具的节点信息。所以在此我们将icon强制转换为工具节点类型,然后根据工具的库函数sfat_set_header_src为图片控件设置图片源。即可完成GUI工具应用的菜单图标显示。

3.应用的运行

3.1 应用运行的准备

static int app_main(intent_t i)
{
    p_intent tmp = (intent_t)app_malloc(sizeof(_intent));
    rt_memcpy(tmp, i, sizeof(_intent));
    sfat_manager_set_active_by_id(&tmp->content[0], SFAT_MANAGER_TYPE_APP);
    app_free(tmp);

    sfat_manager_node_t *node = sfat_manager_get_active_node(SFAT_MANAGER_TYPE_APP);
    gui_app_regist_msg_handler_ext((const char *)node->binary.header.st->id, msg_handler, (void *)node, 0);

    return 0;
}

app_main是应用运行的入口函数,每当应用创建准备开始运行的时候,会执行此函数。、 在此我们可以提前获取到即将要运行的应用的ID,并通过ID获取到工具应用的节点。然后将其传递给后续流程使用。

3.2 应用运行与退出

static void on_start(void)
{
    sfat_gui_sys_init(p_sfat_node);			//app tool system init
}
static void on_stop(void)
{
    sfat_gui_sys_deinit(p_sfat_node);       //app tool system deinit
    p_sfat_node = NULL;
}

当应用开始运行的时候,需要对GUI工具的系统进行初始化,其中包括设置脚本运行环境,读取字体信息,控制命令管理。
相应的在应用退出的时候,需要进行反初始化,将之前的配置移除。

三、应用子页

相关文件:
《app_tool_page.c》
《app_tool_page.h》

1.子页的创建

void sfat_page_main(char *theme_id)
{
    /*创建的页面一定是在当前活动的应用上*/
    sfat_manager_node_t *node = sfat_manager_get_active_node(SFAT_MANAGER_TYPE_APP);

    /*检查theme id的有效性*/
    if (false == sfat_set_active_theme(node, theme_id))
    {
        rt_kprintf("%s, not find:%s in file:%s!!!

", __func__, theme_id, node->binary.header.st->id);
        RT_ASSERT(0);
    }

    if (RT_EOK == gui_app_goback_to_page(theme_id)) return;

    gui_app_create_page_ext(theme_id, msg_handler, sfat_get_theme_by_id(node, theme_id));
}

static void msg_handler(gui_app_msg_type_t msg, void *param)
{
    p_sfat_node = sfat_manager_get_node_by_id((char *)param, SFAT_MANAGER_TYPE_APP);
    p_sfat_theme = gui_app_this_page_userdata();
}

在页面创建的时候,需要把当前活动页的信息设置到页面框架中,方便后续读取使用。

四、应用页的弹窗

相关文件:
《app_tool_pop.c》
《app_tool_pop.h》

1.弹窗注册

void sfat_pop_register(void *data)
{
    sfat_manager_node_t *node  = (sfat_manager_node_t *)data;

    for (uint8_t i = 0; i < node->binary.header.st->theme_count; i++)
    {
        if (node->binary.theme_table[i].sta.flag.type == SFAT_THEME_TYPE_APP_WINDOW)
        {
            sfat_theme_t *theme = sfat_read_theme(node->file_path, &node->binary, i, false);
            popup_register_for_app(node->binary.header.st->id, theme->sta.id, theme->dynamic.pop_data->prio, theme->dynamic.pop_data->time, msg_handler, 0, POPUP_APP_TOOLS);
        }
    }
}

在应用文件的解析过程中,会遍历此应用的所有页面,所有的弹窗页面都会在此处统一进行注册。

2.弹窗注销

void sfat_pop_unregister(void *data)
{
    sfat_manager_node_t *node  = (sfat_manager_node_t *)data;
    popup_unregister_for_app(node->binary.header.st->id);
}

在卸载应用的过程中,会调用此函数将此应用所包含的所有弹窗移除。

3.弹窗使用

int popup_run(const char *id, void *user_data);

工具使用弹窗是在《app_tool_event.c》中由事件触发进行使用。
但是由于弹窗是注册到系统的弹窗框架中的,所有在用户自己的代码中也可以使用这些弹窗。