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