• 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<std::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     switch (type) {
158         case CallSupplementType::TYPE_DEFAULT: {
159             std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
160             auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
161                 connectionMap_, callInfo.index);
162             if (pConnection == nullptr) {
163                 TELEPHONY_LOGE("HangUp return, error type: connection is null");
164                 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
165             }
166             pConnection->SetHangupFlag(true);
167             if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
168                 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
169                     pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
170             }
171             pConnection->SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
172             return pConnection->HangUpRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
173         }
174         case CallSupplementType::TYPE_HANG_UP_HOLD_WAIT:
175             // release the second (active) call and recover the first (held) call
176         case CallSupplementType::TYPE_HANG_UP_ACTIVE: {
177             CellularCallConnectionIMS connection;
178             UpdateCallDisconnectReason(callInfo.callId, RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
179             return connection.CallSupplementRequest(callInfo.slotId, type);
180         }
181         case CallSupplementType::TYPE_HANG_UP_ALL: {
182             TELEPHONY_LOGI("HangUp, hang up all call");
183             CellularCallConnectionIMS connection;
184             // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
185             // so the reject interface is reused.
186             {
187                 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
188                 for (auto &connection : connectionMap_) {
189                     connection.second.SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
190                 }
191             }
192             return connection.RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
193         }
194         default: {
195             TELEPHONY_LOGE("HangUp warring, type is invalid");
196             return TELEPHONY_ERR_ARGUMENT_INVALID;
197         }
198     }
199 }
200 
Answer(const CellularCallInfo & callInfo)201 int32_t IMSControl::Answer(const CellularCallInfo &callInfo)
202 {
203     TELEPHONY_LOGI("IMSControl::Answer start");
204     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
205     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
206         connectionMap_, callInfo.index);
207     if (pConnection == nullptr) {
208         TELEPHONY_LOGE("HangUp return, error type: connection is null");
209         return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
210     }
211     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) &&
212         IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
213         TELEPHONY_LOGD("already threeway mode. hangup holding call and pickup new call");
214         int32_t ret = CheckAndHangupHoldingCall();
215         if (ret != TELEPHONY_SUCCESS) {
216             TELEPHONY_LOGE("hangup holding call failed");
217             return ret;
218         }
219     }
220     auto con = FindConnectionByState<ImsConnectionMap &, CellularCallConnectionIMS *>(
221         connectionMap_, TelCallState::CALL_STATUS_ACTIVE);
222     if (con != nullptr && !con->IsPendingHold() &&
223         pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
224         TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting");
225         return con->SwitchCallRequest(callInfo.slotId, callInfo.videoState);
226     }
227     if (pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING ||
228         pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING ||
229         pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
230         return pConnection->AnswerRequest(callInfo.slotId, callInfo.phoneNum, callInfo.videoState, callInfo.index);
231     }
232     TELEPHONY_LOGE("IMSControl::Answer return, error type: call state error, phone not ringing.");
233     return CALL_ERR_CALL_STATE;
234 }
235 
CheckAndHangupHoldingCall()236 int32_t IMSControl::CheckAndHangupHoldingCall()
237 {
238     for (auto &it : connectionMap_) {
239         CellularCallConnectionIMS holdConn = it.second;
240         if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) {
241             auto callReportInfo = holdConn.GetCallReportInfo();
242             int32_t result = holdConn.HangUpRequest(callReportInfo.accountId,
243                 callReportInfo.accountNum, callReportInfo.index);
244             if (result != TELEPHONY_SUCCESS) {
245                 return result;
246             }
247         }
248     }
249     return TELEPHONY_SUCCESS;
250 }
251 
Reject(const CellularCallInfo & callInfo)252 int32_t IMSControl::Reject(const CellularCallInfo &callInfo)
253 {
254     TELEPHONY_LOGI("IMSControl::Reject start");
255     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
256     auto pConnection =
257         FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callInfo.index);
258     if (pConnection == nullptr) {
259         TELEPHONY_LOGE("IMSControl::Reject, error type: connection is null");
260         return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
261     }
262     if (!pConnection->IsRingingState()) {
263         TELEPHONY_LOGE("IMSControl::Reject return, error type: call state error, phone not ringing.");
264         return CALL_ERR_CALL_STATE;
265     }
266     if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
267         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
268             pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
269     }
270     pConnection->SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_DECLINE);
271     return pConnection->RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
272 }
273 
HoldCall(int32_t slotId)274 int32_t IMSControl::HoldCall(int32_t slotId)
275 {
276     TELEPHONY_LOGI("HoldCall start");
277     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
278     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
279         TELEPHONY_LOGE("HoldCall return, error type: call state error.");
280         return CALL_ERR_CALL_STATE;
281     }
282     CellularCallConnectionIMS cellularCallConnectionIms;
283     return cellularCallConnectionIms.HoldCallRequest(slotId);
284 }
285 
UnHoldCall(int32_t slotId)286 int32_t IMSControl::UnHoldCall(int32_t slotId)
287 {
288     TELEPHONY_LOGI("UnHoldCall start");
289     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
290     for (auto &it : connectionMap_) {
291         CallReportInfo reportInfo = it.second.GetCallReportInfo();
292         if (slotId == reportInfo.accountId && reportInfo.state == TelCallState::CALL_STATUS_HOLDING) {
293             return it.second.UnHoldCallRequest(slotId);
294         }
295     }
296     TELEPHONY_LOGE("UnHoldCall return, not exist hold call.");
297     return TELEPHONY_ERROR;
298 }
299 
SwitchCall(int32_t slotId)300 int32_t IMSControl::SwitchCall(int32_t slotId)
301 {
302     TELEPHONY_LOGI("SwitchCall start");
303     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
304     VideoStateType callMode = VideoStateType::TYPE_VOICE;
305     for (auto &it : connectionMap_) {
306         CallReportInfo reportInfo = it.second.GetCallReportInfo();
307         if (slotId == reportInfo.accountId) {
308             callMode = reportInfo.callMode;
309             break;
310         }
311     }
312     CellularCallConnectionIMS cellularCallConnectionIms;
313     return cellularCallConnectionIms.SwitchCallRequest(slotId, static_cast<int32_t>(callMode));
314 }
315 
316 /**
317  * Add another remote party, to which a private communication has been established using
318  * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then
319  * exceed the maximum number allowed, which results in an active multiParty call.
320  */
CombineConference(int32_t slotId)321 int32_t IMSControl::CombineConference(int32_t slotId)
322 {
323     TELEPHONY_LOGI("CombineConference entry");
324     CellularCallConnectionIMS connection;
325     int32_t voiceCall = 0;
326     return connection.CombineConferenceRequest(slotId, voiceCall);
327 }
328 
HangUpAllConnection(int32_t slotId)329 int32_t IMSControl::HangUpAllConnection(int32_t slotId)
330 {
331     TELEPHONY_LOGI("HangUpAllConnection entry");
332     CellularCallConnectionIMS connection;
333     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
334     if (connectionMap_.empty()) {
335         TELEPHONY_LOGI("connectionMap_ is empty.");
336         return TELEPHONY_ERROR;
337     }
338     for (auto &it : connectionMap_) {
339         int32_t index = it.second.GetIndex();
340         std::string number = it.second.GetNumber();
341         connection.RejectRequest(slotId, number, index);
342     }
343     // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
344     // so the reject interface is reused.
345     return TELEPHONY_SUCCESS;
346 }
347 
InviteToConference(int32_t slotId,const std::vector<std::string> & numberList)348 int32_t IMSControl::InviteToConference(int32_t slotId, const std::vector<std::string> &numberList)
349 {
350     TELEPHONY_LOGI("InviteToConference entry");
351     CellularCallConnectionIMS connection;
352     return connection.InviteToConferenceRequest(slotId, numberList);
353 }
354 
KickOutFromConference(int32_t slotId,const std::string & KickOutString,int32_t index)355 int32_t IMSControl::KickOutFromConference(int32_t slotId, const std::string &KickOutString, int32_t index)
356 {
357     TELEPHONY_LOGI("KickOutFromConference entry");
358     if (KickOutString.empty()) {
359         TELEPHONY_LOGW("KickOutFromConference, splitString is empty.");
360     }
361 
362     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
363     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, index);
364     if (pConnection != nullptr) {
365         return pConnection->KickOutFromConferenceRequest(slotId, pConnection->GetIndex());
366     }
367 
368     TELEPHONY_LOGI("KickOutFromConference: connection cannot be matched, use index directly");
369     CellularCallConnectionIMS connection;
370     return connection.KickOutFromConferenceRequest(slotId, index);
371 }
372 
StartRtt(int32_t slotId,const std::string & msg)373 int32_t IMSControl::StartRtt(int32_t slotId, const std::string &msg)
374 {
375     TELEPHONY_LOGI("StartRtt entry");
376     CellularCallConnectionIMS connection;
377     return connection.StartRttRequest(slotId, msg);
378 }
379 
StopRtt(int32_t slotId)380 int32_t IMSControl::StopRtt(int32_t slotId)
381 {
382     TELEPHONY_LOGI("StopRtt entry");
383     CellularCallConnectionIMS connection;
384     return connection.StopRttRequest(slotId);
385 }
386 
ReleaseAllConnection()387 void IMSControl::ReleaseAllConnection()
388 {
389     TELEPHONY_LOGI("ReleaseAllConnection entry");
390     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
391     connectionMap_.clear();
392 }
393 
GetConnectionMap()394 ImsConnectionMap IMSControl::GetConnectionMap()
395 {
396     TELEPHONY_LOGI("GetConnectionMap entry");
397     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
398     return connectionMap_;
399 }
400 
ReportImsCallsData(int32_t slotId,const ImsCurrentCallList & callInfoList,bool isNeedQuery)401 int32_t IMSControl::ReportImsCallsData(int32_t slotId, const ImsCurrentCallList &callInfoList, bool isNeedQuery)
402 {
403     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
404     if (callInfoList.callSize <= 0) {
405         if (isNeedQuery) {
406             GetCallFailReason(slotId, connectionMap_);
407             return TELEPHONY_SUCCESS;
408         }
409         return ReportHangUpInfo(slotId);
410     } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
411         return ReportIncomingInfo(slotId, callInfoList);
412     } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
413         if (isNeedQuery) {
414             GetCallFailReason(slotId, connectionMap_);
415             return TELEPHONY_SUCCESS;
416         }
417         return ReportUpdateInfo(slotId, callInfoList);
418     }
419     return TELEPHONY_ERROR;
420 }
421 
ReportCallsData(int32_t slotId,const CallInfoList & callInfoList)422 int32_t IMSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
423 {
424     return TELEPHONY_ERROR;
425 }
426 
ReportHangUpInfo(int32_t slotId)427 int32_t IMSControl::ReportHangUpInfo(int32_t slotId)
428 {
429     TELEPHONY_LOGI("ReportHangUpInfo entry");
430     CallsReportInfo callsReportInfo;
431     for (auto &it : connectionMap_) {
432         CallReportInfo reportInfo = it.second.GetCallReportInfo();
433         reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
434         reportInfo.accountId = slotId;
435         reportInfo.reason = static_cast<DisconnectedReason>(it.second.GetDisconnectReason());
436         callsReportInfo.callVec.push_back(reportInfo);
437     }
438     if (connectionMap_.empty()) {
439         TELEPHONY_LOGI("connectionMap_ is empty");
440         CallReportInfo reportInfo;
441         reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
442         reportInfo.accountId = slotId;
443         callsReportInfo.callVec.push_back(reportInfo);
444     }
445     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
446         TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr.");
447         return TELEPHONY_ERR_LOCAL_PTR_NULL;
448     }
449     callsReportInfo.slotId = slotId;
450     if (isIgnoredIncomingCall_) {
451         isIgnoredIncomingCall_ = false;
452     } else {
453         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
454     }
455     ReleaseAllConnection();
456     return TELEPHONY_SUCCESS;
457 }
458 
ReportIncomingInfo(int32_t slotId,const ImsCurrentCallList & imsCurrentCallInfoList)459 int32_t IMSControl::ReportIncomingInfo(int32_t slotId, const ImsCurrentCallList &imsCurrentCallInfoList)
460 {
461     TELEPHONY_LOGI("ReportIncomingInfo entry");
462     CallsReportInfo callsReportInfo;
463     for (int32_t i = 0; i < imsCurrentCallInfoList.callSize; ++i) {
464         CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, imsCurrentCallInfoList.calls[i]);
465 
466         CellularCallConnectionIMS connection;
467         connection.SetStatus(static_cast<TelCallState>(imsCurrentCallInfoList.calls[i].state));
468         connection.SetIndex(imsCurrentCallInfoList.calls[i].index);
469         connection.SetNumber(imsCurrentCallInfoList.calls[i].number);
470         connection.SetOrUpdateCallReportInfo(reportInfo);
471         SetConnectionData(connectionMap_, imsCurrentCallInfoList.calls[i].index, connection);
472 
473         callsReportInfo.callVec.push_back(reportInfo);
474     }
475     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
476         TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr.");
477         return TELEPHONY_ERR_ARGUMENT_INVALID;
478     }
479     callsReportInfo.slotId = slotId;
480     if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() &&
481         callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) {
482         isIgnoredIncomingCall_ = true;
483     } else {
484         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
485     }
486     return TELEPHONY_SUCCESS;
487 }
488 
ReportUpdateInfo(int32_t slotId,const ImsCurrentCallList & callInfoList)489 int32_t IMSControl::ReportUpdateInfo(int32_t slotId, const ImsCurrentCallList &callInfoList)
490 {
491     TELEPHONY_LOGD("ReportUpdateInfo entry");
492     CallsReportInfo callsReportInfo;
493     for (int32_t i = 0; i < callInfoList.callSize; ++i) {
494         CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
495         if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) {
496             TELEPHONY_LOGI("only one call, report incoming state instead of waiting state");
497             reportInfo.state = TelCallState::CALL_STATUS_INCOMING;
498         }
499         auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
500             connectionMap_, callInfoList.calls[i].index);
501         if (pConnection == nullptr) {
502             CellularCallConnectionIMS connection;
503             connection.SetOrUpdateCallReportInfo(reportInfo);
504             connection.SetFlag(true);
505             connection.SetIndex(callInfoList.calls[i].index);
506             connection.SetNumber(callInfoList.calls[i].number);
507             SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
508         } else {
509             TelCallState preCallState = pConnection->GetStatus();
510             pConnection->SetFlag(true);
511             pConnection->SetIndex(callInfoList.calls[i].index);
512             pConnection->SetNumber(callInfoList.calls[i].number);
513             pConnection->SetOrUpdateCallReportInfo(reportInfo);
514             TelCallState curCallState = pConnection->GetStatus();
515             if (IsConnectedOut(preCallState, curCallState)) {
516                 pConnection->UpdateCallNumber(pendingPhoneNumber_);
517                 pendingPhoneNumber_.clear();
518                 ExecutePostDial(slotId, pConnection->GetIndex());
519             }
520         }
521         callsReportInfo.callVec.push_back(reportInfo);
522     }
523     callsReportInfo.slotId = slotId;
524     DeleteConnection(callsReportInfo, callInfoList);
525     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
526         TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr.");
527         return TELEPHONY_ERR_LOCAL_PTR_NULL;
528     }
529     if (isIgnoredIncomingCall_) {
530         isIgnoredIncomingCall_ = false;
531     } else {
532         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
533     }
534     return TELEPHONY_SUCCESS;
535 }
536 
EncapsulationCallReportInfo(int32_t slotId,const ImsCurrentCall & callInfo)537 CallReportInfo IMSControl::EncapsulationCallReportInfo(int32_t slotId, const ImsCurrentCall &callInfo)
538 {
539     TELEPHONY_LOGD("EncapsulationCallReportInfo entry");
540     CallReportInfo callReportInfo;
541     if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) {
542         TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail.");
543         return callReportInfo;
544     }
545 
546     StandardizeUtils standardizeUtils;
547     std::string phoneNumber = callInfo.number;
548     callReportInfo.name = callInfo.number.empty() ? "" : callInfo.name;
549     std::string newString = standardizeUtils.FormatNumberAndToa(phoneNumber, callInfo.toa);
550     size_t cpyLen = strlen(newString.c_str()) + 1;
551     if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) {
552         TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
553         return callReportInfo;
554     }
555     if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) {
556         TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
557         return callReportInfo;
558     }
559     callReportInfo.index = callInfo.index;
560     callReportInfo.accountId = slotId;
561     callReportInfo.state = static_cast<TelCallState>(callInfo.state);
562     callReportInfo.voiceDomain = callInfo.voiceDomain;
563     callReportInfo.callType = CallType::TYPE_IMS;
564     switch (callInfo.callType) {
565         case ImsCallType::TEL_IMS_CALL_TYPE_VOICE:
566             callReportInfo.callMode = VideoStateType::TYPE_VOICE;
567             break;
568         case ImsCallType::TEL_IMS_CALL_TYPE_VT_TX:
569             callReportInfo.callMode = VideoStateType::TYPE_SEND_ONLY;
570             break;
571         case ImsCallType::TEL_IMS_CALL_TYPE_VT_RX:
572             callReportInfo.callMode = VideoStateType::TYPE_RECEIVE_ONLY;
573             break;
574         case ImsCallType::TEL_IMS_CALL_TYPE_VT:
575             callReportInfo.callMode = VideoStateType::TYPE_VIDEO;
576             break;
577         default:
578             callReportInfo.callMode = VideoStateType::TYPE_VOICE;
579             break;
580     }
581     callReportInfo.mpty = callInfo.mpty;
582     callReportInfo.crsType = callInfo.toneType;
583     callReportInfo.originalCallType = callInfo.callInitialType;
584     callReportInfo.namePresentation = callInfo.namePresentation;
585     return callReportInfo;
586 }
587 
DeleteConnection(CallsReportInfo & callsReportInfo,const ImsCurrentCallList & callInfoList)588 void IMSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const ImsCurrentCallList &callInfoList)
589 {
590     TELEPHONY_LOGI("DeleteConnection entry");
591     auto it = connectionMap_.begin();
592     while (it != connectionMap_.end()) {
593         if (!it->second.GetFlag()) {
594             CallReportInfo callReportInfo = it->second.GetCallReportInfo();
595             callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
596             callReportInfo.reason = static_cast<DisconnectedReason>(it->second.GetDisconnectReason());
597             callsReportInfo.callVec.push_back(callReportInfo);
598             it = connectionMap_.erase(it);
599         } else {
600             it->second.SetFlag(false);
601             ++it;
602         }
603     }
604 }
605 
ExecutePostDial(int32_t slotId,int64_t callId)606 int32_t IMSControl::ExecutePostDial(int32_t slotId, int64_t callId)
607 {
608     TELEPHONY_LOGI("ExecutePostDial entry");
609     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
610     if (connectionMap_.empty()) {
611         TELEPHONY_LOGE("connectionMap_ is empty.");
612         return TELEPHONY_ERROR;
613     }
614     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callId);
615     if (pConnection == nullptr) {
616         return TELEPHONY_ERR_LOCAL_PTR_NULL;
617     }
618     char currentChar;
619     PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar);
620     switch (state) {
621         case PostDialCallState::POST_DIAL_CALL_STARTED:
622             DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar);
623             break;
624         case PostDialCallState::POST_DIAL_CALL_DELAY:
625             DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay(
626                 pConnection->GetLeftPostDialCallString());
627             break;
628         default:
629             break;
630     }
631     return TELEPHONY_SUCCESS;
632 }
633 
PostDialProceed(const CellularCallInfo & callInfo,const bool proceed)634 int32_t IMSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)
635 {
636     TELEPHONY_LOGI("PostDialProceed entry");
637     std::string networkAddress;
638     std::string postDialString;
639     StandardizeUtils standardizeUtils;
640     standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString);
641     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
642     auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_,
643         callInfo.index);
644     if (pConnection == nullptr) {
645         TELEPHONY_LOGE("ims pConnection is nullptr!");
646         return TELEPHONY_ERR_LOCAL_PTR_NULL;
647     }
648     if (proceed) {
649         ExecutePostDial(callInfo.slotId, pConnection->GetIndex());
650     } else {
651         pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED);
652     }
653     return TELEPHONY_SUCCESS;
654 }
655 
RestoreConnection(const std::vector<CellularCallInfo> & infos,int32_t slotId)656 int32_t IMSControl::RestoreConnection(const std::vector<CellularCallInfo> &infos, int32_t slotId)
657 {
658     TELEPHONY_LOGI("RestoreConnection entry");
659     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
660     for (auto &info : infos) {
661         if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) {
662             CellularCallConnectionIMS connectionIMS;
663             connectionIMS.SetIndex(info.index);
664             connectionIMS.SetNumber(info.phoneNum);
665             SetConnectionData(connectionMap_, info.index, connectionIMS);
666         }
667     }
668     return TELEPHONY_SUCCESS;
669 }
670 
ReportHangUp(const std::vector<CellularCallInfo> & infos,int32_t slotId)671 int32_t IMSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)
672 {
673     CallsReportInfo callsReportInfo;
674     callsReportInfo.slotId = slotId;
675     for (const auto &info : infos) {
676         if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) {
677             CallReportInfo imsCallReportInfo;
678             if (memset_s(imsCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) {
679                 TELEPHONY_LOGE("memset_s fail");
680                 return TELEPHONY_ERR_MEMSET_FAIL;
681             }
682             if (memcpy_s(imsCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) {
683                 TELEPHONY_LOGE("memcpy_s fail");
684                 return TELEPHONY_ERR_MEMCPY_FAIL;
685             }
686             imsCallReportInfo.index = info.index;
687             imsCallReportInfo.accountId = info.slotId;
688             imsCallReportInfo.callType = CallType::TYPE_IMS;
689             imsCallReportInfo.callMode =
690                 static_cast<bool>(info.callType) ? VideoStateType::TYPE_VIDEO : VideoStateType::TYPE_VOICE;
691             imsCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
692             callsReportInfo.callVec.push_back(imsCallReportInfo);
693         }
694     }
695     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
696         TELEPHONY_LOGE("CellularCallRegister instance is nullptr");
697         return TELEPHONY_ERR_LOCAL_PTR_NULL;
698     }
699     DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
700     return TELEPHONY_SUCCESS;
701 }
702 
DialAfterHold(int32_t slotId)703 void IMSControl::DialAfterHold(int32_t slotId)
704 {
705     TELEPHONY_LOGI("DialAfterHold entry");
706     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
707     for (auto &connection : connectionMap_) {
708         if (connection.second.IsNeedToDial()) {
709             ImsDialInfoStruct holdToDialInfo = connection.second.GetHoldToDialInfo();
710             CellularCallConnectionIMS cellularCallConnectionIms;
711             cellularCallConnectionIms.DialRequest(slotId, holdToDialInfo);
712             connection.second.SetDialFlag(false);
713             break;
714         }
715     }
716 }
717 
RecoverPendingHold()718 void IMSControl::RecoverPendingHold()
719 {
720     TELEPHONY_LOGI("RecoverPendingHold entry");
721     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
722     for (auto &connection : connectionMap_) {
723         if (connection.second.IsPendingHold()) {
724             connection.second.UpdatePendingHoldFlag(false);
725             break;
726         }
727     }
728 }
729 
UpdateDisconnectedReason(const ImsCurrentCallList & currentCallList,RilDisconnectedReason reason)730 void IMSControl::UpdateDisconnectedReason(const ImsCurrentCallList &currentCallList, RilDisconnectedReason reason)
731 {
732     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
733     for (auto &connection : connectionMap_) {
734         bool isFind = false;
735         if (connection.second.GetDisconnectReason() != RilDisconnectedReason::DISCONNECTED_REASON_INVALID) {
736             continue;
737         }
738         for (auto &call : currentCallList.calls) {
739             if (connection.second.GetIndex() == call.index) {
740                 isFind = true;
741                 break;
742             }
743         }
744         if (!isFind) {
745             connection.second.SetDisconnectReason(reason);
746         }
747     }
748 }
749 
HasEndCallWithoutReason(const ImsCurrentCallList & currentCallList)750 bool IMSControl::HasEndCallWithoutReason(const ImsCurrentCallList &currentCallList)
751 {
752     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
753     for (auto &connection : connectionMap_) {
754         bool isFind = false;
755         if (connection.second.GetDisconnectReason() != RilDisconnectedReason::DISCONNECTED_REASON_INVALID) {
756             continue; // This call already has a disconnect reason.
757         }
758         for (auto &call : currentCallList.calls) {
759             if (connection.second.GetIndex() == call.index) {
760                 isFind = true;
761                 break;
762             }
763         }
764         if (!isFind) {
765             return true; // There are still calls need query disconnect reason.
766         }
767     }
768     return false; // All calls have disconnected reason, no need to query disconnect reason.
769 }
770 
UpdateCallDisconnectReason(int32_t callId,RilDisconnectedReason reason)771 void IMSControl::UpdateCallDisconnectReason(int32_t callId, RilDisconnectedReason reason)
772 {
773     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
774     for (auto &connection : connectionMap_) {
775         if (connection.second.GetIndex() == callId) {
776             connection.second.SetDisconnectReason(reason);
777             return; // call id not duplicated.
778         }
779     }
780 }
781 
782 #ifdef BASE_POWER_IMPROVEMENT_FEATURE
GetPendingEmcCallInfo()783 CellularCallInfo IMSControl::GetPendingEmcCallInfo()
784 {
785     return pendingEmcDialCallInfo_;
786 }
787 
isPendingEmcFlag()788 bool IMSControl::isPendingEmcFlag()
789 {
790     return isPendingEmc_;
791 }
792 
setPendingEmcFlag(bool flag)793 void IMSControl::setPendingEmcFlag(bool flag)
794 {
795     isPendingEmc_ = flag;
796 }
797 #endif
798 } // namespace Telephony
799 } // namespace OHOS
800