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
25 namespace OHOS {
26 namespace Telephony {
27
~CSControl()28 CSControl::~CSControl()
29 {
30 ReleaseAllConnection();
31 }
32
Dial(const CellularCallInfo & callInfo,bool isEcc)33 int32_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
DialCdma(const CellularCallInfo & callInfo)62 int32_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
DialGsm(const CellularCallInfo & callInfo)92 int32_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
EncapsulateDialCommon(int32_t slotId,const std::string & phoneNum,CLIRMode & clirMode)128 int32_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
HangUp(const CellularCallInfo & callInfo,CallSupplementType type)163 int32_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
Answer(const CellularCallInfo & callInfo)216 int32_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
CheckAndHangupHoldingCall()277 int32_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
Reject(const CellularCallInfo & callInfo)292 int32_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
HoldCall(int32_t slotId)323 int32_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
UnHoldCall(int32_t slotId)340 int32_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
SwitchCall(int32_t slotId)353 int32_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 */
SeparateConference(int32_t slotId,const std::string & splitString,int32_t index)378 int32_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 */
CombineConference(int32_t slotId)401 int32_t CSControl::CombineConference(int32_t slotId)
402 {
403 CellularCallConnectionCS connectionCs;
404 return connectionCs.CombineConferenceRequest(slotId, VOICE_CALL);
405 }
406
HangUpAllConnection(int32_t slotId)407 int32_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
CalculateInternationalRoaming(int32_t slotId) const416 bool 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
ReportCallsData(int32_t slotId,const CallInfoList & callInfoList)433 int32_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
ReportUpdateInfo(int32_t slotId,const CallInfoList & callInfoList)446 int32_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
DeleteConnection(CallsReportInfo & callsReportInfo,const CallInfoList & callInfoList)492 void 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 connectionMap_.erase(it++);
502 GetCallFailReason(callsReportInfo.slotId, connectionMap_);
503 } else {
504 it->second.SetFlag(false);
505 ++it;
506 }
507 }
508 }
509
EncapsulationCallReportInfo(int32_t slotId,const CallInfo & callInfo)510 CallReportInfo 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
ReportIncomingInfo(int32_t slotId,const CallInfoList & callInfoList)555 int32_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
ReportHangUpInfo(int32_t slotId)585 int32_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
ExecutePostDial(int32_t slotId,int64_t callId)617 int32_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
PostDialProceed(const CellularCallInfo & callInfo,const bool proceed)645 int32_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
ReleaseAllConnection()667 void CSControl::ReleaseAllConnection()
668 {
669 TELEPHONY_LOGI("ReleaseAllConnection entry");
670 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
671 connectionMap_.clear();
672 }
673
GetConnectionMap()674 CsConnectionMap CSControl::GetConnectionMap()
675 {
676 TELEPHONY_LOGI("GetConnectionMap entry");
677 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
678 return connectionMap_;
679 }
680
ReportHangUp(const std::vector<CellularCallInfo> & infos,int32_t slotId)681 int32_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