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 if (ret != TELEPHONY_SUCCESS) {
40 return ret;
41 }
42 ModuleServiceUtils moduleServiceUtils;
43 RegServiceState regState = moduleServiceUtils.GetPsRegState(callInfo.slotId);
44 if (!(regState == RegServiceState::REG_STATE_IN_SERVICE || isEcc)) {
45 TELEPHONY_LOGE("can not dial.");
46 return TELEPHONY_ERR_NETWORK_NOT_IN_SERVICE;
47 }
48 // sip uri needs to remove separator
49 std::string newPhoneNum(callInfo.phoneNum);
50 StandardizeUtils standardizeUtils;
51 if (newPhoneNum.find('@') != std::string::npos || newPhoneNum.find("%40") != std::string::npos) {
52 newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(newPhoneNum);
53 }
54
55 CLIRMode clirMode = CLIRMode::DEFAULT;
56 if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, true)) {
57 TELEPHONY_LOGI("Dial return, mmi code type.");
58 return RETURN_TYPE_MMI;
59 }
60 return DialJudgment(callInfo.slotId, newPhoneNum, clirMode, callInfo.videoState);
61 }
62
DialJudgment(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState)63 int32_t IMSControl::DialJudgment(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState)
64 {
65 TELEPHONY_LOGI("DialJudgment entry.");
66 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
67 if (!CanCall(connectionMap_)) {
68 TELEPHONY_LOGE("DialJudgment return, error type: call state error.");
69 CellularCallHiSysEvent::WriteDialCallFaultEvent(
70 slotId, INVALID_PARAMETER, videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "ims dial call state error");
71 return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT;
72 }
73 pendingPhoneNumber_ = phoneNum;
74 // Calls can be put on hold, recovered, released, added to conversation,
75 // and transferred similarly as defined in 3GPP TS 22.030 [19].
76 for (auto &connection : connectionMap_) {
77 if (connection.second.GetStatus() == TelCallState::CALL_STATUS_ACTIVE &&
78 !connection.second.IsPendingHangup()) {
79 TELEPHONY_LOGI("DialJudgment, have connection in active state.");
80 EmergencyUtils emergencyUtils;
81 bool isEmergency = false;
82 emergencyUtils.IsEmergencyCall(slotId, phoneNum, isEmergency);
83 connection.second.SetHoldToDialInfo(phoneNum, clirMode, videoState, isEmergency);
84 connection.second.SetDialFlag(true);
85 // - a call can be temporarily disconnected from the ME but the connection is retained by the network
86 return connection.second.SwitchCallRequest(slotId);
87 }
88 }
89 return EncapsulateDial(slotId, phoneNum, clirMode, videoState);
90 }
91
EncapsulateDial( int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState) const92 int32_t IMSControl::EncapsulateDial(
93 int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState) const
94 {
95 TELEPHONY_LOGI("EncapsulateDial start");
96
97 ImsDialInfoStruct dialInfo;
98 dialInfo.videoState = videoState;
99 dialInfo.bEmergencyCall = false;
100 EmergencyUtils emergencyUtils;
101 emergencyUtils.IsEmergencyCall(slotId, phoneNum, dialInfo.bEmergencyCall);
102
103 /**
104 * <idx>: integer type;
105 * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1
106 * this number can be used in +CHLD command operations
107 * <dir>:
108 */
109 dialInfo.phoneNum = phoneNum;
110 /**
111 * <n> (parameter sets the adjustment for outgoing calls):
112 * 0 presentation indicator is used according to the subscription of the CLIR service
113 * 1 CLIR invocation
114 * 2 CLIR suppression
115 */
116 dialInfo.clirMode = clirMode;
117 /**
118 * An example of voice group call service request usage:
119 * ATD*17*753#500; (originate voice group call with the priority level 3)
120 * OK (voice group call setup was successful)
121 */
122
123 CellularCallConnectionIMS cellularCallConnectionIms;
124 return cellularCallConnectionIms.DialRequest(slotId, dialInfo);
125 }
126
HangUp(const CellularCallInfo &callInfo, CallSupplementType type)127 int32_t IMSControl::HangUp(const CellularCallInfo &callInfo, CallSupplementType type)
128 {
129 TELEPHONY_LOGI("HangUp start");
130 switch (type) {
131 case CallSupplementType::TYPE_DEFAULT: {
132 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
133 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
134 connectionMap_, callInfo.index);
135 if (pConnection == nullptr) {
136 TELEPHONY_LOGE("HangUp return, error type: connection is null");
137 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
138 }
139 pConnection->SetHangupFlag(true);
140 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
141 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
142 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
143 }
144 return pConnection->HangUpRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
145 }
146 case CallSupplementType::TYPE_HANG_UP_HOLD_WAIT:
147 // release the second (active) call and recover the first (held) call
148 case CallSupplementType::TYPE_HANG_UP_ACTIVE: {
149 CellularCallConnectionIMS connection;
150 return connection.CallSupplementRequest(callInfo.slotId, type);
151 }
152 case CallSupplementType::TYPE_HANG_UP_ALL: {
153 TELEPHONY_LOGI("HangUp, hang up all call");
154 CellularCallConnectionIMS connection;
155 // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
156 // so the reject interface is reused.
157 return connection.RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
158 }
159 default: {
160 TELEPHONY_LOGE("HangUp warring, type is invalid");
161 return TELEPHONY_ERR_ARGUMENT_INVALID;
162 }
163 }
164 }
165
Answer(const CellularCallInfo &callInfo)166 int32_t IMSControl::Answer(const CellularCallInfo &callInfo)
167 {
168 TELEPHONY_LOGI("IMSControl::Answer start");
169 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
170 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
171 connectionMap_, callInfo.index);
172 if (pConnection == nullptr) {
173 TELEPHONY_LOGE("HangUp return, error type: connection is null");
174 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
175 }
176 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) &&
177 IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
178 TELEPHONY_LOGD("already threeway mode. hangup holding call and pickup new call");
179 int32_t ret = CheckAndHangupHoldingCall();
180 if (ret != TELEPHONY_SUCCESS) {
181 TELEPHONY_LOGE("hangup holding call failed");
182 return ret;
183 }
184 }
185 auto con = FindConnectionByState<ImsConnectionMap &, CellularCallConnectionIMS *>(
186 connectionMap_, TelCallState::CALL_STATUS_ACTIVE);
187 if (con != nullptr && !con->IsPendingHold() &&
188 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
189 TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting");
190 return con->SwitchCallRequest(callInfo.slotId);
191 }
192 if (pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING ||
193 pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING ||
194 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
195 return pConnection->AnswerRequest(callInfo.slotId, callInfo.phoneNum, callInfo.videoState, callInfo.index);
196 }
197 TELEPHONY_LOGE("IMSControl::Answer return, error type: call state error, phone not ringing.");
198 return CALL_ERR_CALL_STATE;
199 }
200
CheckAndHangupHoldingCall()201 int32_t IMSControl::CheckAndHangupHoldingCall()
202 {
203 for (auto &it : connectionMap_) {
204 CellularCallConnectionIMS holdConn = it.second;
205 if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) {
206 auto callReportInfo = holdConn.GetCallReportInfo();
207 int32_t result = holdConn.HangUpRequest(callReportInfo.accountId,
208 callReportInfo.accountNum, callReportInfo.index);
209 if (result != TELEPHONY_SUCCESS) {
210 return result;
211 }
212 }
213 }
214 return TELEPHONY_SUCCESS;
215 }
216
Reject(const CellularCallInfo &callInfo)217 int32_t IMSControl::Reject(const CellularCallInfo &callInfo)
218 {
219 TELEPHONY_LOGI("IMSControl::Reject start");
220 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
221 auto pConnection =
222 FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callInfo.index);
223 if (pConnection == nullptr) {
224 TELEPHONY_LOGE("IMSControl::Reject, error type: connection is null");
225 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
226 }
227 if (!pConnection->IsRingingState()) {
228 TELEPHONY_LOGE("IMSControl::Reject return, error type: call state error, phone not ringing.");
229 return CALL_ERR_CALL_STATE;
230 }
231 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
232 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
233 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
234 }
235 return pConnection->RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index);
236 }
237
HoldCall(int32_t slotId)238 int32_t IMSControl::HoldCall(int32_t slotId)
239 {
240 TELEPHONY_LOGI("HoldCall start");
241 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
242 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
243 TELEPHONY_LOGE("HoldCall return, error type: call state error.");
244 return CALL_ERR_CALL_STATE;
245 }
246 CellularCallConnectionIMS cellularCallConnectionIms;
247 return cellularCallConnectionIms.HoldCallRequest(slotId);
248 }
249
UnHoldCall(int32_t slotId)250 int32_t IMSControl::UnHoldCall(int32_t slotId)
251 {
252 TELEPHONY_LOGI("UnHoldCall start");
253 CellularCallConnectionIMS cellularCallConnectionIms;
254 return cellularCallConnectionIms.UnHoldCallRequest(slotId);
255 }
256
SwitchCall(int32_t slotId)257 int32_t IMSControl::SwitchCall(int32_t slotId)
258 {
259 TELEPHONY_LOGI("SwitchCall start");
260 CellularCallConnectionIMS cellularCallConnectionIms;
261 return cellularCallConnectionIms.SwitchCallRequest(slotId);
262 }
263
264 /**
265 * Add another remote party, to which a private communication has been established using
266 * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then
267 * exceed the maximum number allowed, which results in an active multiParty call.
268 */
CombineConference(int32_t slotId)269 int32_t IMSControl::CombineConference(int32_t slotId)
270 {
271 TELEPHONY_LOGI("CombineConference entry");
272 CellularCallConnectionIMS connection;
273 int32_t voiceCall = 0;
274 return connection.CombineConferenceRequest(slotId, voiceCall);
275 }
276
HangUpAllConnection(int32_t slotId)277 int32_t IMSControl::HangUpAllConnection(int32_t slotId)
278 {
279 TELEPHONY_LOGI("HangUpAllConnection entry");
280 CellularCallConnectionIMS connection;
281 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
282 if (connectionMap_.empty()) {
283 TELEPHONY_LOGI("connectionMap_ is empty.");
284 return TELEPHONY_ERROR;
285 }
286 for (auto &it : connectionMap_) {
287 int32_t index = it.second.GetIndex();
288 std::string number = it.second.GetNumber();
289 connection.RejectRequest(slotId, number, index);
290 }
291 // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
292 // so the reject interface is reused.
293 return TELEPHONY_SUCCESS;
294 }
295
InviteToConference(int32_t slotId, const std::vector<std::string> &numberList)296 int32_t IMSControl::InviteToConference(int32_t slotId, const std::vector<std::string> &numberList)
297 {
298 TELEPHONY_LOGI("InviteToConference entry");
299 CellularCallConnectionIMS connection;
300 return connection.InviteToConferenceRequest(slotId, numberList);
301 }
302
KickOutFromConference(int32_t slotId, const std::string &KickOutString, int32_t index)303 int32_t IMSControl::KickOutFromConference(int32_t slotId, const std::string &KickOutString, int32_t index)
304 {
305 TELEPHONY_LOGI("KickOutFromConference entry");
306 if (KickOutString.empty()) {
307 TELEPHONY_LOGW("KickOutFromConference, splitString is empty.");
308 }
309
310 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
311 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, index);
312 if (pConnection != nullptr) {
313 return pConnection->KickOutFromConferenceRequest(slotId, pConnection->GetIndex());
314 }
315
316 TELEPHONY_LOGI("KickOutFromConference: connection cannot be matched, use index directly");
317 CellularCallConnectionIMS connection;
318 return connection.KickOutFromConferenceRequest(slotId, index);
319 }
320
StartRtt(int32_t slotId, const std::string &msg)321 int32_t IMSControl::StartRtt(int32_t slotId, const std::string &msg)
322 {
323 TELEPHONY_LOGI("StartRtt entry");
324 CellularCallConnectionIMS connection;
325 return connection.StartRttRequest(slotId, msg);
326 }
327
StopRtt(int32_t slotId)328 int32_t IMSControl::StopRtt(int32_t slotId)
329 {
330 TELEPHONY_LOGI("StopRtt entry");
331 CellularCallConnectionIMS connection;
332 return connection.StopRttRequest(slotId);
333 }
334
ReleaseAllConnection()335 void IMSControl::ReleaseAllConnection()
336 {
337 TELEPHONY_LOGI("ReleaseAllConnection entry");
338 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
339 connectionMap_.clear();
340 }
341
GetConnectionMap()342 ImsConnectionMap IMSControl::GetConnectionMap()
343 {
344 TELEPHONY_LOGI("GetConnectionMap entry");
345 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
346 return connectionMap_;
347 }
348
ReportImsCallsData(int32_t slotId, const ImsCurrentCallList &callInfoList)349 int32_t IMSControl::ReportImsCallsData(int32_t slotId, const ImsCurrentCallList &callInfoList)
350 {
351 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
352 if (callInfoList.callSize <= 0) {
353 return ReportHangUpInfo(slotId);
354 } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
355 return ReportIncomingInfo(slotId, callInfoList);
356 } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
357 return ReportUpdateInfo(slotId, callInfoList);
358 }
359 return TELEPHONY_ERROR;
360 }
361
ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)362 int32_t IMSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
363 {
364 return TELEPHONY_ERROR;
365 }
366
ReportHangUpInfo(int32_t slotId)367 int32_t IMSControl::ReportHangUpInfo(int32_t slotId)
368 {
369 TELEPHONY_LOGI("ReportHangUpInfo entry");
370 CallsReportInfo callsReportInfo;
371 for (auto &it : connectionMap_) {
372 CallReportInfo reportInfo = it.second.GetCallReportInfo();
373 reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
374 reportInfo.accountId = slotId;
375 callsReportInfo.callVec.push_back(reportInfo);
376 GetCallFailReason(slotId, connectionMap_);
377 }
378 if (connectionMap_.empty()) {
379 TELEPHONY_LOGI("connectionMap_ is empty");
380 CallReportInfo reportInfo;
381 reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
382 reportInfo.accountId = slotId;
383 callsReportInfo.callVec.push_back(reportInfo);
384 }
385 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
386 TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr.");
387 return TELEPHONY_ERR_LOCAL_PTR_NULL;
388 }
389 callsReportInfo.slotId = slotId;
390 if (isIgnoredIncomingCall_) {
391 isIgnoredIncomingCall_ = false;
392 } else {
393 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
394 }
395 ReleaseAllConnection();
396 return TELEPHONY_SUCCESS;
397 }
398
ReportIncomingInfo(int32_t slotId, const ImsCurrentCallList &imsCurrentCallInfoList)399 int32_t IMSControl::ReportIncomingInfo(int32_t slotId, const ImsCurrentCallList &imsCurrentCallInfoList)
400 {
401 TELEPHONY_LOGI("ReportIncomingInfo entry");
402 CallsReportInfo callsReportInfo;
403 for (int32_t i = 0; i < imsCurrentCallInfoList.callSize; ++i) {
404 CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, imsCurrentCallInfoList.calls[i]);
405
406 CellularCallConnectionIMS connection;
407 connection.SetStatus(static_cast<TelCallState>(imsCurrentCallInfoList.calls[i].state));
408 connection.SetIndex(imsCurrentCallInfoList.calls[i].index);
409 connection.SetNumber(imsCurrentCallInfoList.calls[i].number);
410 connection.SetOrUpdateCallReportInfo(reportInfo);
411 SetConnectionData(connectionMap_, imsCurrentCallInfoList.calls[i].index, connection);
412
413 callsReportInfo.callVec.push_back(reportInfo);
414 }
415 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
416 TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr.");
417 return TELEPHONY_ERR_ARGUMENT_INVALID;
418 }
419 callsReportInfo.slotId = slotId;
420 if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() &&
421 callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) {
422 isIgnoredIncomingCall_ = true;
423 } else {
424 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
425 }
426 return TELEPHONY_SUCCESS;
427 }
428
ReportUpdateInfo(int32_t slotId, const ImsCurrentCallList &callInfoList)429 int32_t IMSControl::ReportUpdateInfo(int32_t slotId, const ImsCurrentCallList &callInfoList)
430 {
431 TELEPHONY_LOGD("ReportUpdateInfo entry");
432 CallsReportInfo callsReportInfo;
433 for (int32_t i = 0; i < callInfoList.callSize; ++i) {
434 CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
435 if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) {
436 TELEPHONY_LOGI("only one call, report incoming state instead of waiting state");
437 reportInfo.state = TelCallState::CALL_STATUS_INCOMING;
438 }
439 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(
440 connectionMap_, callInfoList.calls[i].index);
441 if (pConnection == nullptr) {
442 CellularCallConnectionIMS connection;
443 connection.SetOrUpdateCallReportInfo(reportInfo);
444 connection.SetFlag(true);
445 connection.SetIndex(callInfoList.calls[i].index);
446 connection.SetNumber(callInfoList.calls[i].number);
447 SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
448 } else {
449 TelCallState preCallState = pConnection->GetStatus();
450 pConnection->SetFlag(true);
451 pConnection->SetIndex(callInfoList.calls[i].index);
452 pConnection->SetNumber(callInfoList.calls[i].number);
453 pConnection->SetOrUpdateCallReportInfo(reportInfo);
454 TelCallState curCallState = pConnection->GetStatus();
455 if (IsConnectedOut(preCallState, curCallState)) {
456 pConnection->UpdateCallNumber(pendingPhoneNumber_);
457 pendingPhoneNumber_.clear();
458 ExecutePostDial(slotId, pConnection->GetIndex());
459 }
460 }
461 callsReportInfo.callVec.push_back(reportInfo);
462 }
463 callsReportInfo.slotId = slotId;
464 DeleteConnection(callsReportInfo, callInfoList);
465 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
466 TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr.");
467 return TELEPHONY_ERR_LOCAL_PTR_NULL;
468 }
469 if (isIgnoredIncomingCall_) {
470 isIgnoredIncomingCall_ = false;
471 } else {
472 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
473 }
474 return TELEPHONY_SUCCESS;
475 }
476
EncapsulationCallReportInfo(int32_t slotId, const ImsCurrentCall &callInfo)477 CallReportInfo IMSControl::EncapsulationCallReportInfo(int32_t slotId, const ImsCurrentCall &callInfo)
478 {
479 TELEPHONY_LOGD("EncapsulationCallReportInfo entry");
480 CallReportInfo callReportInfo;
481 if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) {
482 TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail.");
483 return callReportInfo;
484 }
485
486 StandardizeUtils standardizeUtils;
487 std::string phoneNumber = callInfo.number.empty() ? callInfo.name : callInfo.number;
488 std::string newString = standardizeUtils.FormatNumberAndToa(phoneNumber, callInfo.toa);
489 size_t cpyLen = strlen(newString.c_str()) + 1;
490 if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) {
491 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
492 return callReportInfo;
493 }
494 if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) {
495 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
496 return callReportInfo;
497 }
498 callReportInfo.index = callInfo.index;
499 callReportInfo.accountId = slotId;
500 callReportInfo.state = static_cast<TelCallState>(callInfo.state);
501 callReportInfo.voiceDomain = callInfo.voiceDomain;
502 callReportInfo.callType = CallType::TYPE_IMS;
503 switch (callInfo.callType) {
504 case ImsCallType::TEL_IMS_CALL_TYPE_VOICE:
505 callReportInfo.callMode = VideoStateType::TYPE_VOICE;
506 break;
507 case ImsCallType::TEL_IMS_CALL_TYPE_VT_TX:
508 callReportInfo.callMode = VideoStateType::TYPE_SEND_ONLY;
509 break;
510 case ImsCallType::TEL_IMS_CALL_TYPE_VT_RX:
511 callReportInfo.callMode = VideoStateType::TYPE_RECEIVE_ONLY;
512 break;
513 case ImsCallType::TEL_IMS_CALL_TYPE_VT:
514 callReportInfo.callMode = VideoStateType::TYPE_VIDEO;
515 break;
516 default:
517 callReportInfo.callMode = VideoStateType::TYPE_VOICE;
518 break;
519 }
520 callReportInfo.mpty = callInfo.mpty;
521 callReportInfo.crsType = callInfo.toneType;
522 callReportInfo.originalCallType = callInfo.callInitialType;
523 return callReportInfo;
524 }
525
DeleteConnection(CallsReportInfo &callsReportInfo, const ImsCurrentCallList &callInfoList)526 void IMSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const ImsCurrentCallList &callInfoList)
527 {
528 TELEPHONY_LOGI("DeleteConnection entry");
529 auto it = connectionMap_.begin();
530 while (it != connectionMap_.end()) {
531 if (!it->second.GetFlag()) {
532 CallReportInfo callReportInfo = it->second.GetCallReportInfo();
533 callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
534 callsReportInfo.callVec.push_back(callReportInfo);
535 it = connectionMap_.erase(it);
536 GetCallFailReason(callsReportInfo.slotId, connectionMap_);
537 } else {
538 it->second.SetFlag(false);
539 ++it;
540 }
541 }
542 }
543
ExecutePostDial(int32_t slotId, int64_t callId)544 int32_t IMSControl::ExecutePostDial(int32_t slotId, int64_t callId)
545 {
546 TELEPHONY_LOGI("ExecutePostDial entry");
547 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
548 if (connectionMap_.empty()) {
549 TELEPHONY_LOGE("connectionMap_ is empty.");
550 return TELEPHONY_ERROR;
551 }
552 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callId);
553 if (pConnection == nullptr) {
554 return TELEPHONY_ERR_LOCAL_PTR_NULL;
555 }
556 char currentChar;
557 PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar);
558 switch (state) {
559 case PostDialCallState::POST_DIAL_CALL_STARTED:
560 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar);
561 break;
562 case PostDialCallState::POST_DIAL_CALL_DELAY:
563 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay(
564 pConnection->GetLeftPostDialCallString());
565 break;
566 default:
567 break;
568 }
569 return TELEPHONY_SUCCESS;
570 }
571
PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)572 int32_t IMSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)
573 {
574 TELEPHONY_LOGI("PostDialProceed entry");
575 std::string networkAddress;
576 std::string postDialString;
577 StandardizeUtils standardizeUtils;
578 standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString);
579 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
580 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_,
581 callInfo.index);
582 if (pConnection == nullptr) {
583 TELEPHONY_LOGE("ims pConnection is nullptr!");
584 return TELEPHONY_ERR_LOCAL_PTR_NULL;
585 }
586 if (proceed) {
587 ExecutePostDial(callInfo.slotId, pConnection->GetIndex());
588 } else {
589 pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED);
590 }
591 return TELEPHONY_SUCCESS;
592 }
593
RestoreConnection(const std::vector<CellularCallInfo> &infos, int32_t slotId)594 int32_t IMSControl::RestoreConnection(const std::vector<CellularCallInfo> &infos, int32_t slotId)
595 {
596 TELEPHONY_LOGI("RestoreConnection entry");
597 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
598 for (auto &info : infos) {
599 if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) {
600 CellularCallConnectionIMS connectionIMS;
601 connectionIMS.SetIndex(info.index);
602 connectionIMS.SetNumber(info.phoneNum);
603 SetConnectionData(connectionMap_, info.index, connectionIMS);
604 }
605 }
606 return TELEPHONY_SUCCESS;
607 }
608
ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)609 int32_t IMSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)
610 {
611 CallsReportInfo callsReportInfo;
612 callsReportInfo.slotId = slotId;
613 for (const auto &info : infos) {
614 if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) {
615 CallReportInfo imsCallReportInfo;
616 if (memset_s(imsCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) {
617 TELEPHONY_LOGE("memset_s fail");
618 return TELEPHONY_ERR_MEMSET_FAIL;
619 }
620 if (memcpy_s(imsCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) {
621 TELEPHONY_LOGE("memcpy_s fail");
622 return TELEPHONY_ERR_MEMCPY_FAIL;
623 }
624 imsCallReportInfo.index = info.index;
625 imsCallReportInfo.accountId = info.slotId;
626 imsCallReportInfo.callType = CallType::TYPE_IMS;
627 imsCallReportInfo.callMode =
628 static_cast<bool>(info.callType) ? VideoStateType::TYPE_VIDEO : VideoStateType::TYPE_VOICE;
629 imsCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
630 callsReportInfo.callVec.push_back(imsCallReportInfo);
631 }
632 }
633 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
634 TELEPHONY_LOGE("CellularCallRegister instance is nullptr");
635 return TELEPHONY_ERR_LOCAL_PTR_NULL;
636 }
637 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
638 return TELEPHONY_SUCCESS;
639 }
640
DialAfterHold(int32_t slotId)641 void IMSControl::DialAfterHold(int32_t slotId)
642 {
643 TELEPHONY_LOGI("DialAfterHold entry");
644 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
645 for (auto &connection : connectionMap_) {
646 if (connection.second.IsNeedToDial()) {
647 ImsDialInfoStruct holdToDialInfo = connection.second.GetHoldToDialInfo();
648 CellularCallConnectionIMS cellularCallConnectionIms;
649 cellularCallConnectionIms.DialRequest(slotId, holdToDialInfo);
650 connection.second.SetDialFlag(false);
651 break;
652 }
653 }
654 }
655
RecoverPendingHold()656 void IMSControl::RecoverPendingHold()
657 {
658 TELEPHONY_LOGI("RecoverPendingHold entry");
659 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
660 for (auto &connection : connectionMap_) {
661 if (connection.second.IsPendingHold()) {
662 connection.second.UpdatePendingHoldFlag(false);
663 break;
664 }
665 }
666 }
667 } // namespace Telephony
668 } // namespace OHOS
669