• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ims_control.h"
17 
18 #include "cellular_call_hisysevent.h"
19 #include "cellular_call_register.h"
20 #include "emergency_utils.h"
21 #include "module_service_utils.h"
22 #include "securec.h"
23 #include "standardize_utils.h"
24 
25 namespace OHOS {
26 namespace Telephony {
~IMSControl()27 IMSControl::~IMSControl()
28 {
29     TELEPHONY_LOGI("~IMSControl start");
30     ReleaseAllConnection();
31 }
32 
Dial(const CellularCallInfo & callInfo,bool isEcc)33 int32_t IMSControl::Dial(const CellularCallInfo &callInfo, bool isEcc)
34 {
35     TELEPHONY_LOGI("Dial start");
36     DelayedSingleton<CellularCallHiSysEvent>::GetInstance()->SetCallParameterInfo(
37         callInfo.slotId, static_cast<int32_t>(callInfo.callType), callInfo.videoState);
38     int32_t ret = DialPreJudgment(callInfo, isEcc);
39 #ifdef BASE_POWER_IMPROVEMENT_FEATURE
40     if (ret == CALL_ERR_GET_RADIO_STATE_FAILED) {
41         return SavePendingEmcCallInfo(callInfo);
42     }
43 #endif
44     if (ret != TELEPHONY_SUCCESS) {
45         return ret;
46     }
47     ModuleServiceUtils moduleServiceUtils;
48     RegServiceState regState = moduleServiceUtils.GetPsRegState(callInfo.slotId);
49     if (!(regState == RegServiceState::REG_STATE_IN_SERVICE || isEcc)) {
50         TELEPHONY_LOGE("can not dial.");
51         return TELEPHONY_ERR_NETWORK_NOT_IN_SERVICE;
52     }
53     // sip uri needs to remove separator
54     std::string newPhoneNum(callInfo.phoneNum);
55     StandardizeUtils standardizeUtils;
56     if (newPhoneNum.find('@') != std::string::npos || newPhoneNum.find("%40") != std::string::npos) {
57         newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(newPhoneNum);
58     }
59 
60     CLIRMode clirMode = CLIRMode::DEFAULT;
61     if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, true)) {
62         TELEPHONY_LOGI("Dial return, mmi code type.");
63         return RETURN_TYPE_MMI;
64     }
65     return DialJudgment(callInfo.slotId, newPhoneNum, clirMode, callInfo.videoState);
66 }
67 
DialJudgment(int32_t slotId,const std::string & phoneNum,CLIRMode & clirMode,int32_t videoState)68 int32_t IMSControl::DialJudgment(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState)
69 {
70     TELEPHONY_LOGI("DialJudgment entry.");
71     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
72     if (!CanCall(connectionMap_)) {
73         TELEPHONY_LOGE("DialJudgment return, error type: call state error.");
74         CellularCallHiSysEvent::WriteDialCallFaultEvent(
75             slotId, INVALID_PARAMETER, videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "ims dial call state error");
76         return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT;
77     }
78     pendingPhoneNumber_ = phoneNum;
79     // Calls can be put on hold, recovered, released, added to conversation,
80     // and transferred similarly as defined in 3GPP TS 22.030 [19].
81     for (auto &connection : connectionMap_) {
82         if (connection.second.GetStatus() == TelCallState::CALL_STATUS_ACTIVE &&
83             !connection.second.IsPendingHangup()) {
84             TELEPHONY_LOGI("DialJudgment, have connection in active state.");
85             EmergencyUtils emergencyUtils;
86             bool isEmergency = false;
87             emergencyUtils.IsEmergencyCall(slotId, phoneNum, isEmergency);
88             connection.second.SetHoldToDialInfo(phoneNum, clirMode, videoState, isEmergency);
89             connection.second.SetDialFlag(true);
90             // - a call can be temporarily disconnected from the ME but the connection is retained by the network
91             return connection.second.SwitchCallRequest(slotId, videoState);
92         }
93     }
94     return EncapsulateDial(slotId, phoneNum, clirMode, videoState);
95 }
96 
EncapsulateDial(int32_t slotId,const std::string & phoneNum,CLIRMode & clirMode,int32_t videoState) const97 int32_t IMSControl::EncapsulateDial(
98     int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState) const
99 {
100     TELEPHONY_LOGI("EncapsulateDial start");
101 
102     ImsDialInfoStruct dialInfo;
103     dialInfo.videoState = videoState;
104     dialInfo.bEmergencyCall = false;
105     EmergencyUtils emergencyUtils;
106     emergencyUtils.IsEmergencyCall(slotId, phoneNum, dialInfo.bEmergencyCall);
107 
108     /**
109      * <idx>: integer type;
110      * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1
111      * this number can be used in +CHLD command operations
112      * <dir>:
113      */
114     dialInfo.phoneNum = phoneNum;
115     /**
116      * <n> (parameter sets the adjustment for outgoing calls):
117      *  0	presentation indicator is used according to the subscription of the CLIR service
118      *  1	CLIR invocation
119      *  2	CLIR suppression
120      */
121     dialInfo.clirMode = clirMode;
122     /**
123      * An example of voice group call service request usage:
124      * ATD*17*753#500; (originate voice group call with the priority level 3)
125      * OK (voice group call setup was successful)
126      */
127 
128     CellularCallConnectionIMS cellularCallConnectionIms;
129     return cellularCallConnectionIms.DialRequest(slotId, dialInfo);
130 }
131 
132 #ifdef BASE_POWER_IMPROVEMENT_FEATURE
SavePendingEmcCallInfo(const CellularCallInfo & callInfo)133 int32_t IMSControl::SavePendingEmcCallInfo(const CellularCallInfo &callInfo)
134 {
135         pendingEmcDialCallInfo_.callId = callInfo.callId;
136         pendingEmcDialCallInfo_.slotId = callInfo.slotId;
137         pendingEmcDialCallInfo_.accountId = callInfo.accountId;
138         pendingEmcDialCallInfo_.callType = callInfo.callType;
139         pendingEmcDialCallInfo_.videoState = callInfo.videoState;
140         pendingEmcDialCallInfo_.index = callInfo.index;
141         if (memset_s(pendingEmcDialCallInfo_.phoneNum, kMaxNumberLen, 0, kMaxNumberLen) != EOK) {
142             TELEPHONY_LOGE("memset_s failed!");
143             return TELEPHONY_ERR_MEMSET_FAIL;
144         }
145         if (memcpy_s(pendingEmcDialCallInfo_.phoneNum, kMaxNumberLen, callInfo.phoneNum, kMaxNumberLen) != EOK) {
146             TELEPHONY_LOGE("memcpy_s failed!");
147             return TELEPHONY_ERR_MEMCPY_FAIL;
148         }
149         isPendingEmc_ = true;
150         return TELEPHONY_SUCCESS;
151 }
152 #endif
153 
HangUp(const CellularCallInfo & callInfo,CallSupplementType type)154 int32_t IMSControl::HangUp(const CellularCallInfo &callInfo, CallSupplementType type)
155 {
156     TELEPHONY_LOGI("HangUp start");
157     std::string message = "";
158     switch (type) {
159         case CallSupplementType::TYPE_DEFAULT: {
160             std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
161             auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
162                 connectionMap_, callInfo.index);
163             if (pConnection == nullptr) {
164                 TELEPHONY_LOGE("HangUp return, error type: connection is null");
165                 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
166             }
167             pConnection->SetHangupFlag(true);
168             if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
169                 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
170                     pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
171             }
172             pConnection->SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
173             pConnection->SetDisconnectMessage(message);
174             return pConnection->HangUpRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
175         }
176         case CallSupplementType::TYPE_HANG_UP_HOLD_WAIT:
177             // release the second (active) call and recover the first (held) call
178         case CallSupplementType::TYPE_HANG_UP_ACTIVE: {
179             CellularCallConnectionIMS connection;
180             UpdateCallDisconnectReason(callInfo.callId, RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED,
181                 message);
182             return connection.CallSupplementRequest(callInfo.slotId, type);
183         }
184         case CallSupplementType::TYPE_HANG_UP_ALL: {
185             TELEPHONY_LOGI("HangUp, hang up all call");
186             CellularCallConnectionIMS connection;
187             // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
188             // so the reject interface is reused.
189             {
190                 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
191                 for (auto &connection : connectionMap_) {
192                     connection.second.SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
193                     connection.second.SetDisconnectMessage(message);
194                 }
195             }
196             return connection.RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
197         }
198         default: {
199             TELEPHONY_LOGE("HangUp warring, type is invalid");
200             return TELEPHONY_ERR_ARGUMENT_INVALID;
201         }
202     }
203 }
204 
Answer(const CellularCallInfo & callInfo)205 int32_t IMSControl::Answer(const CellularCallInfo &callInfo)
206 {
207     TELEPHONY_LOGI("IMSControl::Answer start");
208     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
209     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
210         connectionMap_, callInfo.index);
211     if (pConnection == nullptr) {
212         TELEPHONY_LOGE("HangUp return, error type: connection is null");
213         return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
214     }
215     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) &&
216         IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
217         TELEPHONY_LOGD("already threeway mode. hangup holding call and pickup new call");
218         int32_t ret = CheckAndHangupHoldingCall();
219         if (ret != TELEPHONY_SUCCESS) {
220             TELEPHONY_LOGE("hangup holding call failed");
221             return ret;
222         }
223     }
224     auto con = FindConnectionByState<ImsConnectionMap &, CellularCallConnectionIMS *>(
225         connectionMap_, TelCallState::CALL_STATUS_ACTIVE);
226     if (con != nullptr && !con->IsPendingHold() &&
227         pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
228         TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting");
229         return con->SwitchCallRequest(callInfo.slotId, callInfo.videoState);
230     }
231     if (pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING ||
232         pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING ||
233         pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
234         return pConnection->AnswerRequest(callInfo.slotId, callInfo.phoneNum, callInfo.videoState, callInfo.index);
235     }
236     TELEPHONY_LOGE("IMSControl::Answer return, error type: call state error, phone not ringing.");
237     return CALL_ERR_CALL_STATE;
238 }
239 
CheckAndHangupHoldingCall()240 int32_t IMSControl::CheckAndHangupHoldingCall()
241 {
242     for (auto &it : connectionMap_) {
243         CellularCallConnectionIMS holdConn = it.second;
244         if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) {
245             auto callReportInfo = holdConn.GetCallReportInfo();
246             int32_t result = holdConn.HangUpRequest(callReportInfo.accountId,
247                 callReportInfo.accountNum, callReportInfo.index);
248             if (result != TELEPHONY_SUCCESS) {
249                 return result;
250             }
251         }
252     }
253     return TELEPHONY_SUCCESS;
254 }
255 
Reject(const CellularCallInfo & callInfo)256 int32_t IMSControl::Reject(const CellularCallInfo &callInfo)
257 {
258     TELEPHONY_LOGI("IMSControl::Reject start");
259     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
260     auto pConnection =
261         FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callInfo.index);
262     if (pConnection == nullptr) {
263         TELEPHONY_LOGE("IMSControl::Reject, error type: connection is null");
264         return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
265     }
266     if (!pConnection->IsRingingState()) {
267         TELEPHONY_LOGE("IMSControl::Reject return, error type: call state error, phone not ringing.");
268         return CALL_ERR_CALL_STATE;
269     }
270     if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
271         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
272             pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
273     }
274     pConnection->SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_DECLINE);
275     return pConnection->RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
276 }
277 
HoldCall(int32_t slotId)278 int32_t IMSControl::HoldCall(int32_t slotId)
279 {
280     TELEPHONY_LOGI("HoldCall start");
281     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
282     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
283         TELEPHONY_LOGE("HoldCall return, error type: call state error.");
284         return CALL_ERR_CALL_STATE;
285     }
286     CellularCallConnectionIMS cellularCallConnectionIms;
287     return cellularCallConnectionIms.HoldCallRequest(slotId);
288 }
289 
UnHoldCall(int32_t slotId)290 int32_t IMSControl::UnHoldCall(int32_t slotId)
291 {
292     TELEPHONY_LOGI("UnHoldCall start");
293     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
294     for (auto &it : connectionMap_) {
295         CallReportInfo reportInfo = it.second.GetCallReportInfo();
296         if (slotId == reportInfo.accountId && reportInfo.state == TelCallState::CALL_STATUS_HOLDING) {
297             return it.second.UnHoldCallRequest(slotId);
298         }
299     }
300     TELEPHONY_LOGE("UnHoldCall return, not exist hold call.");
301     return TELEPHONY_ERROR;
302 }
303 
SwitchCall(int32_t slotId)304 int32_t IMSControl::SwitchCall(int32_t slotId)
305 {
306     TELEPHONY_LOGI("SwitchCall start");
307     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
308     VideoStateType callMode = VideoStateType::TYPE_VOICE;
309     for (auto &it : connectionMap_) {
310         CallReportInfo reportInfo = it.second.GetCallReportInfo();
311         if (slotId == reportInfo.accountId) {
312             callMode = reportInfo.callMode;
313             break;
314         }
315     }
316     CellularCallConnectionIMS cellularCallConnectionIms;
317     return cellularCallConnectionIms.SwitchCallRequest(slotId, static_cast<int32_t>(callMode));
318 }
319 
320 /**
321  * Add another remote party, to which a private communication has been established using
322  * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then
323  * exceed the maximum number allowed, which results in an active multiParty call.
324  */
CombineConference(int32_t slotId)325 int32_t IMSControl::CombineConference(int32_t slotId)
326 {
327     TELEPHONY_LOGI("CombineConference entry");
328     CellularCallConnectionIMS connection;
329     int32_t voiceCall = 0;
330     return connection.CombineConferenceRequest(slotId, voiceCall);
331 }
332 
HangUpAllConnection(int32_t slotId)333 int32_t IMSControl::HangUpAllConnection(int32_t slotId)
334 {
335     TELEPHONY_LOGI("HangUpAllConnection entry");
336     CellularCallConnectionIMS connection;
337     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
338     if (connectionMap_.empty()) {
339         TELEPHONY_LOGI("connectionMap_ is empty.");
340         return TELEPHONY_ERROR;
341     }
342     for (auto &it : connectionMap_) {
343         int32_t index = it.second.GetIndex();
344         std::string number = it.second.GetNumber();
345         connection.RejectRequest(slotId, number, index);
346     }
347     // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
348     // so the reject interface is reused.
349     return TELEPHONY_SUCCESS;
350 }
351 
InviteToConference(int32_t slotId,const std::vector<std::string> & numberList)352 int32_t IMSControl::InviteToConference(int32_t slotId, const std::vector<std::string> &numberList)
353 {
354     TELEPHONY_LOGI("InviteToConference entry");
355     CellularCallConnectionIMS connection;
356     return connection.InviteToConferenceRequest(slotId, numberList);
357 }
358 
KickOutFromConference(int32_t slotId,const std::string & KickOutString,int32_t index)359 int32_t IMSControl::KickOutFromConference(int32_t slotId, const std::string &KickOutString, int32_t index)
360 {
361     TELEPHONY_LOGI("KickOutFromConference entry");
362     if (KickOutString.empty()) {
363         TELEPHONY_LOGW("KickOutFromConference, splitString is empty.");
364     }
365 
366     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
367     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, index);
368     if (pConnection != nullptr) {
369         return pConnection->KickOutFromConferenceRequest(slotId, pConnection->GetIndex());
370     }
371 
372     TELEPHONY_LOGI("KickOutFromConference: connection cannot be matched, use index directly");
373     CellularCallConnectionIMS connection;
374     return connection.KickOutFromConferenceRequest(slotId, index);
375 }
376 
StartRtt(int32_t slotId,const std::string & msg)377 int32_t IMSControl::StartRtt(int32_t slotId, const std::string &msg)
378 {
379     TELEPHONY_LOGI("StartRtt entry");
380     CellularCallConnectionIMS connection;
381     return connection.StartRttRequest(slotId, msg);
382 }
383 
StopRtt(int32_t slotId)384 int32_t IMSControl::StopRtt(int32_t slotId)
385 {
386     TELEPHONY_LOGI("StopRtt entry");
387     CellularCallConnectionIMS connection;
388     return connection.StopRttRequest(slotId);
389 }
390 
ReleaseAllConnection()391 void IMSControl::ReleaseAllConnection()
392 {
393     TELEPHONY_LOGI("ReleaseAllConnection entry");
394     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
395     connectionMap_.clear();
396 }
397 
GetConnectionMap()398 ImsConnectionMap IMSControl::GetConnectionMap()
399 {
400     TELEPHONY_LOGI("GetConnectionMap entry");
401     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
402     return connectionMap_;
403 }
404 
ReportImsCallsData(int32_t slotId,const ImsCurrentCallList & callInfoList,bool isNeedQuery)405 int32_t IMSControl::ReportImsCallsData(int32_t slotId, const ImsCurrentCallList &callInfoList, bool isNeedQuery)
406 {
407     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
408     if (callInfoList.callSize <= 0) {
409         if (isNeedQuery) {
410             GetCallFailReason(slotId, connectionMap_);
411             return TELEPHONY_SUCCESS;
412         }
413         return ReportHangUpInfo(slotId);
414     } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
415         return ReportIncomingInfo(slotId, callInfoList);
416     } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
417         if (isNeedQuery) {
418             GetCallFailReason(slotId, connectionMap_);
419             return TELEPHONY_SUCCESS;
420         }
421         return ReportUpdateInfo(slotId, callInfoList);
422     }
423     return TELEPHONY_ERROR;
424 }
425 
ReportCallsData(int32_t slotId,const CallInfoList & callInfoList)426 int32_t IMSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
427 {
428     return TELEPHONY_ERROR;
429 }
430 
ReportHangUpInfo(int32_t slotId)431 int32_t IMSControl::ReportHangUpInfo(int32_t slotId)
432 {
433     TELEPHONY_LOGI("ReportHangUpInfo entry");
434     CallsReportInfo callsReportInfo;
435     for (auto &it : connectionMap_) {
436         CallReportInfo reportInfo = it.second.GetCallReportInfo();
437         reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
438         reportInfo.accountId = slotId;
439         reportInfo.reason = static_cast<DisconnectedReason>(it.second.GetDisconnectReason());
440         reportInfo.message = it.second.GetDisconnectMessage();
441         callsReportInfo.callVec.push_back(reportInfo);
442     }
443     if (connectionMap_.empty()) {
444         TELEPHONY_LOGI("connectionMap_ is empty");
445         CallReportInfo reportInfo;
446         reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
447         reportInfo.accountId = slotId;
448         callsReportInfo.callVec.push_back(reportInfo);
449     }
450     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
451         TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr.");
452         return TELEPHONY_ERR_LOCAL_PTR_NULL;
453     }
454     callsReportInfo.slotId = slotId;
455     if (isIgnoredIncomingCall_) {
456         isIgnoredIncomingCall_ = false;
457     } else {
458         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
459     }
460     ReleaseAllConnection();
461     return TELEPHONY_SUCCESS;
462 }
463 
ReportIncomingInfo(int32_t slotId,const ImsCurrentCallList & imsCurrentCallInfoList)464 int32_t IMSControl::ReportIncomingInfo(int32_t slotId, const ImsCurrentCallList &imsCurrentCallInfoList)
465 {
466     TELEPHONY_LOGI("ReportIncomingInfo entry");
467     CallsReportInfo callsReportInfo;
468     for (int32_t i = 0; i < imsCurrentCallInfoList.callSize; ++i) {
469         CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, imsCurrentCallInfoList.calls[i]);
470 
471         CellularCallConnectionIMS connection;
472         connection.SetStatus(static_cast<TelCallState>(imsCurrentCallInfoList.calls[i].state));
473         connection.SetIndex(imsCurrentCallInfoList.calls[i].index);
474         connection.SetNumber(imsCurrentCallInfoList.calls[i].number);
475         connection.SetOrUpdateCallReportInfo(reportInfo);
476         SetConnectionData(connectionMap_, imsCurrentCallInfoList.calls[i].index, connection);
477 
478         callsReportInfo.callVec.push_back(reportInfo);
479     }
480     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
481         TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr.");
482         return TELEPHONY_ERR_ARGUMENT_INVALID;
483     }
484     callsReportInfo.slotId = slotId;
485     if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() &&
486         callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) {
487         isIgnoredIncomingCall_ = true;
488     } else {
489         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
490     }
491     return TELEPHONY_SUCCESS;
492 }
493 
ReportUpdateInfo(int32_t slotId,const ImsCurrentCallList & callInfoList)494 int32_t IMSControl::ReportUpdateInfo(int32_t slotId, const ImsCurrentCallList &callInfoList)
495 {
496     TELEPHONY_LOGD("ReportUpdateInfo entry");
497     CallsReportInfo callsReportInfo;
498     for (int32_t i = 0; i < callInfoList.callSize; ++i) {
499         CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
500         if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) {
501             TELEPHONY_LOGI("only one call, report incoming state instead of waiting state");
502             reportInfo.state = TelCallState::CALL_STATUS_INCOMING;
503         }
504         auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
505             connectionMap_, callInfoList.calls[i].index);
506         if (pConnection == nullptr) {
507             CellularCallConnectionIMS connection;
508             connection.SetOrUpdateCallReportInfo(reportInfo);
509             connection.SetFlag(true);
510             connection.SetIndex(callInfoList.calls[i].index);
511             connection.SetNumber(callInfoList.calls[i].number);
512             SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
513         } else {
514             TelCallState preCallState = pConnection->GetStatus();
515             pConnection->SetFlag(true);
516             pConnection->SetIndex(callInfoList.calls[i].index);
517             pConnection->SetNumber(callInfoList.calls[i].number);
518             pConnection->SetOrUpdateCallReportInfo(reportInfo);
519             TelCallState curCallState = pConnection->GetStatus();
520             if (IsConnectedOut(preCallState, curCallState)) {
521                 pConnection->UpdateCallNumber(pendingPhoneNumber_);
522                 pendingPhoneNumber_.clear();
523                 ExecutePostDial(slotId, pConnection->GetIndex());
524             }
525         }
526         callsReportInfo.callVec.push_back(reportInfo);
527     }
528     callsReportInfo.slotId = slotId;
529     DeleteConnection(callsReportInfo, callInfoList);
530     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
531         TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr.");
532         return TELEPHONY_ERR_LOCAL_PTR_NULL;
533     }
534     if (isIgnoredIncomingCall_) {
535         isIgnoredIncomingCall_ = false;
536     } else {
537         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
538     }
539     return TELEPHONY_SUCCESS;
540 }
541 
EncapsulationCallReportInfo(int32_t slotId,const ImsCurrentCall & callInfo)542 CallReportInfo IMSControl::EncapsulationCallReportInfo(int32_t slotId, const ImsCurrentCall &callInfo)
543 {
544     TELEPHONY_LOGD("EncapsulationCallReportInfo entry");
545     CallReportInfo callReportInfo;
546     if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) {
547         TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail.");
548         return callReportInfo;
549     }
550 
551     StandardizeUtils standardizeUtils;
552     std::string phoneNumber = callInfo.number;
553     callReportInfo.name = callInfo.number.empty() ? "" : callInfo.name;
554     std::string newString = standardizeUtils.FormatNumberAndToa(phoneNumber, callInfo.toa);
555     size_t cpyLen = strlen(newString.c_str()) + 1;
556     if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) {
557         TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
558         return callReportInfo;
559     }
560     if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) {
561         TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
562         return callReportInfo;
563     }
564     callReportInfo.index = callInfo.index;
565     callReportInfo.accountId = slotId;
566     callReportInfo.state = static_cast<TelCallState>(callInfo.state);
567     callReportInfo.voiceDomain = callInfo.voiceDomain;
568     callReportInfo.callType = CallType::TYPE_IMS;
569     switch (callInfo.callType) {
570         case ImsCallType::TEL_IMS_CALL_TYPE_VOICE:
571             callReportInfo.callMode = VideoStateType::TYPE_VOICE;
572             break;
573         case ImsCallType::TEL_IMS_CALL_TYPE_VT_TX:
574             callReportInfo.callMode = VideoStateType::TYPE_SEND_ONLY;
575             break;
576         case ImsCallType::TEL_IMS_CALL_TYPE_VT_RX:
577             callReportInfo.callMode = VideoStateType::TYPE_RECEIVE_ONLY;
578             break;
579         case ImsCallType::TEL_IMS_CALL_TYPE_VT:
580             callReportInfo.callMode = VideoStateType::TYPE_VIDEO;
581             break;
582         default:
583             callReportInfo.callMode = VideoStateType::TYPE_VOICE;
584             break;
585     }
586     callReportInfo.mpty = callInfo.mpty;
587     callReportInfo.crsType = callInfo.toneType;
588     callReportInfo.originalCallType = callInfo.callInitialType;
589     callReportInfo.namePresentation = callInfo.namePresentation;
590     callReportInfo.newCallUseBox = callInfo.newCallUseBox;
591     return callReportInfo;
592 }
593 
DeleteConnection(CallsReportInfo & callsReportInfo,const ImsCurrentCallList & callInfoList)594 void IMSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const ImsCurrentCallList &callInfoList)
595 {
596     TELEPHONY_LOGI("DeleteConnection entry");
597     auto it = connectionMap_.begin();
598     while (it != connectionMap_.end()) {
599         if (!it->second.GetFlag()) {
600             CallReportInfo callReportInfo = it->second.GetCallReportInfo();
601             callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
602             callReportInfo.reason = static_cast<DisconnectedReason>(it->second.GetDisconnectReason());
603             callReportInfo.message = it->second.GetDisconnectMessage();
604             callsReportInfo.callVec.push_back(callReportInfo);
605             it = connectionMap_.erase(it);
606         } else {
607             it->second.SetFlag(false);
608             ++it;
609         }
610     }
611 }
612 
ExecutePostDial(int32_t slotId,int64_t callId)613 int32_t IMSControl::ExecutePostDial(int32_t slotId, int64_t callId)
614 {
615     TELEPHONY_LOGI("ExecutePostDial entry");
616     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
617     if (connectionMap_.empty()) {
618         TELEPHONY_LOGE("connectionMap_ is empty.");
619         return TELEPHONY_ERROR;
620     }
621     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callId);
622     if (pConnection == nullptr) {
623         return TELEPHONY_ERR_LOCAL_PTR_NULL;
624     }
625     char currentChar;
626     PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar);
627     switch (state) {
628         case PostDialCallState::POST_DIAL_CALL_STARTED:
629             DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar);
630             break;
631         case PostDialCallState::POST_DIAL_CALL_DELAY:
632             DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay(
633                 pConnection->GetLeftPostDialCallString());
634             break;
635         default:
636             break;
637     }
638     return TELEPHONY_SUCCESS;
639 }
640 
PostDialProceed(const CellularCallInfo & callInfo,const bool proceed)641 int32_t IMSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)
642 {
643     TELEPHONY_LOGI("PostDialProceed entry");
644     std::string networkAddress;
645     std::string postDialString;
646     StandardizeUtils standardizeUtils;
647     standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString);
648     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
649     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_,
650         callInfo.index);
651     if (pConnection == nullptr) {
652         TELEPHONY_LOGE("ims pConnection is nullptr!");
653         return TELEPHONY_ERR_LOCAL_PTR_NULL;
654     }
655     if (proceed) {
656         ExecutePostDial(callInfo.slotId, pConnection->GetIndex());
657     } else {
658         pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED);
659     }
660     return TELEPHONY_SUCCESS;
661 }
662 
RestoreConnection(const std::vector<CellularCallInfo> & infos,int32_t slotId)663 int32_t IMSControl::RestoreConnection(const std::vector<CellularCallInfo> &infos, int32_t slotId)
664 {
665     TELEPHONY_LOGI("RestoreConnection entry");
666     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
667     for (auto &info : infos) {
668         if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) {
669             CellularCallConnectionIMS connectionIMS;
670             connectionIMS.SetIndex(info.index);
671             connectionIMS.SetNumber(info.phoneNum);
672             SetConnectionData(connectionMap_, info.index, connectionIMS);
673         }
674     }
675     return TELEPHONY_SUCCESS;
676 }
677 
ReportHangUp(const std::vector<CellularCallInfo> & infos,int32_t slotId)678 int32_t IMSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)
679 {
680     CallsReportInfo callsReportInfo;
681     callsReportInfo.slotId = slotId;
682     for (const auto &info : infos) {
683         if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) {
684             CallReportInfo imsCallReportInfo;
685             if (memset_s(imsCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) {
686                 TELEPHONY_LOGE("memset_s fail");
687                 return TELEPHONY_ERR_MEMSET_FAIL;
688             }
689             if (memcpy_s(imsCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) {
690                 TELEPHONY_LOGE("memcpy_s fail");
691                 return TELEPHONY_ERR_MEMCPY_FAIL;
692             }
693             imsCallReportInfo.index = info.index;
694             imsCallReportInfo.accountId = info.slotId;
695             imsCallReportInfo.callType = CallType::TYPE_IMS;
696             imsCallReportInfo.callMode =
697                 static_cast<bool>(info.callType) ? VideoStateType::TYPE_VIDEO : VideoStateType::TYPE_VOICE;
698             imsCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
699             callsReportInfo.callVec.push_back(imsCallReportInfo);
700         }
701     }
702     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
703         TELEPHONY_LOGE("CellularCallRegister instance is nullptr");
704         return TELEPHONY_ERR_LOCAL_PTR_NULL;
705     }
706     DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
707     return TELEPHONY_SUCCESS;
708 }
709 
DialAfterHold(int32_t slotId)710 void IMSControl::DialAfterHold(int32_t slotId)
711 {
712     TELEPHONY_LOGI("DialAfterHold entry");
713     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
714     for (auto &connection : connectionMap_) {
715         if (connection.second.IsNeedToDial()) {
716             ImsDialInfoStruct holdToDialInfo = connection.second.GetHoldToDialInfo();
717             CellularCallConnectionIMS cellularCallConnectionIms;
718             cellularCallConnectionIms.DialRequest(slotId, holdToDialInfo);
719             connection.second.SetDialFlag(false);
720             break;
721         }
722     }
723 }
724 
RecoverPendingHold()725 void IMSControl::RecoverPendingHold()
726 {
727     TELEPHONY_LOGI("RecoverPendingHold entry");
728     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
729     for (auto &connection : connectionMap_) {
730         if (connection.second.IsPendingHold()) {
731             connection.second.UpdatePendingHoldFlag(false);
732             break;
733         }
734     }
735 }
736 
UpdateDisconnectedReason(const ImsCurrentCallList & currentCallList,RilDisconnectedReason reason,const std::string & message)737 void IMSControl::UpdateDisconnectedReason(const ImsCurrentCallList &currentCallList, RilDisconnectedReason reason,
738     const std::string &message)
739 {
740     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
741     for (auto &connection : connectionMap_) {
742         bool isFind = false;
743         if (connection.second.GetDisconnectReason() != RilDisconnectedReason::DISCONNECTED_REASON_INVALID) {
744             continue;
745         }
746         for (auto &call : currentCallList.calls) {
747             if (connection.second.GetIndex() == call.index) {
748                 isFind = true;
749                 break;
750             }
751         }
752         if (!isFind) {
753             connection.second.SetDisconnectReason(reason);
754             connection.second.SetDisconnectMessage(message);
755         }
756     }
757 }
758 
HasEndCallWithoutReason(const ImsCurrentCallList & currentCallList)759 bool IMSControl::HasEndCallWithoutReason(const ImsCurrentCallList &currentCallList)
760 {
761     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
762     for (auto &connection : connectionMap_) {
763         bool isFind = false;
764         if (connection.second.GetDisconnectReason() != RilDisconnectedReason::DISCONNECTED_REASON_INVALID) {
765             continue; // This call already has a disconnect reason.
766         }
767         for (auto &call : currentCallList.calls) {
768             if (connection.second.GetIndex() == call.index) {
769                 isFind = true;
770                 break;
771             }
772         }
773         if (!isFind) {
774             return true; // There are still calls need query disconnect reason.
775         }
776     }
777     return false; // All calls have disconnected reason, no need to query disconnect reason.
778 }
779 
UpdateCallDisconnectReason(int32_t callId,RilDisconnectedReason reason,const std::string & message)780 void IMSControl::UpdateCallDisconnectReason(int32_t callId, RilDisconnectedReason reason, const std::string &message)
781 {
782     std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
783     for (auto &connection : connectionMap_) {
784         if (connection.second.GetIndex() == callId) {
785             connection.second.SetDisconnectReason(reason);
786             connection.second.SetDisconnectMessage(message);
787             return; // call id not duplicated.
788         }
789     }
790 }
791 
792 #ifdef BASE_POWER_IMPROVEMENT_FEATURE
GetPendingEmcCallInfo()793 CellularCallInfo IMSControl::GetPendingEmcCallInfo()
794 {
795     return pendingEmcDialCallInfo_;
796 }
797 
isPendingEmcFlag()798 bool IMSControl::isPendingEmcFlag()
799 {
800     return isPendingEmc_;
801 }
802 
setPendingEmcFlag(bool flag)803 void IMSControl::setPendingEmcFlag(bool flag)
804 {
805     isPendingEmc_ = flag;
806 }
807 #endif
808 } // namespace Telephony
809 } // namespace OHOS
810