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 "cs_control.h" 17 18#include "cellular_call_hisysevent.h" 19#include "cellular_call_register.h" 20#include "cellular_call_service.h" 21#include "module_service_utils.h" 22#include "securec.h" 23#include "standardize_utils.h" 24 25namespace OHOS { 26namespace Telephony { 27 28CSControl::~CSControl() 29{ 30 ReleaseAllConnection(); 31} 32 33int32_t CSControl::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 43 ModuleServiceUtils moduleServiceUtils; 44 RegServiceState regState = moduleServiceUtils.GetCsRegState(callInfo.slotId); 45 if (!(regState == RegServiceState::REG_STATE_IN_SERVICE || isEcc)) { 46 TELEPHONY_LOGE("can not dial."); 47 return TELEPHONY_ERR_NETWORK_NOT_IN_SERVICE; 48 } 49 PhoneType netType = moduleServiceUtils.GetNetworkStatus(callInfo.slotId); 50 if (netType == PhoneType::PHONE_TYPE_IS_GSM) { 51 return DialGsm(callInfo); 52 } 53 if (netType == PhoneType::PHONE_TYPE_IS_CDMA) { 54 return DialCdma(callInfo); 55 } 56 TELEPHONY_LOGE("Dial return, net type error."); 57 CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType), 58 callInfo.videoState, CALL_ERR_UNSUPPORTED_NETWORK_TYPE, "Network type error"); 59 return CALL_ERR_UNSUPPORTED_NETWORK_TYPE; 60} 61 62int32_t CSControl::DialCdma(const CellularCallInfo &callInfo) 63{ 64 TELEPHONY_LOGI("DialCdma entry."); 65 StandardizeUtils standardizeUtils; 66 // Remove the phone number separator 67 std::string newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(callInfo.phoneNum); 68 69 CLIRMode clirMode = CLIRMode::DEFAULT; 70 if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, false)) { 71 TELEPHONY_LOGI("DialCdma return, mmi code type."); 72 return RETURN_TYPE_MMI; 73 } 74 75 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 76 if (!CanCall(connectionMap_)) { 77 TELEPHONY_LOGE("CSControl::DialCdma return, error type: call state error."); 78 CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType), 79 callInfo.videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "cs cdma dial call state error"); 80 return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT; 81 } 82 83 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) { 84 TELEPHONY_LOGI("DialCdma, CDMA is have connection in active state."); 85 CellularCallConnectionCS csConnection; 86 return csConnection.SendCDMAThreeWayDialRequest(callInfo.slotId); 87 } 88 89 return EncapsulateDialCommon(callInfo.slotId, newPhoneNum, clirMode); 90} 91 92int32_t CSControl::DialGsm(const CellularCallInfo &callInfo) 93{ 94 TELEPHONY_LOGI("DialGsm entry."); 95 StandardizeUtils standardizeUtils; 96 // Remove the phone number separator 97 std::string newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(callInfo.phoneNum); 98 99 CLIRMode clirMode = CLIRMode::DEFAULT; 100 if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, false)) { 101 TELEPHONY_LOGI("DialGsm return, mmi code type."); 102 return RETURN_TYPE_MMI; 103 } 104 105 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 106 if (!CanCall(connectionMap_)) { 107 TELEPHONY_LOGE("DialGsm return, error type: call state error."); 108 CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType), 109 callInfo.videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "cs gsm dial call state error"); 110 return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT; 111 } 112 113 // Calls can be put on hold, recovered, released, added to conversation, 114 // and transferred similarly as defined in 3GPP TS 22.030 [19]. 115 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) { 116 // New calls must be active, so other calls need to be hold 117 TELEPHONY_LOGI("DialGsm, GSM is have connection in active state."); 118 CellularCallConnectionCS pConnection; 119 120 // Delay dialing to prevent failure to add a new call while making a multi-party call 121 // Will it block the main thread or other threads? Will the reception of messages be blocked during sleep? 122 // - a call can be temporarily disconnected from the ME but the connection is retained by the network 123 pConnection.SwitchCallRequest(callInfo.slotId); 124 } 125 return EncapsulateDialCommon(callInfo.slotId, newPhoneNum, clirMode); 126} 127 128int32_t CSControl::EncapsulateDialCommon(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode) 129{ 130 pendingPhoneNumber_ = phoneNum; 131 DialRequestStruct dialRequest; 132 /** 133 * <idx>: integer type; 134 * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1 135 * this number can be used in +CHLD command operations 136 * <dir>: 137 */ 138 dialRequest.phoneNum = phoneNum; 139 140 /** 141 * <n> (parameter sets the adjustment for outgoing calls): 142 * 0 presentation indicator is used according to the subscription of the CLIR service 143 * 1 CLIR invocation 144 * 2 CLIR suppression 145 */ 146 dialRequest.clirMode = clirMode; 147 148 /** 149 * An example of voice group call service request usage: 150 * ATD*17*753#500; (originate voice group call with the priority level 3) 151 * OK (voice group call setup was successful) 152 */ 153 CellularCallConnectionCS csConnection; 154 TELEPHONY_LOGI("Set Mute to false"); 155 if (DelayedSingleton<CellularCallService>::GetInstance() == nullptr) { 156 TELEPHONY_LOGE("SetMute return, error type: GetInstance() is nullptr."); 157 return CALL_ERR_RESOURCE_UNAVAILABLE; 158 } 159 DelayedSingleton<CellularCallService>::GetInstance()->SetMute(slotId, false); 160 return csConnection.DialRequest(slotId, dialRequest); 161} 162 163int32_t CSControl::HangUp(const CellularCallInfo &callInfo, CallSupplementType type) 164{ 165 TELEPHONY_LOGI("HangUp start"); 166 switch (type) { 167 case CallSupplementType::TYPE_DEFAULT: { 168 // Match the session connection according to the phone number string 169 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 170 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>( 171 connectionMap_, callInfo.index); 172 if (pConnection == nullptr) { 173 TELEPHONY_LOGE("CSControl::HangUp, error type: connection is null"); 174 CellularCallHiSysEvent::WriteHangUpFaultEvent( 175 callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "HangUp pConnection is null"); 176 return CALL_ERR_CALL_CONNECTION_NOT_EXIST; 177 } 178 179 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) { 180 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo( 181 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING); 182 } 183 184 /** 185 * The "directory number" case shall be handled with dial command D, 186 * and the END case with hangup command H (or +CHUP). 187 * (e.g. +CHLD: (0,1,1x,2,2x,3)). 188 * NOTE: Call Hold, MultiParty and Explicit Call Transfer are only applicable to teleservice 11. 189 */ 190 return pConnection->HangUpRequest(callInfo.slotId); 191 } 192 // 3GPP TS 27.007 V3.9.0 (2001-06) Call related supplementary services +CHLD 193 // 3GPP TS 27.007 V3.9.0 (2001-06) 7.22 Informative examples 194 case CallSupplementType::TYPE_HANG_UP_HOLD_WAIT: 195 // release the second (active) call and recover the first (held) call 196 case CallSupplementType::TYPE_HANG_UP_ACTIVE: { 197 CellularCallConnectionCS connection; 198 return connection.CallSupplementRequest(callInfo.slotId, type); 199 } 200 case CallSupplementType::TYPE_HANG_UP_ALL: { 201 TELEPHONY_LOGI("HangUp, hang up all call"); 202 CellularCallConnectionCS connection; 203 // The AT command for hanging up all calls is the same as the AT command for rejecting calls, 204 // so the reject interface is reused. 205 return connection.RejectRequest(callInfo.slotId); 206 } 207 default: { 208 TELEPHONY_LOGE("HangUp warring, type is invalid"); 209 CellularCallHiSysEvent::WriteHangUpFaultEvent( 210 callInfo.slotId, callInfo.callId, TELEPHONY_ERR_ARGUMENT_INVALID, "HangUp type is invalid"); 211 return TELEPHONY_ERR_ARGUMENT_INVALID; 212 } 213 } 214} 215 216int32_t CSControl::Answer(const CellularCallInfo &callInfo) 217{ 218 TELEPHONY_LOGI("CSControl::Answer start"); 219 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 220 auto pConnection = 221 FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index); 222 if (pConnection == nullptr) { 223 TELEPHONY_LOGE("Answer return, error type: connection is null"); 224 CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState, 225 CALL_ERR_CALL_CONNECTION_NOT_EXIST, "get connection data is null"); 226 return CALL_ERR_CALL_CONNECTION_NOT_EXIST; 227 } 228 229 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) && 230 IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) { 231 int32_t ret = CheckAndHangupHoldingCall(); 232 if (ret != TELEPHONY_SUCCESS) { 233 TELEPHONY_LOGE("hangup holding call failed"); 234 return ret; 235 } 236 } 237 /** 238 * <stat> (state of the call): 239 * 0 active 240 * 1 held 241 * 2 dialing (MO call) 242 * 3 alerting (MO call) 243 * 4 incoming (MT call) 244 * 5 waiting (MT call) 245 */ 246 // There is an active call when you call, or third party call waiting 247 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE) || 248 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) { 249 TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting"); 250 auto con = FindConnectionByState<CsConnectionMap &, CellularCallConnectionCS *>( 251 connectionMap_, TelCallState::CALL_STATUS_ACTIVE); 252 if (con != nullptr) { 253 /** 254 * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up 255 * the call. +CMOD and +FCLASS commands indicate the current settings before dialling or answering 256 * command, not that they shall be given just before D or A command. 257 */ 258 TELEPHONY_LOGI("Answer: There is an active session currently, and it needs to hold"); 259 con->SwitchCallRequest(callInfo.slotId); 260 } else { 261 TELEPHONY_LOGE("Answer return, error type: con is null, there are no active calls"); 262 } 263 } 264 265 if (pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING || 266 pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING || 267 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) { 268 return pConnection->AnswerRequest(callInfo.slotId); 269 } 270 271 TELEPHONY_LOGE("CSControl::Answer return, error type: call state error, phone not ringing."); 272 CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState, 273 CALL_ERR_CALL_STATE, "call state error phone not ringing"); 274 return CALL_ERR_CALL_STATE; 275} 276 277int32_t CSControl::CheckAndHangupHoldingCall() 278{ 279 for (auto &it : connectionMap_) { 280 CellularCallConnectionCS holdConn = it.second; 281 if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) { 282 auto callReportInfo = holdConn.GetCallReportInfo(); 283 int32_t result = holdConn.HangUpRequest(callReportInfo.accountId); 284 if (result != TELEPHONY_SUCCESS) { 285 return result; 286 } 287 } 288 } 289 return TELEPHONY_SUCCESS; 290} 291 292int32_t CSControl::Reject(const CellularCallInfo &callInfo) 293{ 294 TELEPHONY_LOGI("CSControl::Reject start"); 295 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 296 auto pConnection = 297 FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index); 298 if (pConnection == nullptr) { 299 TELEPHONY_LOGE("CSControl::Reject, error type: connection is null"); 300 CellularCallHiSysEvent::WriteHangUpFaultEvent( 301 callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "Reject pConnection is null"); 302 return CALL_ERR_CALL_CONNECTION_NOT_EXIST; 303 } 304 305 /** 306 * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up the call. 307 * +CMOD and +FCLASS commands indicate the current settings before dialling or answering command, 308 * not that they shall be given just before D or A command. 309 */ 310 if (!pConnection->IsRingingState()) { 311 TELEPHONY_LOGE("CSControl::Reject return, error type: call state error, phone not ringing."); 312 CellularCallHiSysEvent::WriteHangUpFaultEvent( 313 callInfo.slotId, callInfo.callId, CALL_ERR_CALL_STATE, "Reject call state error phone not ringing"); 314 return CALL_ERR_CALL_STATE; 315 } 316 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) { 317 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo( 318 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING); 319 } 320 return pConnection->RejectRequest(callInfo.slotId); 321} 322 323int32_t CSControl::HoldCall(int32_t slotId) 324{ 325 /** 326 * When the call hold service is invoked, communication is interrupted on the traffic channel and the traffic 327 * channel is released from the existing call. The traffic channel is reserved for the served mobile subscriber 328 * invoking the call hold service. The served mobile subscriber can only have one call on hold at a time. 329 */ 330 TELEPHONY_LOGI("HoldCall start"); 331 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 332 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) { 333 TELEPHONY_LOGE("HoldCall return, error type: call state error."); 334 return CALL_ERR_CALL_STATE; 335 } 336 CellularCallConnectionCS connection; 337 return connection.HoldRequest(slotId); 338} 339 340int32_t CSControl::UnHoldCall(int32_t slotId) 341{ 342 // A notification shall be send towards the previously held party that the call has been retrieved. 343 TELEPHONY_LOGI("UnHoldCall start"); 344 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 345 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) { 346 TELEPHONY_LOGE("UnHoldCall return, error type: call state error."); 347 return CALL_ERR_CALL_STATE; 348 } 349 CellularCallConnectionCS connection; 350 return connection.UnHoldCallRequest(slotId); 351} 352 353int32_t CSControl::SwitchCall(int32_t slotId) 354{ 355 /** 356 * If the served mobile subscriber is connected to an active call and has another call on hold, she can: 357 * 1) Alternate from one call to the other. 358 * 2) Disconnect the active call. 359 * 3) Disconnect the held call. 360 * 4) Disconnect both calls. 361 */ 362 TELEPHONY_LOGI("SwitchCall start"); 363 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 364 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) { 365 TELEPHONY_LOGE("SwitchCall return, error type: call state error."); 366 return CALL_ERR_CALL_STATE; 367 } 368 CellularCallConnectionCS connection; 369 return connection.SwitchCallRequest(slotId); 370} 371 372/** 373 * Explicitly choose one remote party to have a private communication with. 374 * This results in that remote party being removed from the multiParty call which is placed on hold, 375 * and the conversation between the served mobile subscriber and the designated remote party being a normal 376 * active call. The remaining remote parties may have communication with each other in this state. 377 */ 378int32_t CSControl::SeparateConference(int32_t slotId, const std::string &splitString, int32_t index) 379{ 380 TELEPHONY_LOGI("SeparateConference entry"); 381 if (splitString.empty()) { 382 TELEPHONY_LOGW("SeparateConference, splitString is empty."); 383 } 384 385 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 386 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, index); 387 if (pConnection != nullptr) { 388 return pConnection->SeparateConferenceRequest(slotId, pConnection->GetIndex(), VOICE_CALL); 389 } 390 391 TELEPHONY_LOGI("SeparateConference: connection cannot be matched, use index directly"); 392 CellularCallConnectionCS connection; 393 return connection.SeparateConferenceRequest(slotId, index, VOICE_CALL); 394} 395 396/** 397 * Add another remote party, to which a private communication has been established using 398 * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then 399 * exceed the maximum number allowed, which results in an active multiParty call. 400 */ 401int32_t CSControl::CombineConference(int32_t slotId) 402{ 403 CellularCallConnectionCS connectionCs; 404 return connectionCs.CombineConferenceRequest(slotId, VOICE_CALL); 405} 406 407int32_t CSControl::HangUpAllConnection(int32_t slotId) 408{ 409 TELEPHONY_LOGI("HangUpAllConnection entry"); 410 CellularCallConnectionCS connection; 411 // The AT command for hanging up all calls is the same as the AT command for rejecting calls, 412 // so the reject interface is reused. 413 return connection.RejectRequest(slotId); 414} 415 416bool CSControl::CalculateInternationalRoaming(int32_t slotId) const 417{ 418 bool ret = true; 419 ModuleServiceUtils moduleServiceUtils; 420 std::string operatorCountryIso = moduleServiceUtils.GetNetworkCountryCode(slotId); 421 std::string simCountryIso = moduleServiceUtils.GetIsoCountryCode(slotId); 422 ret = !operatorCountryIso.empty() && !simCountryIso.empty() && (operatorCountryIso != simCountryIso); 423 if (ret) { 424 if (simCountryIso == "us") { 425 ret = operatorCountryIso != "vi"; 426 } else if (simCountryIso == "vi") { 427 ret = operatorCountryIso != "us"; 428 } 429 } 430 return ret; 431} 432 433int32_t CSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList) 434{ 435 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 436 if (callInfoList.callSize <= 0) { 437 return ReportHangUpInfo(slotId); 438 } else if (callInfoList.callSize > 0 && connectionMap_.empty()) { 439 return ReportIncomingInfo(slotId, callInfoList); 440 } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) { 441 return ReportUpdateInfo(slotId, callInfoList); 442 } 443 return TELEPHONY_ERROR; 444} 445 446int32_t CSControl::ReportUpdateInfo(int32_t slotId, const CallInfoList &callInfoList) 447{ 448 TELEPHONY_LOGD("ReportUpdateInfo entry"); 449 CallsReportInfo callsReportInfo; 450 for (int32_t i = 0; i < callInfoList.callSize; ++i) { 451 CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]); 452 if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) { 453 TELEPHONY_LOGI("only one call, report incoming state instead of waiting state"); 454 reportInfo.state = TelCallState::CALL_STATUS_INCOMING; 455 } 456 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>( 457 connectionMap_, callInfoList.calls[i].index); 458 if (pConnection == nullptr) { 459 CellularCallConnectionCS connection; 460 connection.SetOrUpdateCallReportInfo(reportInfo); 461 connection.SetFlag(true); 462 connection.SetIndex(callInfoList.calls[i].index); 463 connection.SetNumber(callInfoList.calls[i].number); 464 SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection); 465 } else { 466 TelCallState preCallState = pConnection->GetStatus(); 467 pConnection->SetFlag(true); 468 pConnection->SetIndex(callInfoList.calls[i].index); 469 pConnection->SetOrUpdateCallReportInfo(reportInfo); 470 pConnection->SetNumber(callInfoList.calls[i].number); 471 TelCallState curCallState = pConnection->GetStatus(); 472 if (IsConnectedOut(preCallState, curCallState)) { 473 pConnection->UpdateCallNumber(pendingPhoneNumber_); 474 pendingPhoneNumber_.clear(); 475 ExecutePostDial(slotId, pConnection->GetIndex()); 476 } 477 } 478 callsReportInfo.callVec.push_back(reportInfo); 479 } 480 callsReportInfo.slotId = slotId; 481 DeleteConnection(callsReportInfo, callInfoList); 482 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 483 TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr."); 484 return TELEPHONY_ERR_LOCAL_PTR_NULL; 485 } 486 if (!isIgnoredIncomingCall_) { 487 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 488 } 489 return TELEPHONY_SUCCESS; 490} 491 492void CSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const CallInfoList &callInfoList) 493{ 494 TELEPHONY_LOGI("DeleteConnection entry"); 495 auto it = connectionMap_.begin(); 496 while (it != connectionMap_.end()) { 497 CallReportInfo callReportInfo = it->second.GetCallReportInfo(); 498 if (!it->second.GetFlag()) { 499 callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 500 callsReportInfo.callVec.push_back(callReportInfo); 501 it = connectionMap_.erase(it); 502 GetCallFailReason(callsReportInfo.slotId, connectionMap_); 503 } else { 504 it->second.SetFlag(false); 505 ++it; 506 } 507 } 508} 509 510CallReportInfo CSControl::EncapsulationCallReportInfo(int32_t slotId, const CallInfo &callInfo) 511{ 512 CallReportInfo callReportInfo; 513 if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) { 514 TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail."); 515 return callReportInfo; 516 } 517 StandardizeUtils standardizeUtils; 518 std::string newString = standardizeUtils.FormatNumberAndToa(callInfo.number, callInfo.type); 519 520 /** 521 * <idx>: integer type; 522 * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1 523 * this number can be used in +CHLD command operations 524 * <dir>: 525 */ 526 size_t cpyLen = strlen(newString.c_str()) + 1; 527 if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) { 528 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail."); 529 return callReportInfo; 530 } 531 if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) { 532 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail."); 533 return callReportInfo; 534 } 535 536 /** 537 * <stat> (state of the call): 538 * 0 active 539 * 1 held 540 * 2 dialing (MO call) 541 * 3 alerting (MO call) 542 * 4 incoming (MT call) 543 * 5 waiting (MT call) 544 */ 545 callReportInfo.index = callInfo.index; 546 callReportInfo.accountId = slotId; 547 callReportInfo.voiceDomain = callInfo.voiceDomain; 548 callReportInfo.state = static_cast<TelCallState>(callInfo.state); 549 callReportInfo.callType = CallType::TYPE_CS; 550 callReportInfo.callMode = VideoStateType::TYPE_VOICE; 551 callReportInfo.mpty = callInfo.mpty; 552 return callReportInfo; 553} 554 555int32_t CSControl::ReportIncomingInfo(int32_t slotId, const CallInfoList &callInfoList) 556{ 557 TELEPHONY_LOGI("ReportIncomingInfo entry"); 558 CallsReportInfo callsReportInfo; 559 for (int32_t i = 0; i < callInfoList.callSize; ++i) { 560 CallReportInfo cellularCallReportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]); 561 562 CellularCallConnectionCS connection; 563 connection.SetStatus(static_cast<TelCallState>(callInfoList.calls[i].state)); 564 connection.SetIndex(callInfoList.calls[i].index); 565 connection.SetOrUpdateCallReportInfo(cellularCallReportInfo); 566 connection.SetNumber(callInfoList.calls[i].number); 567 SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection); 568 569 callsReportInfo.callVec.push_back(cellularCallReportInfo); 570 } 571 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 572 TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr."); 573 return TELEPHONY_ERR_ARGUMENT_INVALID; 574 } 575 callsReportInfo.slotId = slotId; 576 if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() && 577 callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) { 578 isIgnoredIncomingCall_ = true; 579 } else { 580 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 581 } 582 return TELEPHONY_SUCCESS; 583} 584 585int32_t CSControl::ReportHangUpInfo(int32_t slotId) 586{ 587 TELEPHONY_LOGD("ReportHangUpInfo entry"); 588 CallsReportInfo callsReportInfo; 589 for (auto &it : connectionMap_) { 590 CallReportInfo callReportInfo = it.second.GetCallReportInfo(); 591 callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 592 callReportInfo.accountId = slotId; 593 callsReportInfo.callVec.push_back(callReportInfo); 594 GetCallFailReason(slotId, connectionMap_); 595 } 596 if (connectionMap_.empty()) { 597 TELEPHONY_LOGI("connectionMap_ is empty"); 598 CallReportInfo reportInfo; 599 reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 600 reportInfo.accountId = slotId; 601 callsReportInfo.callVec.push_back(reportInfo); 602 } 603 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 604 TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr."); 605 return TELEPHONY_ERR_LOCAL_PTR_NULL; 606 } 607 callsReportInfo.slotId = slotId; 608 if (isIgnoredIncomingCall_) { 609 isIgnoredIncomingCall_ = false; 610 } else { 611 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 612 } 613 ReleaseAllConnection(); 614 return TELEPHONY_SUCCESS; 615} 616 617int32_t CSControl::ExecutePostDial(int32_t slotId, int64_t callId) 618{ 619 TELEPHONY_LOGI("ExecutePostDial entry"); 620 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 621 if (connectionMap_.empty()) { 622 TELEPHONY_LOGE("connectionMap_ is empty."); 623 return TELEPHONY_ERROR; 624 } 625 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callId); 626 if (pConnection == nullptr) { 627 return TELEPHONY_ERR_LOCAL_PTR_NULL; 628 } 629 char currentChar; 630 PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar); 631 switch (state) { 632 case PostDialCallState::POST_DIAL_CALL_STARTED: 633 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar); 634 break; 635 case PostDialCallState::POST_DIAL_CALL_DELAY: 636 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay( 637 pConnection->GetLeftPostDialCallString()); 638 break; 639 default: 640 break; 641 } 642 return TELEPHONY_SUCCESS; 643} 644 645int32_t CSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed) 646{ 647 TELEPHONY_LOGI("PostDialProceed entry"); 648 std::string networkAddress; 649 std::string postDialString; 650 StandardizeUtils standardizeUtils; 651 standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString); 652 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 653 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>( 654 connectionMap_, callInfo.index); 655 if (pConnection == nullptr) { 656 TELEPHONY_LOGE("cs pConnection is nullptr!"); 657 return TELEPHONY_ERR_LOCAL_PTR_NULL; 658 } 659 if (proceed) { 660 ExecutePostDial(callInfo.slotId, pConnection->GetIndex()); 661 } else { 662 pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED); 663 } 664 return TELEPHONY_SUCCESS; 665} 666 667void CSControl::ReleaseAllConnection() 668{ 669 TELEPHONY_LOGI("ReleaseAllConnection entry"); 670 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 671 connectionMap_.clear(); 672} 673 674CsConnectionMap CSControl::GetConnectionMap() 675{ 676 TELEPHONY_LOGI("GetConnectionMap entry"); 677 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 678 return connectionMap_; 679} 680 681int32_t CSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId) 682{ 683 CallsReportInfo callsReportInfo; 684 callsReportInfo.slotId = slotId; 685 for (const auto &info : infos) { 686 if (info.callType == CallType::TYPE_CS && info.slotId == slotId) { 687 CallReportInfo csCallReportInfo; 688 if (memset_s(csCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) { 689 TELEPHONY_LOGE("memset_s fail"); 690 return TELEPHONY_ERR_MEMSET_FAIL; 691 } 692 if (memcpy_s(csCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) { 693 TELEPHONY_LOGE("memcpy_s fail"); 694 return TELEPHONY_ERR_MEMCPY_FAIL; 695 } 696 csCallReportInfo.index = info.index; 697 csCallReportInfo.accountId = info.slotId; 698 csCallReportInfo.callType = CallType::TYPE_CS; 699 csCallReportInfo.callMode = VideoStateType::TYPE_VOICE; 700 csCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 701 callsReportInfo.callVec.push_back(csCallReportInfo); 702 } 703 } 704 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 705 TELEPHONY_LOGE("CellularCallRegister instance is nullptr"); 706 return TELEPHONY_ERR_LOCAL_PTR_NULL; 707 } 708 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 709 ReleaseAllConnection(); 710 return TELEPHONY_SUCCESS; 711} 712} // namespace Telephony 713} // namespace OHOS 714