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