放弃呼出的电话,在OUTGOING界面按下右软件,进入:
void DropRequest(void)
{
       gCallAbortRequested---指示是否正在处理放弃的电话
       gDropRequestFlag------指示是否是主动放弃电话的。
       以上全部设置为TRUE
 
       HangupCall(handle);
}
void HangupCall(CM_CALL_HANDLE CallHandle)
{
       OutgoingProcessCMEvent(CM_KB_HANGUPREQ, &CallHandle);
}
ACTION_RESULT ProcessKBHangupReqEvent(void *MsgStruct)
{
CASE CM_OUTGOING_CALL:
       SetCallflag(handle, CM_HANGUP_REQUESTED, TRUE);
       SetCallState(handle, CM_DISCONNECTING_STATE, TRUE);
 
       如果这个CALL已经被接通了,那么就
              MakePsEndSelectiveCall((void*)HangupReqSucess, handle);
       如果还没被接通,并且还没设置call_handle,那么就:
              gCallAbortReqSentFlag=1  //表示已经发送了放弃电话这个请求
              MakePsAthRequest((void*)PsCBackOutgoingCallEnded);
       如果还没被接通,并且已经设置了call_handle,那么就:
              MakePsEndSelectiveCall((void*)HangupReqSucess, handle);
 
提醒:当存在多通电话,没有发生呼叫等待时,【结束单线】菜单的响应函数也是ProcessKBHangupReqEvent()。
 
 
花开两朵,各表一支。
1. void MakePsAthRequest(void *callBack)放弃还没设置call_handle的CALL
{
       放弃电话的消息:
       #define MMI_ATH_REQ                    mmi_cc_ath_req_struct
       typedef struct
       {
              LOCAL_PARA_HDR
              kal_uint8       op_code; /* l4c_ath_req_enum */
       } mmi_cc_ath_req_struct;
 
       Message.oslSrcId = MOD_MMI;
    Message.oslDestId = MOD_L4C;
    Message.oslMsgId = PRT_ATH_REQ;
    Message.oslPeerBuffPtr = NULL;
    athReq = (MMI_ATH_REQ*) OslConstructDataPtr(sizeof(MMI_ATH_REQ));
    Message.oslDataPtr = (oslParaType*) athReq;
 
    if (GetCallAbortReqSentFlag())
    {
        /* set abort MO flag */
        athReq->op_code = L4C_DISCONNECT_MO;
    }
    else
    {
        athReq->op_code = L4C_DISCONNECT_NONE;
    }
 
       SetProtocolEventHandler((PsFuncPtr) callBack, PRT_ATH_REQ_SUCCESS);
 
 
    OslMsgSendExtQueue(&Message);
}
       然后L4返回消息PRT_ATH_REQ_SUCCESS,进入CBACK函数:
void PsCBackOutgoingCallEnded(void *MsgStruct)
{
       设置gCallAbortReqSentFlag=FALSE;
       OutgoingProcessCMEvent(CM_PS_HANGUPSUC, (void*)&handle);
}
 
另一个挂断函数:
void MakePsEndSelectiveCall(void *callBack, CM_CALL_HANDLE handle)
{
       ClearInputEventHandler(MMI_DEVICE_ALL);
       SetChldReqSent(CM_ENDSELECTIVE_REQ_SENT);//设置gChldReqSent
       gChldReqSent可能的值为:
              typedef enum CHLD_REQ_ACTION
{
    CM_ACTION_NONE = 0,
    CM_HANGUPALL_REQ_SENT,                    挂断所有电话
    CM_HANGUPALLACTIVE_REQ_SENT,      挂断所有ACTIVE
    CM_HANGUPALLHLD_REQ_SENT,             挂断所有HOLD
    CM_ENDSELECTIVE_REQ_SENT,               挂断指定的一通电话
    CM_UDUB_REQ_SENT
} CHLD_REQ_ACTION;
 
       Message.oslSrcId = MOD_MMI;
    Message.oslDestId = MOD_L4C;
    Message.oslMsgId = PRT_CALLENDSPECIFIC_EVENT;
 
       具体的消息,主要设置:
              opcode=CSMCC_REL_SPECIFIC_CALL
              call_id=handle
       
       SetProtocolEventHandler((PsFuncPtr) callBack,                                                                                       PRT_CALLENDSPECIFIC_SUCCESS);
    SetProtocolEventHandler((PsFuncPtr) CheckFailureChld,                                                                        PRT_END_CHLD_RSP);
       注意:这里注册了2个CBACK函数,都是将要被调用的。
 
    OslMsgSendExtQueue(&Message);
}
L4返回消息PRT_CALLENDSPECIFIC_SUCCESS之后,进入:
void HangupReqSucess(void *MsgStruct)
{
       返回的消息结构:
              typedef struct
     {
            LOCAL_PARA_HDR
            kal_uint8       call_id;
            kal_uint16     cause;
     } mmi_cc_call_release_ind_struct;
 
       OutgoingProcessCMEvent(CM_PS_HANGUPSUC, (void*)&handle);
}
 
可见,无论是发送什么挂断电话的消息去放弃呼出的电话,最后都是进入状态机:CM_PS_HANGUPSUC。(网络挂断1通ACTIVE或者HOLD CALL,最后也是进入这个函数处理)
ACTION_RESULT ProcessPSHangupSucEvent(void *MsgStruct)
{
       switch (GetCurrentState())
       {
       CASE CM_IDLE_STATE:
                     break;
       CASE CM_OUTGOING_STATE:当前处于OUTGOIN状态,可能存在其他的电话。在下面的处理中,要判断挂断的是什么电话(比如:挂断了正在呼出的电话;或者已经有1通HOLD CALL时,呼出另一同电话,此刻那个HOLD CALL被网络挂断了。。。)。
                     LogCallInfoForCallHistory(*handle);       //把电话信息拷贝到                                                                              cm_p->state_info.CallStructureForCallLog中
                     if (GetCallState(*handle) == CM_OUTGOING_STATE)//挂断的就是                        是呼出的电话,此时这个电话还处于OUTGOING STATE
                     {
                            flag = TRUE; //方便下面的操作
              GetEndTimeAndNotifyCallAborted();//注册函数:
                                          GetDateTimeAndNotifyCallAbortedCBack()。在这里,                                                 设置了start_time and end_time,然后LogCall( )。再然后                                     进入EntryScrNotifyCallAborted()显示“通话已放弃”                                      这个消息。
                     }
                     else //虽然此时CM处于OUTGOING状态(正在呼出电话),但是挂        断的是其他的电话(比如在make call之前已经有一通ACTIVE CALL了)
                     {
                            GetEndTimeAndNotifyEndCallDuration(*handle);//设置CALL的                                              结束时间为当前时间,并且把最后通话时间和总的                                                  通话时间写入NVRAM中,然后注册:                                                CMGetExactTime(GetDateTimeAndNotifyEndCallDurationCBack);                                            最后进入EntryScr1004NotifyEndCallDuration()。
                     }
                     SetTempUseIPNumber(FALSE);      //设置gTempUseIPNum=0
                     ResetCallflag((*handle), CM_HANGUP_REQUESTED, TRUE);
           SetCallState((*handle), CM_IDLE_STATE, TRUE);
                     根据不同的状态来设置CM状态。
                     break;
       CASE CM_INCOMING_STATE:比如在呼叫等待时,挂断一通ACTIVE                                                                              CALL,或者HOLD CALL。
                     LogCallInfoForCallHistory(*handle);//拷贝电话信息
                     /* rel active and accept waiting but waiting is released by network */
                     if (GetIncomingCallHandle() == *handle)
                     {
                              SetCurrentState(GetPreviousState());
                SetPreviousState(CM_INCOMING_STATE);
                SetCallState((*handle), CM_IDLE_STATE, TRUE);
                     }
                     else//在CM处于INCOMING状态下挂断ACTIVE或HOLD CALL。
                            //此时,不再需要设置CM的当前状态(仍然为INCOING)
                     {
                              GetEndTimeAndNotifyEndCallDuration(*handle);
                SetCallState((*handle), CM_IDLE_STATE, TRUE);
 
                              设置CM的prev_state为:ACTIVE或者HOLD。
                     }
                     break;
       CASE CM_HOLD_STATE:
       CASE CM_ACTIVE_STATE:
                       LogCallInfoForCallHistory(*handle);
            GetEndTimeAndNotifyEndCallDuration(*handle);               
            ResetCallflag((*handle), CM_HANGUP_REQUESTED, TRUE);
            SetCallState((*handle), CM_IDLE_STATE, TRUE);
                       设置CM的当前和之前状态。
       }
}
然后,L4返回消息PRT_END_CHLD_RSP,进入:CheckFailureChld()。这个函数主要就是设置gChldReqSent=CM_ACTION_NONE。
 
 
学习一下这个函数:GetEndTimeAndNotifyEndCallDuration(*handle);用来显示通话时间的提示信息
void GetEndTimeAndNotifyEndCallDuration(CM_CALL_HANDLE handle)
{
       gTimeStructForEndedCallStartTime—保存了结束的通话的开始时间
       如果开始时间不为0的话,那么就设置cm_p->state_info.CallStructureForCallLog.end_time为当前的时间,然后:
       CHISTLogDialedCallDuration(&cm_p->state_info.CallStructureForCallLog);或者       CHISTLogRecvdCallDuration(&cm_p->state_info.CallStructureForCallLog);主要就是把最后通话时间,以及总的通话时间写入到NVRAM中。
       最后注册:CMGetExactTime(GetDateTimeAndNotifyEndCallDurationCBack);这个函数主要做:
       EntryScr1004NotifyEndCallDuration();//显示信息ShowCategory63Screen()。
    memset(&cm_p->state_info.CallStructureForCallLog, 0, sizeof(CALL_INFO));
       
}
 
 
呼出的电话被网络接通(对方接听电话)
L4返回消息PRT_OUTGOINGCALL_CONNECTED,进入:
void OutgoingCallConnected(void *MsgStruct)
{
返回消息的结构:
#define MMI_CONNECT_IND                mmi_cc_call_connect_ind_struct
 
typedef struct
       {
              LOCAL_PARA_HDR
              l4c_number_struct       num;
              l4c_sub_addr_struct    sub_addr;
              kal_uint8       call_type;
              kal_uint8       call_id;
       } mmi_cc_call_connect_ind_struct;
 
       首先停止手机听筒的“嘟嘟”声
       playRequestedTone(CONNECT_TONE);
              学习一下声音的控制:
              1.声音的种类:#define ERROR_TONE  1
#define CONNECT_TONE 2
#define CAMP_ON_TONE 3
#define WARNING_TONE 4
#define INCOMING_CALL_TONE 5
#define ALARM_TONE 6
#define POWER_ON_TONE 7
#define POWER_OFF_TONE 8
#define COVER_OPEN_TONE 9
#define COVER_CLOSE_TONE 10
#define MESSAGE_TONE 11
#define KEYPAD_PLAY_TONE 12
#define SUCCESS_TONE 13
#define SAVE_TONE 14
#define EMPTY_LIST_TONE 15
#define GENERAL_TONE 16
#define SMS_IN_CALL_TONE 17
#define AUX_TONE  18
#define WARNING_TONE_IN_CALL 19
#define ERROR_TONE_IN_CALL 20
#define CONNECT_TONE_IN_CALL 21
#define SUCCESS_TONE_IN_CALL 22
/* Brian added for battery indication, 2003/11/17 */
#define BATTERY_LOW_TONE 23
#define BATTERY_WARNING_TONE 24
#define CALL_REMINDER_TONE 25
#define CCBS_TONE 26
#define CONGESTION_TONE 27
#define AUTH_FAIL_TONE 28
#define NUM_UNOBTAIN_TONE 29
#define CALL_DROP_TONE 30
 
                     2 .void playRequestedTone(ALL_TONE_ENUM playtone)// API to all                               applications to play tone.
 
       //下面是log call,注意看
       handle = GetOutgoingCallHandle();
 
    /* log MO call with original number and name */
    SetCalledNumWithTypeAux(GetMMIStructIndexof(handle), MsgStruct);这个函数把AllCalls[index]中的number拷贝到num中,然后用L4返回来的网络接通的号码msgBuf->num.number拷贝到number中,并且用返回来的msgBuf->call_type拷贝到AllCalls[index].call_trpe。 也就是说,在下面的call log中,使用L4返回来的信息。
    DTGetRTCTime(&t);  获取系统的当前时间,以便下面设置为开始时间
    UpdateCallStartTimeAndLogCall(handle, &t);设置CALL的开始时间为上面的t,然后LogCallWithStartTime(&cm_p->state_info.AllCalls[index]);
    
    /* set MO name for display in case number is changed by PS */
    SetCalledNumWithType(GetMMIStructIndexof(handle), MsgStruct);如果AllCalls[index]中的number与num不一致(说明在上面的函数中,号码被L4改变过),那么就用电话簿中的信息重新设置AllCalls[index]的pBname和name_dcs,以及number。这里有个问题:实验发现在电话簿和call log中,号码相同但是名字不相同,通过call log呼出电话,在OUTGOING 界面显示的是CALL LOG中的名字,接通之后显示的仍然是CALL LOG中的名字。这里已经设置AllCalls的名字为电话簿中的名字了啊? 难道在哪里又设置成CALL LOG中了??
解答:在函数SetCalledNumWithTypeAux()和()中,存在一个宏:
__MMI_CM_DISPLAY_CONN_NUM__。这个宏是关闭的,因此实际上上面所描述的:“先用L4返回的消息设置AllCalls,然后LOG CALL,然后再恢复电话簿里的信息到AllCalls”这个步骤并未执行。也就是说AllCalls里的信息在LOG前后没有改变过。
 
       SetTempUseIPNumber(FALSE);
       OutgoingProcessCMEvent(CM_PS_CALLCONNECTED, &handle);
}
 
ACTION_RESULT ProcessPSCallconnectedEvent(void *MsgStruct)
{
       此时,CM的当前状态只可能是OUTGOING STATE
       MakeHold( );
       SetPreviousState(GetCurrentState());
    SetCurrentState(CM_ACTIVE_STATE);
       SetCallState(gtmpOutgoingIndex, CM_ACTIVE_STATE, FALSE);
 
       if (GetTotalCallCount() > 1)       此时,不止1通电话,要显示电话列表
       {
              handle = GetIncomingCallHandle();
       if (handle != -1)    此时还存在呼叫等待的电话,要显示INCOMING界面
              {
                      SetPreviousState(CM_ACTIVE_STATE);
           SetCurrentState(CM_INCOMING_STATE);
 
                     设置gPhoneNumberStruct结构为呼叫等待的电话信息
                     GoBackToHistory(ITEMSCR_INCOMING_CALL); 回到来电的界面
              }
              else        //没有呼叫等待的电话
              {
                     if (IsScreenPresent(ITEM_SCR_USSN_MSG))
          {
                GoBackHistory();
          }
                     else
                     {                                                                                                                       GoBackToHistory(SCR_CM_ACTIVECALLSCREEN);
                     }
              }
       }
       else 只有刚刚接通的这1通电话
       {
              如果之前已经存在SCR_CM_ACTIVECALLSCREEN,就                                                 GoBackToHistory(SCR_CM_ACTIVECALLSCREEN);
              如果不存在,则:
                            EntryScr1002ActiveCall();  //displays the list of active/Held calls                                                                                     or the single active/held call
                 DeleteUptoCmScreen();
       }
}
然后进入void DummyScr1002ActiveCall(MYTIME *t)
{
       这个IF主要是在接听来电的时候被执行。在来电时,变量gCallHandleForStartTimeUpdate被设置成来电的call_handle,接通之后呢,进入这个函数,显示电话列表,于是就被调用,设置开始时间,并且LOG CALL。
对于OUTGOING CALL,在电话被网络接通的时候,进入回调函数OutgoingCallConnected()时,就已经LOG CALL了。
       if (GetCallHandleForStartTimeUpdate())
    {
        UpdateCallStartTimeAndLogCall(GetCallHandleForStartTimeUpdate(), t);
        SetCallHandleForStartTimeUpdate(0);
    }
       nActiveCall = GetTotalActiveCallCount();
    nHoldCall = GetTotalHoldCallCount();
 
    if (nActiveCall + nHoldCall == 0)
    {
        GetOutOfCMApplication();
        return;
    }
 
设置几个全局变量:
gcallListlen----电话列表的长度
gcallList--------电话列表显示的名字
另外:
gHiliteCall------当前高亮的电话索引
       gcallListlen = 
                     GetAllDispNameorNum(gcallList, gcallListImage, nIconIds, &dummy);
 
       nAllcall =             GetAllDispNameorNum(strDispnames,nImgIds,nIconIds,&firstActiveCallIndex);和上面的函数一样的,只不过设置的变量不同。这里主要是用在显示列表中。firstActiveCallIndex保存的最后的那通电话的索引,用来设置高亮菜单。在排列所有的通话时,通话最早的排在最上面,最后开始通话的排在最下面。高亮的是最下面的也就是最后通话的。
 
在显示通话列表状态时,右软件有关扩音器的操作变量是:
gLoudSpeaker=1,表示扩音器已经激活,此时,设置alert_info.IsHFree=1,右软件将                        要显示“正常”(HHeld)。
gLoudSpeaker=0,表示扩音器已经关闭,此时,设置alert_info.IsHFree=0,右软件将                        要显示“免提”(HFree)。
 
 
       InitializeTimeStructure(&timeStruct, t);//t是作为参数传过来的当前时间,这个函数是获取电话列表中,最早的那个电话时间设置到timeStruct中。并且启动了通话时间的提醒。定时器是CM_CTR_TIMER,响应函数是CheckCtrExpiry().
 
       if ((nActiveCall + nHoldCall) > 1)     //大于1通电话
       {
              if (GetDisconnectingCallHandle() != -1)   //存在正在挂断的电话
                     ShowCategory19Screen( );       //左、右软件都为0
              else
                     ShowCategory19Screen( );       //左、右软件有选项
       }
       else        //只有这1通电话
       {
              设置显示的图片。3中可能:
(1)    使用默认的图片         nImgIds[0]=IMG_CM_STATE_SINGLE_ACTIVE;
(2)    使用系统的4幅图片
(3)    使用文件里的图片
              (2)(3)通过调用
              GetSingleActiveCallInfo(&tmp, &picid, &pic_storeindex)来判断。
              其中如果是2:nImgIds[0] = picid;
                     如果是3:imgPath=GetActiveCallImgPath(tmp, pic_storeindex); 
if (GetDisconnectingCallHandle() != -1)   //存在正在挂断的电话
{       ShowCategory20Screen( );       //左、右软件都为0
}
else
{
       ShowCategory20Screen( );       //左、右软件都有选项
}
 
下面开始设置一些KeyHandler
EntryScr1003CMActiveCallOptions()设置的左软件的选项入口
       }
}