VIA Selle平台 Singleton单件模式

"单件模式的使用意图就是:保证一个类仅有一个实例,并提供一个该实例全局的访问点",在VIA的应用层中,各种应用都是基于类来实现的,例如Call,SMS,Alarm等等,运行其间仅需要一个实例来进行操作(多实例会耗费更多的资源,引起管理上的麻烦,没有必要)

这里以Alarm为例来说明VIA的Singleton单件模式的实现:
class AlarmAppC : public
ApplicationC
{
public: 
 virtual
~AlarmAppC(void);
 static AlarmAppC*
GetInstance();
     ……
private:   
 static AlarmAppC*
_instance;
AlarmAppC(void);
}
AlarmAppC
*AlarmAppC::_instance = NULL;
AlarmAppC*
AlarmAppC::GetInstance()
{
 if (_instance ==
NULL)
 {
    _instance = new
AlarmAppC();
 }
 return _instance;
}
"私有化构造函数,使类的使用者调用不到这个构造函数来new一个实例。类型中可以自己new一个实例。类中创建一个静态私有变量和Static公有属性。在公有属性中实现此类的实例化。这样在第一次请求时创建此对象."
单件模式实际上是利用控制对象创造过程来控制对象的创造个数的方法,这样在Selle运行的过程中,就只有一个Alarm的实例,并且可以在APP层随意调用此Alarm来进行判断或处理.
参考资料:
       <<GoF+23种设计模式解析>>

 

通话记录与SMS中”同号删除”功能的实现

同号删除功能在VIA给的版本中没有提供,需要手工添加,实现是分别基于单条Erase,移植时需要添加新的Erase Same
Number项,这里不做讨论,可参照上一篇文档"消息分组,对话窗结构的结合-VIA 复杂消息的传递过程"

思路是首先提取当前记录,然后跟所有的记录比较,若一致则删除.程序实现复杂的地方是要遍历每个联系人的可能会有的五个号码,如其中任一一个匹配则删除此通话记录,若每个联系人都有五个号码,则两个记录比较需要遍历25轮.
程序中比较关键的几个地方用红色的标记了出来,其它的比较容易理解.
void
RecentCallAppC::OnDeleteSameNumberItem(uint32 RecId)
{
 RECENTCALL_TRACE_FUNC_ENTER(OnDeleteItem)
 RECENTCALL_TRACE_VAR(RecId)
 CallLogItemTimeC
ItemTime;
 GetRecentCallModel()->GetTimeOfCall(&ItemTime,
RecId); // To use the Title info
 GetRecentCallView()->CloseDialog(RECENT_CALL_DLG_ID_DELETE_ITEM_PROMPT,
FALSE, FALSE);
 GetRecentCallView()->CloseDialog(RECENT_CALL_DLG_ID_LIST_OPTIONS,
FALSE, FALSE);
 CallListItemT
RecIdItemInfo; //Get detail Item info from db by RecID
 GetRecentCallModel()->GetCallListItem(RecIdItemInfo,
RecId);
 uint16 Sum = 0;
 ValRcGetCountOfRecord((ValRcTypeT)VAL_RC_TYPE_ALL,
&Sum);// Get All RecID Number
 bool isAllRight;
 isAllRight=TRUE;
 for(uint16
id=0;id<=Sum;id++)
 {
    CallListItemT
ItemInfo; //Get detail Item info from db by RecID
GetRecentCallModel()->GetCallListItem(ItemInfo,
id);
    for(uint8 i=0;
i<RECENTCALL_NUM_MAX; i++)
    {
     
if(RecIdItemInfo.Other.Number[i].Len<1)
        break;
      for(uint8
j=0;j<RECENTCALL_NUM_MAX; j++)
      {
        
if(ItemInfo.Other.Number[j].Len<1)
           break;
     
if(StrCmp((char*)(RecIdItemInfo.Other.Number[i].Data),(char*)(ItemInfo.Other.Number[j].Data))==0)
        {
          
if(!GetRecentCallModel()->DeleteItem(id))
            {
              
isAllRight=FALSE;
            }
           break;
          }
        }
      }
 }
 if(isAllRight)
 {
   
GetRecentCallView()->OpenPopup(RECENT_CALL_POPUP_
ALL_CALLS_DELETED);
 }
 else
 {
    
GetRecentCallView()->OpenPopup(RECENT_CALL_POPUP_DELETE_RECORD_FAILED);
 }
 GetRecentCallView()->UpdateCallListDlg();
}
SMS中的处理整体思路是一样的,提取当前信息的号码,跟所有的信息中的号码相匹配,若一致则进行删除.要注意的是如何获取所有的短信息,包括收件箱,发件箱,草稿箱等.
int
SmsControllerC::HandleViewMsgOptionEraseALLSameNumberHintOk(uint32 MessageId,
uint32 Param)
{
 //get message
 SmsViewMsgManagerC
*ViewMsgManagerP = mModelP->GetViewMsgManager();
 UIASSERT(
!IsNull(ViewMsgManagerP) );
  SmsRecordC *SmsRecordP = ViewMsgManagerP->GetViewMsg();
     if( IsNull(SmsRecordP) )
      {
        return
-1;
  }
     AslSmsRecordIdT
RecordId = SmsRecordP->GetRecordId();
    SmsRecordC
SmsRecordPresent;
   
AslSmsReadMessage(SmsRecordPresent, RecordId);
    SmsAddressC
SmsAddressPresent;
   
SmsRecordPresent.GetSmsAddress(SmsAddressPresent);
    StringC
StrNumberPresent;
   
SmsAddressPresent.ToDigital(StrNumberPresent);
   //erase message
    AslSmsResultT Result
;
    for(int
typeI=0;typeI<5;typeI++)
    {
      SmsRecordListC *
smslist = NULL;
     
smslist=ViewMsgManagerP->GetRecordList((SmsRecordListTypeT)typeI);
//0~4
inbox,sentbox,outbox,draft…
      uint16 Count
=smslist->GetCount();
      //find a message to
delete
      for(uint16
i=Count;i>0;–i)
      {
        uint16
RecordId;
        if(
smslist->GetData(i-1, RecordId) )
        {
          //don’t delete
locked message
          if(
AslSmsIsMessageLocked(RecordId) )
          {
           
continue;
          }
            SmsRecordC
SmsRecord;
           
AslSmsReadMessage(SmsRecord, RecordId);
            SmsAddressC
SmsAddress;
           
SmsRecord.GetSmsAddress(SmsAddress);
                 StringC
StrNumber;
           
SmsAddress.ToDigital(StrNumber);
            
if(StrNumberPresent==StrNumber)
              {
                  Result =
AslSmsDeleteMessage(RecordId);
              }
        }
      }
    }
   if( Result !=
ASLSMS_RESULT_SUCCESS )
   {
    
OpenPopup(APPSMS_DIALOGID_POPUP_VIEW_MSG_MSG_ERASE_FAILED);
     return 0;
   }
  
OpenPopup(APPSMS_DIALOGID_POPUP_VIEW_MSG_MSG_ERASE_SUCCESS);
   //close view message
dialog
  
CloseDialog(APPSMS_DIALOGID_VIEW_MSG_DISPLAY);
   //update view
  
UpdateListMsgDialogAfterView();
   //update
softicon
  
GetView()->UpdateAlert();
 MessageId = 0;
 Param = 0;
 return 0;
}
这样删除有一个问题是,如通话记录或短信息很多,则这样遍历的的速度会不会令用户难以接受,还要进一步评估,若有更好的算法来实现,可以相互交流下:)

 

VIA 冲突管理 (selle)

  VIA平台中,有很多冲突的情况,如电话时来短信,或闹钟;播放MP3或MP4时来电话或短信,此时就要处理其冲突事件的优先级,来达到希望的处理顺序.

以此为例:当像录像的时候,如果此时闹铃响起或来新短信,录像则会停止并且退出.现在想让它继续录像,只是有一声提示,录像结束后给出提示.
查看Camera的代码:
int32
CameraAppC::
OnSuspend()
{
 GetCameraMode()->CameraSuspend();
 return 0;
}
int32
CameraAppC::OnResume()
{
 GetCameraMode()->CameraResume();
 return 0;
}
void
CameraAppC::
OnEventSuspend(uint32 Event, int32 RunBackground)
{
 Event = Event;
 RunBackground =
RunBackground;
 GetCameraMode()->CameraExit();
}
void
CameraAppC::OnEventResume(uint32 Event, int32 Param)
{
 Event = Event;
 Param = Param;
 GetCameraMode()->CameraResume();
}
闹铃响起时,应该是触发了 OnEventSuspend () ,
即使我屏蔽掉了OnEventSuspend,闹铃依旧会响起,只是没有打断当前录相,并且退出后,闹铃己经响过.
后来资讯VIA的郑工(师傅:)
,VIA有自己的冲突管理优先级顺序,客户可调,在uiconflictmanager.cpp的ConflictTable中定义:如下
 CONFILICT_EVENT_CAMERA,        
CONFLICT_EVENT_VOICE_CALL,      CONFLICT_ACTION_C,
 CONFILICT_EVENT_CAMERA,         CONFLICT_EVENT_ALARM,           CONFLICT_ACTION_C,
 CONFILICT_EVENT_CAMERA,        
CONFLICT_EVENT_CALENDAR,        CONFLICT_ACTION_C,
如第二行,当前是在CAMERA拍照或录像的时候,来了ALARM,则执行的测略为CONFLICT_ACTION_C,见其定义:
 CONFLICT_ACTION_A,         
// Continue processing FirstEvent,
                             
// notify and not process SecondEvent
 CONFLICT_ACTION_B,         
// Continue processing FirstEvent,
                             
// process SecondEvent in background
CONFLICT_ACTION_C,         
// Suspend FirstEvent,
                             
// process SecondEvent in foreground
不难看出,若改为CONFLICT_ACTION_A则出现预期的状态.
PS:Uiconflictmanager
是如何跟据这个表,来决定是否调用OnEventSuspend()VIA又是如何在中断后恢复操作OnEventResume()的,下回分解…

 

Camera添加对闪光灯的控制

        默认的Camera选项中没有对闪光灯的控制,但低层上有提供类似的功能。于是要在UI上添加对其的控制,即可以打开,关闭闪光灯:

1.首先查看驱动层提供的接口:
 gCapAttr.optFlash = CameraFlash[(ValCameraFlashT)Data->PropNum ];
static const
MCATCH_UINT16
CameraFlash[VAL_CAMERA_FLASH_MAX] =
{
 MCATCH_FLASH_OFF,
 MCATCH_FLASH_ON,
 MCATCH_FLASH_AUTO
}
可以看出只要给CameraFlash付正确的值就可以实现对闪光灯的控制。现在的问题就是把UI的消息一层一层地传递到驱动层。这里层与层之间的传递是通过消息及函数调用进行的。
2. 从VAL层到驱动层的消息传递:
这是VAL层往驱动层发的消息:
MediaMsgDataP->PropId = (uint32)CaptureProp;
/*store
the parameter in the msg*/
MediaMsgDataP->PropNum = *(uint32 *)DataP;
      /*make the routine
running in mediatask*/
ExeMsgSend(EXE_MEDIA_ID,
MEDIA_MAIN_MAILBOX_ID,MEDIA_CAMERA_CMD_CAPTURE_PROP_MSG,
MediaMsgDataP, sizeof(MediaPropMsgT));
mediatask会处理这里发送的消息,并调用相应的处理函数
static uint32
CmrCapturePropSet(void *DataP)
{
    …
case VAL_CMR_CAPTURE_PROP_OPT_FLASH:
   {
 gCapAttr.optFlash = CameraFlash[(ValCameraFlashT)Data->PropNum
];
 break;
   }
   …
 }
3.从UI层到VAL层是通过对函数的调用来实现的,具体的步骤如下
在UI层新添加一个函数响应按“打开”“关闭”闪光灯的消息:
void
CameraModelC::SettingFlashLight(uint32 status)
{
                
……
AslCmrSnpshtPropSet(ASL_CMR_CAPTURE_PROP_OPT_FLASH, &status);
                
……
}
VAL…
AslCmrResultT
AslCmrSnpshtPropSet(AslCmrCapturePropT snapshotProp, void *data)
{
 return
(AslCmrResultT)
ValCmrCapturePropSet((ValCmrCapturePropT)snapshotProp, data);
}
VAL…
ValCmrCapturePropSet如上2的处理,发送消息到驱动层。
整个过程如此,但有很多工作在这里没有提及,如在资源中添加相应的资源,添加对应的按键消息,打开菜单时的初始化,恢复初厂设置后的初始化等等。

 

阿拉伯输入法的实现-概述

 
最近在做的项目要实现阿拉伯输入法,它的实现涉及到了VIA的editctrol控件,EZI的输入法,arphic的排版引擎及其阿拉伯字库。他们的关系,打个比方,要画出阿拉伯语:ezi是画画的铅笔(用什么画),文鼎是画画的方法(画成什么样子),VIA是画画所用到的画纸(画在哪里)

分解开每一步的实现:
首先,输入控件Editctrol接受Onkeypress的按键消息,判断当前是Arbaic输入法,则会把按键消息传递到HandleEziKeypress_Arabic(),这个函数会记录按键消息,并按照EZI对应的键值,赋于一个全局变量中,如:
        mEziArabicInfo.pElements[mEziArabicInfo.ElementCount++] =
ZI8_CODE_LATIN_KEY4;
然后会调用EZI的API,其参数为此变量mEziArabicInfo,调用API后,对应的候选就己经赋值到此变量中。
       Zi8GetCandidates(&mEziArabicInfo);
接下来就是处理在Editctrol中显示候选。
其次,如当有四个候选时,选择其中一个的序号,此时会把该候选输出到控件Editctrol中。输出的过程是找到该序号对应的候选,调用AddChar把候选中的每个阿位伯字符一位一位的输出,由于阿位伯是Unicode所以要进行相应的转换。AddChar中会把字符插在当前光标所在位置并重新计算插入后光标的位置,这个工作就是文鼎做的。
        
AddChar
中首先会调用AddEditChar
把字符加在光标当前位置,然后会根据整个Editctrol中的输入内容来重新AllocateLineInfo()接着调用OnSetCursorRight设置插入后光标的逻辑位置。最关键的是SetCursPos()这个函数,负责处理当前的显示坐标的像素位置,阿位伯,英文,数字混和时光标位置是否定位准确就是在这里决定的,具体是由下面函数决定的:
 int16
CaretPos = ValDispOemArabicGetCaretPosition(dc, (uint8 *)LinString->String,
LinString->StringLen, CursPtr->Col);
     CursPtr->Pos->x
= EditPtr->TextRect.x + CaretPos+EDIT_TEXT_WIDTH ;
得出的CursPtr->Pos->x
即为光标显示的像素位置。
以上只是一个实现步骤的简单思路,真正的做起来要复杂很多,如要处理左右对齐的情况,以英文,还是数字开头的情况,添加,删除,移动光标的情况等等。

 

如果你有兴趣进一步了解这种忽左忽右的输入法,咱们再单独讨论:)

 

消息分组,对话窗结构的结合-VIA 复杂消息的传递过程

      以APPSMS
为例,短信所用到的消息加起来近三百多条,如果平均每条消息需要三个函数(某些操作远不止调用三个函数)加起来有九百个函数,管理起来将会是非常的麻烦,也不利于代码重用。
      VIA
用到一种虽然有点费解,但相当便利的方法,对消息进行分组,以一个DialogID为Key来关联相关的窗口资源及与窗口相关的操作。
消息分组:在资源中传递消息的时候,传递的消息的参数也是一个消息,首先跟据主消息(即组消息)找到对应的此组的MessageTabler(由消息映射来处理),然后HandleMessage根据传过来的第二个消息(成员消息)在MessageTable查找得到此消息要执行期的相关参数,如是否要打开窗口,打开窗口的ID,是否要关闭窗口,关闭窗口的ID,要设置数据的窗口ID,和所要执行的操作。
//   
MessageHandler
struct
MessageHandlerT———HandleMessage负责处理()
{
#ifdef
APP_TABLE_CHECK
 uint16 mParam;
#endif
 ControllserCommandOpenT
mCommandOpen;
 uint16
mOpenDialogId;
 ControllserCommandCloseT
mCommandClose;
 uint16
mCloseDialogId;
 uint16
mSetDataDialogId;
 MessageHandlerFuncT
mMessagenHandlerP;
};
HandleMessage处理四个操作:1.如果需要
对特定窗口进行SetData
                                                           
2.
如果需要 执行此消息的特定函数
                                                           
3.
如果需要 打开指定窗口
                                                           
4.
如果需要 关闭指定窗口    
窗口结构:由指定的DialogID关联相关的窗口资源ID及打开窗口时的更新名柄,设置数据的句柄,对按键消息进行反映的句柄组成。 如下面的定义:
//! dialog information
struct
DialogIdInfoT
{
#ifdef
APP_TABLE_CHECK
 int mDialogId;  
//dialog id, to check if a valid object                
#endif
 RESOURCE_ID(DialogResT)
mDialogResId;     //dialog resource id
 bool
mNeedUpdateWhenShow;
  UpdateViewFuncT mUpdateViewFuncP;       
//
由在APP中的OnCreateDialog重载来实现调用 ( Creat Dialog
时首先调用基类默认的Creat,如果派生类中有OnCreateDialog则调用派生类中的)
  SetDataFuncT mSetDataFuncP;    // 由 HandleMessage 中判断
mSetDataDialogId 是否为空,不为空则调用此处的mSetDataFuncP
  HandleWinNotifyFuncT
mHandleWinNotifyFuncP;
      //由在APP中的 HandleWinNotify
重载来实现调用(如SoftKeyBar,MenuCtrl在接收按键消息,如向上向下,确定,取消键时会触发此消息,更具体首先由 APP的
HandleKey(uint32 KeyMsgId, uint32 KeyCode) 来处理消息,处理完后会 调用基类的 Notify 基类调用
派生类的HandleWinNotify)
};
打开窗口时以DialogID为参数,查找该表可以得到相关资源。关健的地方在窗口相关句柄的调用是在哪里。基类帮我们完成了很多很多的事,但是它还会检查它的派生类是否具有某些特定的操作,如基类完成CreateDialog的操作,但如果发现派生类中有OnCreatDialog的定义,则会执行派生类的操作。这就是其中定义的句柄调用的地方,我在上面的定义后写了相关注释。
这样的处理流程也可用于需要大型的软件系统或分布式系统,对消息进行分组然后查表执行相关操作,其中的任一一项操作可以再查表…
如对WCF的调用,可以对消息进行分组,把具体的消息做为组消息的参数进行传递,在服务端进行分解,执行相关的操作。

 

Trace32调试——VIA平台

 

  1. elf文件的准备
在makefile-hdr中修改编译参数g-为g+,加入调试信息;
# Switches to be
used in Compile
#
——————————
CC_FLAGS =
$(CC_SW_ANSI) $(CC_SW_FPU) $(CC_SW_WARN) $(CC_SW_OPTIMIZE) –g- -fa \
-I"$(subst ;,"
-I",$(subst \,/,$(ARMINC)))" $(CC_SW_EXTRA) \
$(CC_DEFS)
$(CC_INCS) $(CC_MISC)
CCPLUSPLUS_FLAGS =
-embeddedcplusplus -strict $(CC_SW_FPU) $(CC_SW_WARN) $(CC_SW_OPTIMIZE) –g- -fa \
-I"$(subst ;,"
-I",$(subst \,/,$(ARMINC)))" $(CC_SW_EXTRA) \
$(CC_DEFS)
$(CCPLUSPLUS_INCS) $(CC_MISC) -D bool=boolean

app/ UI/ RES 目录中的makefile文件中的 CC_SW_EXTRA = -g-
改为-g+
把build.bat文件中的USE_WATCHDOG=TRUE改为
FALSE,关闭看门狗
Clean之后重新编译,找到D:\software\cp\rom_revc4中的cp.axf文件,备用;
  1. jt文件夹下找到trace脚本:debug-cp-4M.cmm C:\Trace32\jt_D1200P\ debug-cp-4M.cmm
    1. 确定其中axf文件的访问位置:if
      ("&file"=="") &file="../ram_revc2/cp.axf"
      ,并拷贝已有的cp.axf到此目录;
    2. 确定所用cpROM中的起始位置:r.s pc
      0x10000
    3. 确定cp的空间大小:
; Uses on-chip
breakpoints for code in Flash space
map.ro
0x10000–0x003FFFFF
  1. 打开ICD ARM,切换工作目录到对应的jt文件,执行do
    debug-cp-4M.cmm,
    axf文件loadTrace32
  1. 打开ETS
  1. Trace32cpu设置里Down
    变为UP。使下面状态栏显示system
    up.
  1. 设置断点,也可在程序运行中暂停设置,只能设置Onchip类型的断点。
  1. Go运行程序,Break可以暂停,预设断点处会自动停下,可以进行单步调试,查看变量。(更多的调试方法参阅TRACE-ICP使用手册)

 

MVC 设计模式VIA 的实现

. MVC模式
MVC是三个单词的缩写,这三个单词分别为:模型(Model)、视图(View)和控制(Controller)
1.优点:降低耦合度、增强内聚性(如图1层和区的概念)
2.使人员职能分工明确,有助于团队开发
3.有助于分布式开发
4.封装分解系统的复杂性 (可以对比D2000 appsms.cpp
的实现的复杂度)
 
二、MVC简介
(1)视图(View)代表用户交互界面,有可能为HTML、XHTML、XML和SmartClient。随着应用的复杂性和规模性,界面的处理也变得具有挑战性。一个应用可能有很多不同的视图,MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理。业务流程的处理交予模型(Model)处理。
(2)模型(Model):就是业务流程/状态的处理以及业务规则的制定。业务流程的处理过程对其它层来说是黑箱操作,模型接受视图请求的数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。
(3)控制(Controller)可以理解为从用户接收请求, 将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以完成什么样的用户请求。控制层并不做任何的数据处理。例如,用户点击一个连接,控制层接受请求后,
并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个模型。
,   D300中的MVC calendar为例
         分别对应三个文件: View :
calendarview.cpp
                                                
Model :
calendarmodel.cpp
Controller: appcalendar.cpp
 
模型、视图与控制器的分离,使得一个模型可以具有多个显示视图。如果用户通过某个视图的控制器改变了模型的数据,所有其它依赖于这些数据的视图都应反映到这些变化。因此,无论何时发生了何种数据变化,控制器都会将变化通知所有的视图,导致显示的更新。这实际上是一种模型的变化-传播机制。模型、视图、控制器三者之间的关系和各自的主要功能,
可见,所有的消息映射都是在appcalendar.cpp既Controller中,在View上操作,都会反映到Conrtoller中,然后Controller会更新View或把调用Model完成相关的业务操作
D300
“主动—MVC模式,也是通常意义下的MVC模式
 
【注:为什么说是主动的?View不是等Controller通知它Model更新了然后才从Model取数据并更新显示,而是自己监视Model的更新(如果用观察者模式)或主动询问Model是否更新。前面那种等待Controller通知的方式是下面所介绍的“被动—MVC”的实现方式。】
四,D300中 MVC模式的初始化:
CalendarAppC::CalendarAppC()
{
 mModelP = new
CalendarModelC();
 mViewP = new
CalendarViewC();
  mModelP->AddView(mViewP);
 AddModel(mModelP); 
 UiRegisterSpeKey(KP_FLIP_KEY,
this);
#ifdef FEATURE_VCALENDAR
 mRetMsgId = 0;
#endif 
 AudioC::GetInstance()->RegisterSndApp(APPID_CALENDAR,
SCHEDULE_APP_PRI, APPMSG_SOUND_EVENT, 0);
}
由于基类实现了MVC,自己写APP的话,可以套用相同的格式,这样即方便今后对代码的查看与修改,同时可以得到基类的更多特性的支持

 

VIA平台上显示中文

 在英文的VIA平台上显示中文(关于中文字库的开启与选择)

1.USE_SW_CHN=TRUE 中文字库的开关
    在Makefile里的定义:
ifeq "$(USE_SW_TYPHOON)" "TRUE"
ifeq "$(USE_SW_CHN)"
"TRUE"
             OBJS_LOCAL
+= valdispfont_chn.o valdispfontdata_chn.o
 //中文相关
            else
          OBJS_LOCAL += valdispfont_typhoon.o
valdispfontdata_typhoon.o  //没有中文
endif
else
    OBJS_LOCAL += valdispfont.o
valdispfontdata.o
endif
valdispfont_chn.c中
 void FontGetCharBitmap( DispFontT
Font,uint16 CharCode, DispBitmapT *BitmapP,bool OnlyWidth)
 {
           
//
实现了由资源编辑器产生的对应字符编码到从字库中取出对应字符的bitmap的过程。
   /* char is a ASCII or UNICODE
*/
   if (CharCode > 0xFF)
   {
     pFontData =
DispFontDataUnicode[Font];
   //中文编码是用Unicode
   }
   else
   {
     pFontData =
DispFontDataAscii[Font];
   }
   }
 static DispFontInfoT*
DispFontDataUnicode[DISP_FONT_TOTAL] =
 {
  
(DispFontInfoT*)&FontInfoHZ12x12,           /* DISP_FONT_SMALL_PLAIN  
*/
  
(DispFontInfoT*)&FontInfoHZ12x12,           /* DISP_FONT_SMALL_BOLD   
*/
  
(DispFontInfoT*)&FontInfoHZ12x12,          
/* DISP_FONT_NORMAL_PLAIN */
  
(DispFontInfoT*)&FontInfoHZ12x12,           /* DISP_FONT_NORMAL_BOLD  
*/
  
(DispFontInfoT*)&FontInfoHZ12x12,           /* DISP_FONT_LARGE_PLAIN  
*/
  
(DispFontInfoT*)&FontInfoHZ12x12            /* DISP_FONT_LARGE_BOLD   
*/
 };
FontInfoHZ12x12在    valdispfontdata_chn.c中定义,对应着相关字库
2. valdisppainter.c中的
DispTextOut()     与    DispMeasureText()
显示调用      
FontGetCharBitmap(dc->Font,CharCode,&Bitmap,TRUE);
来取得字编码相应的bitmap
3.在uieditcontrol.cpp中
EziFreeNumVector(),EziLoad(),EziUnLoad(),EziHandleKeypress(),EziCopyBufferToScreen(),
EziDrawElement()
是有关于Ezi输入法的,由#defined USER_EZI控制
4.由于中文字库比较大,所以删除了图片,游戏等辅助程序,腾出更多的Flash空间。

 

idle界面的Banner若设为动画则背景为黑色

对在idle界面的Banner若设为动画则背景为黑色的分析:
在Appidle.cpp文件中:
ControlP->SetText(StringP,TRUE);
在Uistatictextcontrol.cpp中
 void StaticTextControlC::SetText(const StringT*
StringResP,bool AnimationYesNo)
             {
 SetAnimationYesNo = AnimationYesNo;
              }
 void StaticTextControlC::Draw()
             {
                    if( !mBorder && SetAnimationYesNo )
{
   
DispEraseRect(&mDC, &CtrlRect);
}
              }
问题就出在DispEraseRect(&mDC,
&CtrlRect),它会调用DispFillSolidRect(dc, Rect, dc->BackColor);
使用BackColor的颜色填充此BannerRect,默认的BackColor为黑色。
解决方法尝试:
             1.屏蔽掉DispEraseRect(&mDC,
&CtrlRect);这样虽然不显示黑色背景了,但
Banner会不断自我重叠,无法正常显示
             2.屏蔽掉上句后,使用HwdUpdateDisplayRect(NULL,&drt);更新,但显示依然不正常还会重叠。又尝试了对局部和全屏刷新,问题依旧。
3.ImageResT dataBuffer;
   DispBitmapT mBitmap;
   GET_RESOURCE(ResourceDatabase,
(ImageResT*)IDI_MENUITEM_BG_BMP, &dataBuffer);
  
GetBitmapFromImage(dataBuffer,&mBitmap);
 DispBitBlt(&mDC, CtrlRect.x, CtrlRect.y,
CtrlRect.dx, CtrlRect.dy, &mBitmap, 0,0);
   //可以在屏幕的任意位置画图形。
上面实现了在Banner下面画上背景图,但问题是要当前Idle的图片
4. 继续尝试着读取当前画面
   ImageResT dataBuffer;
   //DispBitmapT mBitmap;
 // GET_RESOURCE(ResourceDatabase,
(ImageResT*)IDI_MENUITEM_BG_BMP, &dataBuffer);
   DispBitmapT*
mBitmap=DispGetDeviceBitmap(&mDC)
  
GetBitmapFromImage(dataBuffer,mBitmap);
 DispBitBlt(&mDC, CtrlRect.x, CtrlRect.y,
CtrlRect.dx, CtrlRect.dy, mBitmap, 0,34);
问题依然,虽能读取当前画面,但当前面画随着DrawText还是会每次都叠加,因为读取了是上次写上字的画面。
5.继续尝试当第一次读取画面时保存起来一个备份,以后就用这张不变的画面刷。
 ImageResT dataBuffer;
 // DispBitmapT mBitmap; 这类的定义中声名。
 GET_RESOURCE(ResourceDatabase,
(ImageResT*)IDI_MENUITEM_BG_BMP, &dataBuffer);
    if(IsNull(mBitmap))  
    {
    
mBitmap=DispGetDeviceBitmap(&mDC);
    }
  
GetBitmapFromImage(dataBuffer,mBitmap);
 DispBitBlt(&mDC, CtrlRect.x, CtrlRect.y,
CtrlRect.dx, CtrlRect.dy,
IdleApplicationC::GetInstance()->mBitmapForStaticTextctrl, 0,0);
问题依旧,随后把读取放在Appidle.cpp的Onlanch()中,在OnUpdateBanner()之前,但显示依然会重叠。
6.最后的解决办法
从SIDB中读取当前WallPaper的值,把对应的图片替换到第四种尝试中。
   else if( !mBorder &&
SetAnimationYesNo )
{      DialogC* TopDialogP =
DialogStackP->GetTopDialog();

   if
((TopDialogP->GetResourceId() ==(ResourceIdT)IDD_IDLE_DIALOG)||(TopDialogP->GetResourceId()
==(ResourceIdT)IDD_IDLE_NOTIME_DIALOG))
    { 
    FsiResultT SidbResult =
FSI_SUCCESS;
    uint32 Index = 0;
   uint32 size = sizeof(Index);
   SidbResult = FsiSidbRead(ITEM_DISPLAY,
KEY_SCREEN_WALLPAPER, (void *)&Index, 0, &size);
    if (IsEqual(SidbResult,
FSI_SUCCESS))
    {
           ImageResT dataBuffer;
           DispBitmapT mBitmap;
      if (Index <
gPhotoReservedNum)
      {
        ResourceDatabaseC::ErrorT ErrorCode =
GET_RESOURCE(ResourceDatabase, (ImageResT*)IdleBgBmpInfo[Index],
&dataBuffer);
        UIASSERT(IsEqual(ErrorCode,
ResourceDatabaseC::SUCCESS));
 GetBitmapFromImage(dataBuffer,&mBitmap);
        DispBitBlt(&mDC, CtrlRect.x,
CtrlRect.y, CtrlRect.dx, CtrlRect.dy, &mBitmap, 0,18);
      }
     }
     else
     {
DispEraseRect(&mDC, &CtrlRect);
     }
 }
问题解决。
局限性:1.不适用用户自己添加的WallPager,(D2000项目中不能客户自己添加)
        2.因为动画的刷新频率很高,这样读SIDB势必影响速度。
改善:
7.每次刷新都从SIDB里读一边很费时间与空间,要是能把读取图像放在Appidle中的OnUpdateWallPager中,那每次只有当更新WallPager时才读一边。于是,程序更为
Appidle中OnUpdateWallPager()中:
    if (IsEqual(SidbResult, FSI_SUCCESS))
    {
      char *BufferP = NULL;
      ImageResT dataBuffer; //ZJJ
      //UIASSERT(Index <= ARR_SIZE(IdleBgBmpInfo) –
1);
      //UIASSERT(Index <= (sizeof(IdleBgBmpInfo[]) /
sizeof(IdleBgBmpInfo[0]) – 1));
      if (Index < gPhotoReservedNum)
      {
        ResourceDatabaseC::ErrorT ErrorCode =
GET_RESOURCE(ResourceDatabase, (ResourceIdT)IdleBgBmpInfo[Index],
(void**)&BufferP);
        UIASSERT(IsEqual(ErrorCode,
ResourceDatabaseC::SUCCESS));
        
/******************zjj*************************/
         ResourceDatabaseC::ErrorT ErrorCode2 =
GET_RESOURCE(ResourceDatabase, (ImageResT*)IdleBgBmpInfo[Index],
&dataBuffer);
     UIASSERT(IsEqual(ErrorCode2,
ResourceDatabaseC::SUCCESS));
  GetBitmapFromImage(dataBuffer,&mBitmapForStaticText);
// mBitmapForStaticTextAppidle.h中声明为Pubilc DispBitmapT
mBitmapForStaticText;
        
/*******************zjj************************/
}
在 uistatictextctrl.cpp 中添加对 #include "appidle.h" 的引用
   else if( !mBorder && SetAnimationYesNo )
   {
   //Add by zjj for show background image when the statictextctrl is
rolling in idle 20080704
     DialogC* TopDialogP =
DialogStackP->GetTopDialog();
 if((TopDialogP->GetResourceId()==(ResourceIdT)IDD_IDLE_DIALOG)||(TopDialogP->GetResourceId()
==(ResourceIdT)IDD_IDLE_NOTIME_DIALOG))
     {
       
DispBitBlt(&mDC,CtrlRect.x,CtrlRect.y,CtrlRect.dx,CtrlRect.dy, &(IdleApplicationC::GetInstance()->mBitmapForStaticText),
0,18);
     }
     else
     {
      DispEraseRect(&mDC, &CtrlRect);
     }
   }
至此在即不影响效率的情况下实现了文本的滚动显示。
遗留问题:若用户要添加自定义背景图片,则不能正常滚动,背景是当前Dialog的背景色
解决:在添加自定义背景图片中用相同原理实现。
(D2000不支持用户自定义添加WallPager,以后有需求再添加)
注意:对头文件的引用。