MTK - 10A帮助文档(总结)

更新时间:2024-04-04 04:11:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

MTK 10A帮助文档

一.10A MMI主要新特征

1. 新Event机制 API:

#define MMI_FRM_SEND_EVENT(_evt, _proc, _user_data) \\ mmi_frm_send_event((mmi_event_struct *)(_evt), (mmi_proc_func)(_proc), (void *)(_user_data))

#define MMI_FRM_POST_EVENT(_evt, _proc, _user_data) \\

mmi_frm_post_event((mmi_event_struct *)(_evt), (mmi_proc_func)(_proc), (void *)(_user_data))

mmi_frm_send_event = 直接函数调用

mmi_frm_post_event 发消息稍后调用(据MTK说是为了防止循环调用)

mmi_frm_invoke_post_event可以处理队列里的消息,这个mtk已经做好了在一些必要的地方调用

Event处理机制在MTK 10A mmi framework代码中很重要,在后续特征中会有体现

2. Callback管理机制

10A中callback其实还是用event机制实现的

在mmi_cb_mgr_cfg.h中可以看到如何注册一个event的callback,也可以通过调用mmi_ret mmi_frm_cb_reg_event(U16 evt_id, mmi_proc_func call_back, void *user_data)来注册,一个event可以注册多个callback,会依次调用,如果有需要截断后面的处理,则不能返回MMI_RET_OK

MTK新版本中已有的event数量已经非常多,也可以自己添加,需要在以后熟悉代码中慢慢熟悉已有的event的意义

此时的callback event和上面1中的event有些区别的,使用mmi_frm_cb_emit_post_event来发送,在mmi_frm_invoke_post_event中会判断然后和1中的event区别处理

3. Screen Group机制 见图形化文档

跟原来的screen机制并不能完全兼容,如需移植代码需要注意,独立的功能最好添加一个group id,否则可以使用已有的group id

4. CUI Common UI

5. 添加XML 方式描述Mmi Resource

1

可见代码:phonebook.res MTK会解析*.res文件生成mmi_rp_{APP_NAME}_def.h 兼容以前的添加资源方式

6. 新按键处理

static void process_key_event_routing(mmi_frm_key_evt_struct *key_evt_p) 参考PRST_FRM_NewInputHandler.pdf

7. 新屏幕刷新机制

MTK为了避免屏幕闪的问题,改在特定的时间刷新屏幕,如果需要马上刷新需要设置

mmi_frm_set_curr_scr_blt_mode(MMI_FRM_SCR_BLT_IMMEDIATE);(有些需要频繁刷新屏幕的应用需要)

8. 怎样添加一个新应用

见文档 PRST_FRM_HOW_TO_WRITE_APP_10A.pdf

二.MTK History机制深入分析

1.10A的屏幕架构

10A中的屏幕管理,不再像以前那样简单的管理一个数组,出栈入栈,而是维护一个树,如下图:

Group headtailGroup nextGroup nextGroup head\\tailheadtailheadtailScreeen Screeen nextGroup Screeen nextGroup head\\tailheadtailnextScreeen Screeen Screeen 这个是总的屏幕集合的一部分,基本上是主菜单一个应用有自己的一个总的group(也不排除特殊情况,比如设置菜单),在这个group下有许多子group(就好像一个菜单中有很多子菜单),子group中又会有用来显示的screen以及其它的group,依次类推,不过最底部(叶子节点)一定会是个screen,用作显示。 以前的EntryNewScreen是一个入栈的过程,现在的进入新屏,就需要创建新的group连接到已有的父group的子group中的尾部,然后再以新建的group为父

2

节点创建screen用作显示,当然这其中也会处理前一个group,也就是保存历史的操作。

进屏之后返屏,可以想象返屏就会移除父group的子group中的tail的group并释放在其申请的内存,接着激活其前一个节点(可能是group,可能是screen),tail的group就会是激活的节点。 具体的进\\出屏幕会在下文详细介绍。

2.进屏流程

由于10A中也会用到原来的EntryNewScreen进屏,也会有直接创建screen进屏等多种方式进屏,我在这就只列出一个比较具有象征性的进屏方式。因为现在进屏比较复杂我就大体例举其调用的主要的几个函数以及他的作用。

1) mmi_frm_group_create (MMI_ID parent_id, MMI_ID group_id, mmi_proc_func proc, void *user_data),看到这个我想都会知道是创建一个group,它的父ID,ID等系列属性也会根据参数来赋值,值得一提的是group是动态申请内存的方式创建,还有在创建的时候,不会把新节点加到父节点的子节点的尾部。而是先加到shell.scenario_dangle这个节点下。 2) 创建好group后,就会进入group,mmi_frm_group_enter (MMI_ID group_id, mmi_group_enter_flag flag)进入新的group,注意在这里他又会调用add_node这个函数把group加入到他的父级group下,加到尾部,同时会用remove_node()这个函数来remove掉shell.scenario_dangle下对应节点,(有点没懂为什么在新建的时候会add到shell.scenario_dangle这个节点后,又在紧跟着的entry group中remove掉这个节点,是为了防止在第一次creategroup之后没有调用entry gourp么?期待高手解答)这步就是加链表的操作了。

3)接着就是用这个函数group_active(group_node_struct *node, mmi_scenario_evt_struct* evt),这个函数会对该node的父级group做判断:

只有在父级group为shell.scenario_root,才会调用mmi_frm_entry_new_screen(),这个又是我们熟知的进屏函数了,我不再这一一介绍,只说一些不同的操作,他不单利用historyData这个结构体来保

3

存上一个屏幕的信息,也会记录新进的屏幕的信息,还有在记录上一个屏幕信息的时候不再用mmi_frm_add_history这个函数来申请内存保存上一个屏幕控件的历史信息。

接着会inactive其前一个节点。调用group_inactive或者scrn_inactive。

4) group_inactive会调用scrn_inactive来inactive其节点下的(包括本身节点)节点。那么得分析下scrn_inactive,这里会调用该node所记录的退出函数,根据进入函数来调用scrn_add_history(scrn_node_struct *node)来保存历史,这个改良了53的保存控件历史的函数,它统一了各个所有控件的保存方式,不再是像以前那样对特殊模板独立保存方式。这里同样会申请内存来保存控件信息,不过它会根据控件的size大小来申请内存,而且都是保存在node这个结构体中,同样也可以在退出函数中作保存历史的操作。

5) 以上几步是把上个屏幕的信息保存下来了,现在要做的是对新的group的操作了。现在要做的就是对新group的操作。这个就要关注下post_scenario_evt(MMI_ID group_id, U32 scrn_id, post_scenario_act_enum act, mmi_scenario_evt_struct *evt, U32 type)这个函数会把参数中的写到post_queue这个结构体队列中,然后调用scenario_process_post_evt_ex(U32 type)来读取队列执行相应写入的操作,比如激活新group就会调用group_post_active(group_node_struct *node, mmi_scenario_evt_struct* evt)这个函数用shell.active_group来记录进入的新node。shell.active_scrn为NULL。

6) 仅仅只有好像只是group的操作,那么screen的操作去哪了呢?现在就是开始screen的步骤了,和group一样也会新建screen,同样也是申请内存,把screen加到新的group下,调用scrn_active激活screen,用shell.active_scrn记录新的screen。这里主要还是介绍下两种进屏幕的方式mmi_frm_scrn_first_enter和mmi_frm_scrn_enter,这两者的区别就在于前者可以应用显示函数中应用参数(一般都是节点结构体中记录的数据)还有tab页的进入调用mmi_frm_scrn_tab_enter,和scrn一样最终页调用scrn_node_enter,具体流程类似。(可以看一下mmi_phb_entry_op_option) 具体流程入下图所示(这只是一个比较标准的进屏,10A中也有直接申请Sreen进的,还有用原始的进屏方式等等)

4

Groupshell.scenario_danActive_groupgleHead\\tailHead\\tailScreenActive_scrnNew_groupGroupshell.scenario_danActive_groupgle2个小弟了没小弟了….HeadTailScreenActive_scrnNextNew_groupGroupInactive_group这些操作会写入队列,靠读取队列执行相应动作HeadTailScreenInactive_scrn这里会申请内存来NextNew_group记录控件历史GroupHeadTailScreenNew_groupNextActive_group终于轮到我了。GroupHeadTailScreenNew_groupNextActive_group我也有小弟了ScreenActive_scrn

5

3.返回屏幕

1)mmi_frm_group_close_ex (MMI_ID group_id, U32 type)中会调用group_close,而该函数会先关闭该节点的孩子节点,也就是screen节点,而scrn_close()会scrn_inactive()screen节点后,在调用execute_node_deinit(base_node_struct *node, mmi_scenario_evt_struct* evt)把POST_EXECUTE_DEINIT的操作写进队列中,接着调用scenario_process_post_evt_ex读取队列中的操作执行execute_node_post_deinit来释放screen申请的内存。这么一来原有的screen就不在了,对于group来说也会做类似的操作,同样是先inactive,再exit,最后deinit都会把操作写进队列,这样一来就结束了显示着的界面。

2)现在就是要看怎么实现返回的了,其实简单来说就是激活了被释放节点的前一个节点,如果该节点是group会激活该group下的screen,如果是screen就直接激活screen,调用screen节点所记录下的entry函数,实现了返回的效果。注意,在被释放节点的父节点为shell.scenario_root时,在返回时会调用GobackHistory,来返回历史。这个是我们熟知的方法,也就不在这一一介绍了。 具体流程如下图所示:

6

GroupHeadTailGroupScreennextActvie_groupHead\\tailScreenActive_screenGroupshell.scenario_dangleHeadTailHead\\tailScreenScreennextGroupInctive_screenActvie_group一些删屏响应函数在这调用shell.scenario_Groupdangle小弟…HeadTailScreen先释放保存控件ScreennextGroupActvie_group申请的内存,再释放Screen申请的内存Groupshell.scenario_Active_groupdangle你敢不走么?Head\\TailHead\\tailScreen激活这个节点的操Group作已写进队列Inctvie_groupGroupshell.scenario_Active_groupdangle。。。Head\\TailScreenGroupActive_screen释放内存,这个过程会调用根据本节点保留的控该节点记录的进入函数,用件信息还原历史户可以按自己需求写该函数

7

4.删除屏幕

其实删屏在返回屏幕中已经介绍了他的具体流程,这里就简单介绍些常用的几个删屏函数吧:

1)mmi_frm_group_close (MMI_ID group_id):删除相应ID的group,删除group会连带删除该group下的所有子节点。

2)mmi_frm_scrn_close_active_id()顾名思义会删除激活状态下的screen 3)mmi_frm_scrn_close_ex (MMI_ID parent_id, MMI_ID scrn_id, scrn_close_type_enum flag)删除指定ID的screen。 4)mmi_frm_scrn_multiple_close (MMI_ID parent_id, MMI_ID start_scrn_id, U8 b_inc_start, U16 count, MMI_ID end_scrn_id, U8 b_inc_end)这个类似53平台上的DeleteHistoryInt(),用来删除多个屏幕。

注意:如果被删的节点的父节点,只有一个子节点(也就是被删的节点),那么同样会删除该节点的父节点。

5.插入节点

1)mmi_frm_group_insert (MMI_ID parent_id, MMI_ID base_id, mmi_frm_node_struct *new_node_info, mmi_scenario_node_flag flag)

2)mmi_frm_scrn_insert (MMI_ID parent_id, MMI_ID base_id, mmi_frm_node_struct *new_node_info, mmi_scenario_node_flag flag)

两者都会根据传入的flag参数确定加入的位置,加节点的流程与进屏加节点类似,只是位置不同,不再分析流程。

6.一些函数介绍

1.mmi_frm_get_active_scrn_id(MMI_ID *group_id, MMI_ID *scrn_id)获取激活的group和screen的ID

2.mmi_frm_group_get_active_id(void)

3.mmi_frm_scrn_get_active_id(void)和以前类似,对tab页也是获取主屏ID

4.mmi_frm_scrn_tab_get_active_id(void)这个函数是获取tab页主屏的ID 5.mmi_frm_scrn_tab_page_get_active_id(void)获取激活的page页ID(也就是子屏ID)

6.mmi_frm_scrn_get_active_gui_buf (void)这个函数封装了所有screen的历史获取,包括tab页。

7.mmi_frm_scrn_set_leave_proc (MMI_ID parent_id, MMI_ID scrn_id, mmi_proc_func proc)设置删屏响应函数

7.总结

由上可知10A的屏幕管理要比以前的复杂的多,上面所分析的也是一种常见的屏幕架构,也会有比较特殊的,会直接用以前的EntryNewScreen,也会有一个group下游很多screen子节点,可是万变不离其中,都是根据节点的增删,维护一个树,来实现屏幕的切换。

还有些tab页的进屏没有详细分析,不过也是类似节点的管理,不再一一介绍,可以根据代码了解过程。主要是进一个主屏,这个主屏链接着树,管理其顺序,然后主屏下有相应的page页,激活着的page页在这个主屏的尾部,在返回时只对主屏进行操作,不过在操作中会操作它的子节点。

8

注意:

在10A中也可以用EntryNewScreen,不过有几点限制: 1.如果前后都是EntryNewScreen,可以。

2.如果前面是节点,那么该节点的父节点必须为shell.scenario_root 3.如果后面是节点,那么该节点的父节点必须为shell.scenario_root

终上所述,也就是说EntryNewScreen进的screen可以理解为shell.scenario_root这个节点的子节点。 以上就是我的收获了,希望有帮助,谢谢。

三.资源添加

1、文件结构

目录一:plutommi\\MMI\\FirstApp

目录二:plutommi\\MMI\\FirstApp\\FirstAppInc(该结构未改变) 文件列表:

FirstAppDefs.h:用于存放本程序所需要的类型,结构,常量的定义

FirstAppProt.h:用于存放本程序中的所有函数声明,但此文件只被本文件的源程序所加载

FirstAppGprot.h:也是用于存放函数声明,但是此文件是用于别的程序加载,即此文件中的函数声明的都是对外的接口

FirstAppResDef.h:用于存放本资源ID的定义接口

目录三:plutommi\\MMI\\FirstApp\\FirstAppSrc(该结构未改变) FirstAppSrc.c程序的主源文件

目录四:plutommi\\MMI\\FirstApp\\FirstAppRes(新的目录)

FirstApp.res:资源文件定义,包含字串、图片、菜单、屏幕等的定义,该文件实际为一个标准xml文件

ref_list_FirstApp.txt:该模块多国语言字串定义(目前发现该文件并未生效,不知道是否是设置问题)

2、将文件加入项目

修改make\\plutommi\\mmi_app\\下的三个文件:

1)mmi_app.lis:此文件用来申明MMI所要编译的所有源文件,添加如下一行: plutommi\\MMI\\FirstApp\\FirstAppSrc\\FirstAppSrc.c

2)mmi_app.inc:此文件用来指明MMI所有头文件所在目录,同样添加: plutommi\\MMI\\FirstApp\\FirstAppInc

3)mmi_app.pth:此文件用来指明MMI所有源文件所在目录,添加:

9

plutommi\\MMI\\FirstApp\\FirstAppSrc

4)在plutommi\\Customer\\ResGenerator\\MakeFile文件中添加如下一行: -I \

3、应用程序ID定义

1)在基础ID 统一定义文件plutommi\\MMI\\Inc\\mmi_res_range_def.h(原来为MMIDataType.h)中找到如下定义块:

RESOURCE_BASE_ENUM_BEGIN()

/**************************************************************************************

* Declare resource ID range below

**************************************************************************************/ ……

/**************************************************************************************

* Declare resource ID range above

**************************************************************************************/

RESOURCE_BASE_ENUM_END()

在其中添加:

#ifdef __MMI_FIRSTAPP__

RESOURCE_BASE_RANGE(FIRSTAPP, 50), #endif

2)找到如下定义块:

/* Beginning of resource table */

RESOURCE_BASE_TABLE_BEGIN() ……

/* End of resource table */

RESOURCE_BASE_TABLE_END()

10

在块中间末尾位置添加:

/**************************************************************************** * FirstApp

*****************************************************************************/

#ifdef __MMI_FIRSTAPP__

#define FIRSTAPP_BASE ((U16) GET_RESOURCE_BASE(APP_FIRSTAPP)) #define FIRSTAPP_BASE_MAX ((U16) GET_RESOURCE_MAX(APP_FIRSTAPP))

RESOURCE_BASE_TABLE_ITEM_PATH(APP_FIRSTAPP, \这里较之前有所变化 #endif

4、字串、图片、屏幕资源的添加

先来说字串、图片、屏幕资源ID的添加。10A版本中对资源定义的改动比较大,稍微对比一下新老版本,你会发现很多原来很大的文件变小了,而多出来了很多.res后缀的文件,这就是新版本的资源定义文件。10A版本仍部分保持了老版本的定义方式,不过笔者建议采用新版本的方式来定义资源,而且与之前相比新版本的资源定义要方便不少。读者可以随便找一个res文件,会看到如下定义格式:

/* Needed header files of the compile option in XML files, if you need others need to add here */

#include \#include \

/* Need this line to tell parser that XML start, must after all #include. */

/* APP tag, include your app name defined in MMIDataType.h */

/* When you use any ID of other module, you need to add that header file here, so that Resgen can find the ID */

/* String ID of you Application, we will get string from ref_list.txt for all

11

languages */

/* 这里说下,字串的内容定义和之前的版本一样放在YourProjectPath\\plutommi\\Customer\\CustResource\\PLUTO_MMI\\ref_list.txt下,为了更好的兼容,最好将你自己定义的字串重新规整到YourProjectPath\\plutommi\\MMI\\FirstApp\\FirstAppRes\\ref_list_FirstApp.txt下,具体定义方式和ref_list.txt类似,参考本博客文章《MTK编程起步——建立新APP和资源定义》 */

/* Image Id and path of you Application , you can use compile option in Path, but need out of \

id=\pp\\\\\\\\HELLO.BMP\

/* 这里定义自己的图片ID和路径,注意图片现在的CUST_IMG_PATH路径是在YourProjectPath\\plutommi\\Customer\\Images\\FTE320x480,请将图片文件夹放在这里,然后打包整个MainLCD文件夹为image.zip(改了mtk_resgenerator.cpp的可以不用打包) */

/* Only MENUITEM need compile option, MENUITEM_ID does not need */ /* 这里定义你的菜单ID,具体定义方法稍后给出 */

这个res文件类似与xml文件,不过你可以在其中使用一些C的预处理命令和注释。使用这种方式你不需要自己去定义res_app_firstapp.c,系统会在这个文件中搜索ID并自动生成名为mmi_rp_app_firstapp_def.h和mmi_rp_app_firstapp.c的文件,并在后者中定义对应的populate函数。至于res文件中各标签和其属性定义,请参看MTK官方文档10A_MMI_Resource_Training.pdf。

12

5、菜单添加

菜单由于有上下级关系,定义要相对复杂些,这里先介绍几个标签:MENU、MENUITEM和MENUITEM_ID。MENU是用来定义菜单树的标签,MENUITEM是用来定义单个菜单项的标签,MENUITEM_ID是用来在MENU树中安置菜单项的标签。下面来讨论菜单的定义。

新版本中菜单的定义方式有很多种,现介绍最常用的三种方式,其它方式请读者参看上面给出的MTK官方文档。

方法一:MENU中包含MENUITEM_ID方式定义

这种方式采用如下格式:

SUBMENU1 SUBMENU2

采用这种方式要在MENU体外申明对应MENUITEM的定义,可以放在引用MENU之前也可在其后,但MENU中MENUITEM_ID包含的内容必须是已定义的MENUITEM的ID,如果不存在系统将会将该菜单忽略。另外提一点,为了和先前的版本兼容,MTK提供了@OID:前缀,用来引用原先在c文件中定义的菜单ID,使用方法是将其放在标签对之间即可,例如:@OID:SUBMENU3。不过引用前请使用下。

方法二:直接将MENUITEM定义在MENU中,格式如下:

这种方式不需要在MENU体外定义对应MENUITEM,只需要放在MENU标签内同时定义MENUITEM信息即可。

13

方法三:嵌套MENU,格式如下:

采用这种方式使得菜单的定义一次完成,也易于理解,但是当属性较多层次较深的时候可能显得较乱。这种方式是直观的MENU树表现方式,显示了子菜单与父级菜单的对应关系。有些读者可能对MENU和MENUITEM有些迷茫,笔者认为,在大部分时候MENU和MENUITEM可以通用,你可以把他们看成一种东西(MENU)。你可以将方法三第二行替换成方法一或方法二的形式。不过如果有SUBMENU1有子菜单的时候,方法三可以直接嵌套在对应MENU体之中,而方法一或方法二则需在MENU方法体外做如下定义:

以上三种方法可以根据需要混合使用。最后为了完整实现菜单功能,别忘了添加对应菜单的highlight和hint函数。说到highlight和hint函数,这里有必要提一下,不是所有菜单都可以直接在res文件中添加highlight和hint选项来实现的,如果你发现你的highlight和hint不起作用,请使用模拟器跟踪一下同类高亮函数,会发现其高亮处理在类似mmi_ret mmi_phnset_gpio_menu_handler(cui_menu_event_struct *menu_evt, MMI_ID parent_gid)和static void mmi_phnset_gpio_select_menu(mmi_menu_id id, MMI_ID parent_id)的函数中使switch (menu_evt->highlighted_menu_id){case SUBMENU1:}或switch (id){case SUBMENU1:}进行多分支进行的。其中前一个函数的作用是点选左键或点触该菜单项所执行的事件即原来高亮函数中的SetLeftSoftkeyFunction,而后一个函数则是高亮该菜单项所执行的函数即原来的高亮函数。而hint函数存在于类似static mmi_ret mmi_phnset_disp_setup_sub_menu_entry_handler(cui_menu_event_struct *param)中,switch (param->parent_menu_id){case MENU1:}对父级菜单ID进行判断并执行相应初始化函数,hint函数位于对应父级菜单的初始化函数中。注意这里一定是父级菜单而不是本菜单,因为hint函数的加载都是在进入包含该菜单的父级菜单中进行的。

14

本文来源:https://www.bwwdw.com/article/u2vr.html

Top