放弃呼出的电话,在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()设置的左软件的选项入口
}
}