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 ¤tCallList, 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 ¤tCallList)
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