VIA Selle SMS 系列之—发送篇

上一篇文章由Duplic
Message引出了SMS的接受过程,这篇文章则由Page Message引出SMS的发送过程,同样是基于Selle1.0的。
二,短信的发送过程
这里只讲到从新建短信,添加联系人,然后发送的典型过程,不包括调用接口直接发送短信的情况,稍有不同。
1.UI层新建短信,编辑内容,选择发送:
编辑内容不为空时,此时按Send键,会调用:(或者在Edit Message的窗口中选择Options选项,也会调用:)
     SmsViewC::SetDataNewMsg(DialogC *DlgP, uint32 MsgId, uint32
Param)
      {
  EditCtrlC *EditCtrlP =
(EditCtrlC*)DlgP->GetControlByType(CTRL_TYPE_EDIT);
         StringC
StrText;
  EditCtrlP->GetText(StrText);
SmsEditMsgManagerC *EditMsgManagerP =
((SmsModelC*)mModelP)->GetEditMsgManager();
           //set StrText
to Model
          if(MsgId ==
APPMSG_SMS_NEWMSG)
         {
           EditMsgManagerP->SetEditMsgText(StrText); 

//激活 SmsEditMsgManagerC中具体的短信对象即mEditMsg,并调用默认的短信设置选项来进行初始化设置!

          }
      }
这里EditMsgManagerP是一个临时的对象,包括你在新建短信时输入的内容,与之后添加的收件人,及其相关设置。
编辑内容为空时,此时Send键不起做用,Selle默认好像是不支持空短信的,在smscust中配置设置。
const SmsCustSettingsT
gSmsCustSettings =
{
 TRUE,//FALSE didn’t allow to send blank sms
 TRUE,
  "10010"
};
判断的方法如下:   
//if can not send empty message, then
delete Send and group menu item
if(
!SmsGetCustSettings()->mSendEmptyMsg )
{
    //为空时不删除Seng等按键
}
2.UI层编辑内容后,添加联系人,选择发送:
这里以直接输入联系人电话号码为例,输入对方联系人手机号,点击发送后,会调用:
SmsViewC::SetDataNewMsgEditAddress(DialogC
*DlgP, uint32 MsgId, uint32 Param)
{
    SmsEditMsgManagerC
*EditMsgManagerP = ((SmsModelC*)mModelP)->GetEditMsgManager();
    StringC
StrAddress;
AddressEditCtrlP->GetText(StrAddress);
   
//……
省略了对多联系人及联系人列表中出现";"的处理
EditMsgManagerP->ClearEditGroupAddress();
 EditMsgManagerP->SetEditGroupAddressNumber(StrAddress);//把输入的联系人放到临时的编写短信的对象中
 EditMsgManagerP->SaveEditGroupAddress();
}
在支持空短信的处理中,我在这后面添加了从临时对象中取出短信内容,并添加类似这样的内容: "Call:123456789"
    SmsRecordC
*SmsRecordP;
  SmsRecordP = new SmsRecordC;
   SmsRecordP->CopyFrom(*(EditMsgManagerP->GetEditMsg())); //从临时对象中实例化一个SmsRecordP的对象
 StringC Content;
 SmsRecordP->GetUserData(Content);
 if(Content.GetLength()<1)
 {
    Content.Append("Call:");
    Content.Append(StrAddress);
   
EditMsgManagerP->SetEditMsgText(Content);
 }
其实这一步可以在第一步输入为空时进行操作,但在这里还要做合并号码的动作,所以就在这个地方一起处理了。
在执行完SetData的动作后,还会同时执行发送动做,因为根据输入的内容不为空,即有号码输入时:
if(Event ==
EDIT_EVENT_DATA_EMPTY) //no data in edit control, set left softkey bar to
‘search’
{
         
SoftkeybarP->SetButtonTitle(1,IDS_SMS_SEND);
         
SoftkeybarP->SetButtonMessageId(1, APPMSG_SMS_NEWMSG);
          if(
NEWMSGEDITADDRESS==EditType )
//为编辑号码状态
          {
           
SoftkeybarP->SetButtonMessageParam(1,APPMSG_SMS_PARAM_NEWMSG_SEND);
          }
}
所以按Send的同时会执行(跟踪此消息可查知,不再详细列出其消息映射关系)
3.APP层处理发送过程:
    首先会处理,APPMSG_SMS_NEWMSGAPPMSG_SMS_PARAM_NEWMSG_SEND的消息:
int
SmsControllerC::HandleNewMsgSend(uint32 MessageId, uint32 Param)
{
 //check if previous message sending
finish
 if
(!mModelP->IsPreviousMessageSendingFinish())
 {
   
GetView()->OpenPopup(APPSMS_DIALOGID_POPUP_SENDING_PREVIOUS_MESSAGE);
    return -1;
 }
 //add message to send
 if(
IsEqual(ASLSMS_RESULT_INVALID_PARAMETER, mModelP->AddEditMsgGroupToPending()) )//A
 {
   
GetView()->OpenPopup(APPSMS_DIALOGID_POPUP_ADDRESS_EMPTY);
    return 0;
 }
 //send message
 SendMessage(HasMemoryFullDialog);//B
}
其上面A处AddEditMsgGroupToPending()的做用是把编写短信时的临时对象EditMsgManagerP中的内容添加到一个代发短信列表后面,即LinkedListC
mPendingMsgList;大致的过程为:
AslSmsResultT
SmsModelC::AddEditMsgGroupToPending()
{
 int i=0;
 SavePendingMsg();//clear outbox message这里我的理解为,把PendingList中的第一条内容存储到Storage当中
    {
    SmsRecordC *SmsRecordP;
    SmsRecordP = new SmsRecordC;
    if( IsNull(SmsRecordP) )
    {
      return
ASLSMS_RESULT_OUT_OF_MEMORY;
    }
   
SmsRecordP->CopyFrom(*mEditMsgManager.GetEditMsg());
//zjj add 20090916 —begin 添加空短信时的特殊处理
#ifdef FEATURE_PAGEMESSAGE   StringC
Content;
 StringC CallContent("Call:");
 SmsRecordP->GetUserData(Content);
 if((Content.SubString(0,5).GetLength()==5)&&(IsEqual(Content.SubString(0,5),
CallContent)))
 {
   
SmsRecordP->SetTeleserviceID(AslSmsGetTeleserviceIdByType(ASLSMS_TELESERVICE_TYPE_PAGE));
//这里判断为空短信时,要把短信的TeleserviceID设置了4097,接收方跟据此标志在HandleMessageIncoming里来做特殊的显示处理
 }
#endif 
//zjj add 20090916 —end
    SmsAddressC *AddressP =
(SmsAddressC*)(*AddressArrayP)[i];
    UIASSERT( !IsNull(AddressP)
);
   
SmsRecordP->SetSmsAddress(*AddressP);
   
AddToPendingMsg(SmsRecordP);
//把当前短信添加到发PendingList的尾部,等待发送。
 }
 return ASLSMS_RESULT_SUCCESS;
}
然后是B处,SendMessage(HasMemoryFullDialog)的处理:
void SmsControllerC::SendMessage(bool
HasMemoryFullDialog,bool IsFromEditMsg,bool IsForEditAddress)
{
 //Check if is in airplane mode.
 #ifdef SYS_OPTION_RUIM
 //check if have uim card or not
 #endif
 //check if has network.
 if (
IsEqual(AslGetServiceInfo()->ServiceStatus, VAL_PSW_NO_SERVICE))
 {
   
OpenPopup(APPSMS_DIALOGID_POPUP_NO_NETWORK);
    //clear pending list
    mModelP->ClearAll();
    return;
 }
 //check storage 强调的一点是这里处理有关是否存储发送短信的相关操作,在下一篇中再介绍
 if(
!CheckStorageBeforeSendMsg(HasMemoryFullDialog,IsFromEditMsg,IsForEditAddress)
)
 {
    //clear pending list
    mModelP->ClearAll();
    return;
 }
 AslSmsResultT Result =
mModelP->SendPendingMsg() ;//具体的发送过程在这里
 APPSMS_PRINTF((char*)"SmsControllerC::SendMessage
Result = %d", Result);
 if( (Result == ASLSMS_RESULT_SUCCESS)
|| (Result == ASLSMS_RESULT_SENT_BUT_SAVE_FAILED) )
}
SendPendingMsg()的大致流程如下,省略了与主题无关的代码:
AslSmsResultT
SmsModelC::SendPendingMsg()
{
   //no message to send, then return
success
 if(mPendingMsgList.GetCount() == 0
)
 {
    return
ASLSMS_RESULT_SUCCESS;
 }
 // 设置发送频道
 if(IsEqual(1, GetSendChannelSidb()))
 {
    
APPSMS_PRINTF((char*)"SmsModelC::SendPendingMsg: set channel to TC");
   
ValSmsSetChannel(VAL_SMS_CHANNEL_TC);
 }
 else
 {
   
APPSMS_PRINTF((char*)"SmsModelC::SendPendingMsg: set channel to Default");
   
ValSmsSetChannel(VAL_SMS_CHANNEL_DEFAULT);
 }
 SmsRecordC *SmsRecordP =
(SmsRecordC*)mPendingMsgList.GetHead();//获取待发送列表中的第一条
 uint16 RecordId=0;
 uint16 MessageId=0;
 AslSmsResultT Result =
AslSmsSendMessage(*SmsRecordP, &RecordId, &MessageId,
GetSettings()->mAutoSave);//调用ASL层的函数继续处理发送过程
 if( (Result == ASLSMS_RESULT_SUCCESS)
|| (Result == ASLSMS_RESULT_SENT_BUT_SAVE_FAILED) )
 return Result;
}
4.ASL层的发送处理过程:
主要处理是根据是否为自注册短信,而选择存储或不存储此发送短信
AslSmsResultT
AslSmsSendMessage(SmsRecordC &SmsRecord, uint16 *RecordIdP, uint16
*MessageIdP, bool ToSave)
{
 AslSmsResultT result ;
#ifdef FEATURE_SMS_AUTO_REGISTER
 if(SmsRecord.GetAutoRegisterFlag())
 {
    //not
need save if is AutoRegister message.
    result = (AslSmsResultT)ValSmsSendTxtMessage(gSmsRegisterId, RecordIdP,
SmsRecord, MessageIdP, FALSE);
 }
 else
#endif
 { 
    result = (AslSmsResultT)ValSmsSendTxtMessage(gSmsRegisterId, RecordIdP,
SmsRecord, MessageIdP, ToSave);
 }
 gSmsUnReadCount = -1;//Unread sms
number should be update
 return result;
}
5.VAL层的发送过程:
ValSmsSendTxtMessage 不再详细介绍,其间是一些发送设置,最重要是继续调用ValSmsSendMessage来发送
ValSmsSendTxtMessage …
{
 if ( 0 != ValSmsSendMessage( SmsTxtMsgP ) ) //SmsTxtMsgP 为发送内容
 {
    ValSmsSendInfo[RegId].Acked =
TRUE; /* send failed, then clear the flag of ack */
    return
VAL_SMS_ERR_MSG_FORMAT;
 }
}
这里只以新建短信的发送过程为例:
int ValSmsSendMessage( ValSmsMessageT *MessageP )
{
 ValSmsTeleMsgT MsgType;
 MsgType =
MessageP->TeleMsgType;
 switch(MsgType)
 {
    case
VAL_SMS_MSG_TYPE_ORIGINATION_SUBMIT:
      i = SendSubmitMsg(MessageP);
      break;
       ……
      }
}
SendSubmitMsg函数中有更为复杂的参数设置,如跟基站交互时发送地址的格式问题等,这里就不一一介绍了(如果你对这里的设置很熟悉,欢迎跟我交流,一起研究下,现在也不是很明白:),但关键有一处,如下:
static int SendSubmitMsg(
ValSmsMessageT* MessageP )
{
 /* send ack data message to PSW
*/
 ExeMsgSend(EXE_PSW_ID,
PSW_MAILBOX_CMD, PSW_SMS_SUBMIT_DATA_MSG,
             (void *)DataMsgP,
sizeof(PswSmsUserDataMsgT));
 ——-or—————————————————————-
 /* send sms
parameter message to PSW
*/
 ExeMsgSend( EXE_PSW_ID,
               PSW_MAILBOX_CMD,
              
PSW_SMS_SUBMIT_PARMS_MSG,
  
(void*)ParmMsgP,
   sizeof(
PswSmsSubmitParmsMsgT ) );
}
把短信发送到协议层,然后就真的发出去了,至于PSW层的发送处理,唉,搞协议层暂还没纳入规划:)
6.总结:
以上实现了以空短信为例,从最上层的UI—>APP—>ASL—>VAL—>PSW层的处理过程,即短信发送的大致过程。
下一篇准备介绍有关短信是否存储的相关设置问题,哈哈,希望比这篇要短很多。

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.