来电和呼叫等待
在空闲状态下是来电,在ACTIVE或者HOLD状态下是呼叫等待。
1.IDLE状态下来电,L4发送消息PRT_INCOMINGCALL_EVENT
void PsCBackCallIncoming(void *info)
{
       参数:#define MMI_INCOMING        mmi_cc_call_ring_ind_struct
       typedef struct
       {
              LOCAL_PARA_HDR
              kal_uint8       call_id;
              l4c_number_struct       num;
              l4c_sub_addr_struct    sub_addr;
              kal_uint8       name[30];
              kal_uint8       auto_answer;
              kal_uint8       call_type;
       } mmi_cc_call_ring_ind_struct;
 
       首先获取来电的号码,类型,句柄,然后判断是否启动了拒接不明来电,就是没有号码的来电。如果启用了,就自动拒接。也就是说,如果是匿名来电,并且手机启动了拒接功能,那么就直接发送ATH去拒接电话。即没有把来电的信息添加到AllCalls中。
       gRejectCallFlag判断当前是否开启拒接不明来电
       if(    GetRejectUnknownCallFlag() && 
              (pfnUnicodeStrlen((PS8)myIncmg.Number) == 0))
       {
              //Reject;
              SetClearKeyFlag(FALSE);
              MakePsAthRequest( (void*)PsCBackIncomingCallRejected);
              return;
       }与主动拒接来电的处理是相同的。
 
       ProcessIncomingEvents(CM_PS_CALL_INCOMING info);
}
 
进入状态机处理函数,参数info是来电信息
ACTION_RESULT ProcessIncomingCallEvent(void *info)
{
       gAttempToAnswer = FALSE;
       LeftKeyIncomingShowMute=FALSE;
       SetAnswerMode(NULL);//设置应答模式gCMAnsMode=0
       SetCallWaitFlag(FALSE);//设置呼叫等待的标志gCallWaitFlag=0
 
       switch(GetCurrentState())   //处理2种当前状态:IDLE,OUTGOING
       {
              case CM_IDLE_STATE:
                     SetPreviousState(GetCurrentState());
          SetCurrentState(CM_INCOMING_STATE);
                     AddNewCallInfo(
                myIncmg.Number,
                GetCurrentState(),
                GetPreviousState(),
                CM_CALL_MT,
                (CM_CALL_HANDLE) myIncmg.callHandle,
                myIncmg.callType);
 
              黑名单的拒接处理。
              gBlackListFlag指示是否启动了来电警卫。
              gBlackIncomingFlag指示拒接了一个黑名单中的电话
              #ifdef __MMI_CM_BLACK_LIST__
      if (BlockedHandle((CM_CALL_HANDLE) myIncmg.callHandle) == TRUE)
      {
        SetBlackIncomingFlag(TRUE);
        ProcessIncomingEvents(CM_KB_INCOMING_CALL_REJECT, info);
        return CM_CALL_SUCCESS;
     }
    #endif 
 
              自动应答操作:
              gCMAnsMode---自动应答变量
              gAutoAnswerFlag—指示已经自动应答了
                     SetAnswerMode(GetAnsweringMode());
 
            if (((MMI_ANSWERING_MODE*) GetAnswerMode())->automatic == TRUE && (((MMI_INCOMING*)info)->call_type != CSMCC_FAX_CALL))
            {
                SetAutoAnswerFlag(TRUE);// gAutoAnswerFlag
                StartTimer(
                    CM_AUTOANSWER_NOTIFYDURATION_TIMER,
                    CM_AUTOANSWER_NOTIFY_TIMEOUT,       2秒钟
                    KbCBackCallIncomingAccepted);
            }
 
                     EntryScrIncomingCallEvent();
                     if (!GetRingingFlag())
              {
                 ShowIncomingCallIndication();
              }
              AddMarkerToHistory();
                     return CM_CALL_SUCCESS;
 
       case CM_OUTGOING_STATE:
                     if (cm_p->redial_info.RedialTimer == TRUE)//正处在自动重拨
                     {
                            与上面的处理一样,不同的就是:终止了自动重拨                                             ResetRedialAttempts();
                     }
                     else //MO MT冲突
                     {
                            冲突的话,终止MO,以MT为优先,与上面的处理相同
                     }
       }
}
 
*  This function is the entry screen for the incoming call*
void EntryScrIncomingCallEvent(void)
{
       获取显示的来电姓名,图像等
       
       if (GetDisconnectingCallHandle() != -1)   //有正在挂断的电话
       {
              ShowCategory17Screen();
       }
       else //没有正在挂断的电话
       {
              #ifdef __MMI_INCOMING_CALL_VIDEO__   //来电显示VIDEO
              if ((imgId & 0x8000) || ((imgId & 0x3fff) >= VDO_ID_PHB_MTCALL_1))
                     ShowCategory17Screen();
              else
              #endif
                     ShowCategory17Screen()
 
              开始设置按键响应函数
              SetRightSoftkeyFunction(KbCBackCallIncomingRejected,                                                                                     KEY_EVENT_UP);
              if (GetTotalCallCount() > 1)
              {
                     SetLeftSoftkeyFunction(EntryScrIncomingMultipleOptions,                                                                              KEY_EVENT_UP);如果有多通电话时,发生                                                         呼叫等待时,左软件的选项入口函数
                     
              }
              else 
              {
                     SetKeyHandler(KbCBackCallIncomingAccepted, KEY_SEND,                                                              KEY_EVENT_DOWN);
            SetKeyHandler(KbCBackCallIncomingRejected, KEY_END,                                                              KEY_EVENT_DOWN);
              SetKeyHandler(KbCBackCallIncomingRejected, KEY_RSK,                                                                  KEY_EVENT_DOWN);
              }
       }
}
 
呼叫等待
L4发送来消息PRT_INCOMING_CALL_WAIT,进入:
void PsCBackCallWait(void *info)
{
    ProcessIncomingEvents(CM_PS_CALL_WAIT, info);
}
 
首先设置:
SetAutoReleaseFlag(TRUE);     //gAutoReleaseFlag=TRUE
ReleaseCall();这个函数处理过程是:针对当前所有的curr_state=CM_DISCONNECTING_STATE的CALL,
                     MakePsReleaseCompleteRequest(handle); PRT_RELCOMP_EVENT 
           OutgoingProcessCMEvent(CM_PS_HANGUPSUC, (void*)&handle);
然后再设置:SetAutoReleaseFlag(FALSE); //gAutoReleaseFlag=FALSE
 
再进入:
ACTION_RESULT ProcessCallWait(void *info)
{
       gAttempToAnswer=FALSE
       SetPreviousState(GetCurrentState());
    SetCurrentState(CM_INCOMING_STATE);
 
       SetCallWaitFlag(TRUE);//gCallWaitFlag=TRUE
       AddNewCallInfo(
        myIncmg.Number,
        GetCurrentState(),
        GetPreviousState(),
        CM_CALL_MT,
        (CM_CALL_HANDLE) myIncmg.callHandle,
        myIncmg.callType);
 
       黑名单处理,自动拒接,与上面的相同
       if (BlockedHandle((CM_CALL_HANDLE) myIncmg.callHandle) == TRUE)
    {
        ProcessIncomingEvents(CM_KB_INCOMING_CALL_REJECT, info);
        return CM_CALL_SUCCESS;
    }
 
       EntryScrIncomingCallEvent();
 
    StartRingTone(TONE_CALL_WAITING);
 
    if (!IsScreenPresent(CM_SCR_MARKER))
    {
        AddMarkerToHistory();
    }
}
 
拒接来电
来电的拒接,可以有这样几种情况:1自动拒接匿名来电,2自动拒接黑名单中的号码来电,3用户按下右软件手动拒接来电。这3种方式的代码进入点是不一样的,但是,本质操作是相同的。
 
手动按下右软件[拒接],进入:
void KbCBackCallIncomingRejected(void)
{     
       gAttempToReject=TRUE
       UnSilencethePhone();
    StopIncomingCallIndication();在这里清除了呼叫等待的标志gCallWaitFlag
    ProcessIncomingEvents(CM_KB_INCOMING_CALL_REJECT, NULL); 上面的拒接黑名单的操作就是直接进入这里,即直接进入状态机拒接,没有设置gAttempToReject,没有停止IncomingCallIndication(因为就没有打开)。
}
 
进入状态机,这里分为3中情况:
case CM_KB_INCOMING_CALL_REJECT:
       handle = GetIncomingCallHandle();
    if (GetTotalCallCount() > 1)   //拒接的是呼叫等待的来电
       {
              SetCallState(handle, CM_DISCONNECTING_STATE, TRUE);
              MakePsSendUDUB((void*)PsCBackIncomingCallRejected);
                     设置gChldReqSent=CM_UDUB_REQ_SENT
                     发送的消息是:PRT_UDUB_REQ
                     消息opnode是:CSMCC_REL_HELD_OR_UDUB.
                     L4返回消息是:PRT_UDUB_RES_SUCCESS
       }
       else if(GetCCBSFlag() == MMI_TRUE)       //拒接的时遇忙回叫的来电
       {
              SetCallState(handle, CM_DISCONNECTING_STATE, TRUE);
        MakePsEndSelectiveCall((void*)PsCBackIncomingCallRejected, handle);
                     设置gChldReqSent=CM_ENDSELECTIVE_REQ_SENT
                     发送的消息是:PRT_CALLENDSPECIFIC_EVENT
                     消息opnode是:CSMCC_REL_SPECIFIC_CALL
                     L4返回消息是:PRT_CALLENDSPECIFIC_SUCCESS
       }
       else  //IDLE状态下的一般来电
       {
              SetCallState(handle, CM_DISCONNECTING_STATE, TRUE);
        MakePsAthRequest((void*)PsCBackIncomingCallRejected);自动拒接匿名来电是直接进入这里,即直接发送ATH到L4。
                     发送的消息是:PRT_ATH_REQ
                     消息的opnode是:L4C_DISCONNECT_NONE
                     L4返回的消息是:PRT_ATH_REQ_SUCCESS
       }
       break;
 
 
CALL BACK函数:
void PsCBackIncomingCallRejected(void *info)
{
       ProcessIncomingEvents(CM_PS_INCOMING_CALL_REJECTED, info);
}
 
g_bUserReject=TRUE;
SetIncomingCallDroppedFlag(TRUE); gIncomingCallDroppedFlag=TRUE
ProcessIncomingCallRejected(info);
 
ACTION_RESULT ProcessIncomingCallRejected(void *info)    //来电时,如果网络挂断了这个来电(对方放弃),不论是什么类型的电话,只要是incoming call,就直接进入这个函数进行一些处理操作。返回的消息:
#define MMI_RELEASE_IND                mmi_cc_call_release_ind_struct
       typedef struct
       {
              LOCAL_PARA_HDR
              kal_uint8 call_id;
              kal_uint16       cause;
       } mmi_cc_call_release_ind_struct;
{
       if ((GetTotalCallCount() > 1) && 
              (GetIncomingCallHandle() != ((MMI_RELEASE_IND*) info)->call_id))
       /* use chld to reject */
        /* dropped is not MT call, use default drop call handler */
       {
              PsCBackNetworkCallDropped(info);
       }
       else if ((GetTotalCallCount() == 1 && GetCurrentState() != CM_INCOMING_STATE) ||                           (GetIncomingCallHandle() == -1))
    {
        /* use ath to reject or call already dropped when ath rsp comes */
              OutgoingProcessCMEvent(CM_PS_HANGUPSUC, (void*)&handle);
       }
 
       gAttempToReject=TRUE;
       清除CALL的CM_HANGUP_REQUESTED标志
       根据来电之前的CM状态,设置CM的之前和当前状态
 
       LogCallInfoForCallHistory(GetIncomingCallHandle());
    PurgeIncomingCallStructure();在这个函数中,有SetCallState(CM_IDLE_STATE)。如果拒接的是黑名单中的电话,那么直接ResetCallInfo(index, FALSE)清除AllCalls中的参数,然后电话总数减一;如果不是黑名单中的电话,那么将分为2中处理:missed和rejected。
                     SetCallEndedBeforeConnFlag(TRUE);   //gCallEndedBeforeConnFlag=TRUE
                     if( g_bUserReject )
                            GetEndTimeAndNotifyCallRejected();
                     else 
                GetEndTimeAndNotifyCallMissed();
}
 
 
提醒:呼叫等待的【接听】。
       只存在ACTIVE CALL或者只存在HOLD CALL时,才有【接听】菜单。即:如果同时存在ACTIVE和HOLD CALL,那么将不会有【接听】菜单。HiliteMenuIncomingAnswer(),响应函数:KbCBackCallIncomingAccepted
接听INCOMING CALL
来电的接听有2种方式:1自动接听:定时器溢出时自动调用接听函数CM_AUTOANSWER_NOTIFYDURATION_TIMER,2手动按下左软件或者[SEND]键(只有1路通话时)
void KbCBackCallIncomingAccepted(void)
{
       这几种情况下,不能接听来电:1.同时存在ACTIVE CALL,HOLD CALL,2当前存在CM_HOLD_REQUESTED,或者CM_RETRIEVE_REQUESTED,或者CM_SPLIT_REQUESTED,3.来电不是CSMCC_VOICE_CALL。
       以上几种情况直接显示错误信息,然后返回
       
       如果已经启动了自动应答(比如在自动应答之前就手动接听了),则停止自动应答定时器,设置gAutoAnswerFlag=FALSE
 
       UnSilencethePhone();
    StopIncomingCallIndication();
    ProcessIncomingEvents(CM_KB_INCOMING_CALL_ACCEPT, NULL);
}
 
void ProcessStateCheckIncomingCall(void)处理在接听之前,做一些事情
{
              gAttempToAnswer = TRUE;
 
              根据当前是否有ACTIVE CALL,发送不同的消息去接听来电。
              if (GetTotalActiveCallCount() > 0)
        {
            gAcceptIncoming = TRUE;
            SetHoldFlag();
            MakePsActiveHold((void*)PsCBackActiveCallsHeld);
        }
        else
        {
            MakePsCallAcceptIncoming((void*)PsCBackIncomingCallAccepted);
        }
}
先来看第二种情况,简单一些,直接接听(当前没有ACTIVE CALL)
void MakePsCallAcceptIncoming(void *callBack)
{
       发送到L4的消息:PRT_INCOMINGCALL_ACCEPT_EVENT
       L4返回消息:PRT_INCONINGCALL_ACCEPT_SUCCESS
}进入回调函数:
void PsCBackIncomingCallAccepted(void *info)
{     
       gAttempToAnswer=FALSE
       ProcessIncomingEvents(CM_PS_INCOMING_CALL_CONNECTED, info);
}
第一种情况:先HOLD当前的ACTIVE CALL,然后接听来电
void MakePsActiveHold(void *callBack)
{
       发送到L4的消息结构:
       #define MMI_CC_CHLD_REQ                mmi_cc_chld_req_struct
       typedef struct
       {
              LOCAL_PARA_HDR
              kal_uint8 opcode; /* csmcc_crss_req_enum */
              kal_uint8 call_id;
       } mmi_cc_chld_req_struct;
 
       发送到L4的消息是:PRT_RETRIEVECALL_EVENT
       消息opnode:CSMCD_HOLD_ACTIVE_AND_ACCEPT
       L4返回的消息是:PRT_END_CHLD_RSP
}
进入回调函数:
void PsCBackActiveCallsHeld(void *info)
{
       ProcessIncomingEvents(CM_PS_ACTIVE_CALL_HELD, info);
}ACTION_RESULT ProcessCallsHeld(void *info)
{
       此刻,至少有2通电话,因此,MMI与L4要进行一次电话同步
       if (GetTotalCallCount() > 0)
    {
        SyncCallList();
    }
 
    gAttempToAnswer = FALSE;
 
       switch (GetPreviousState())我认为:此时CM的prev_state只可能为CM_ACTIVE_SATAE,但是代码中为什么还列举了那么多CASE?
       {
              case CM_ACTIVE_STATE:
            if (gAcceptIncoming)
            {
                MakeHold();
                ProcessIncomingEvents(CM_PS_INCOMING_CALL_CONNECTED, info);
                gAcceptIncoming = FALSE;
            }
       }
} 
无论是哪种方式接听来电,最后都是进入这个函数处理:
ACTION_RESULT ProcessAcceptIncomingCall(void *info)
{
       SetCallHandleForStartTimeUpdate(GetIncomingCallHandle());设置变量:                                                 gCallHandleForStartTimeUpdate,以便在Dummy1002Screen()中log call。
       switch (GetPreviousState())  //根据CM的prev_state进行不同处理
       {
              case CM_IDLE_STATE:
                     设置CM的状态:之前INCOMING,现在:ACTIVE
                     设置这个CALL的当前状态:ACTIVE。
                     EntryScr1002ActiveCall();
                     break;
              case CM_ACTIVE_CALL:
                     设置CM的状态:之前:INCOMING,当前:ACTIVE
                     设置CALL的当前状态:ACTIVE
                     进行SMS的SCREEN的一些设置操作
                     最后,直接或通过GoBackToHistory进入:EntryScr1002ActiveCall()
                     break;
              case CM_HOLD_STATE:
                     CM_INCOMING_STATE:
                     CM_OUTGOING_STATE:
                     操作大体与上面都相同,都是设置CM的状态,设置CALL的ACTIVE状态。               然后进入Entry1002ActiveCall()中。
       }
}