来电和呼叫等待
在空闲状态下是来电,在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()中。
}
}