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<ffrt::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<ffrt::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<ffrt::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 pConnection->SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
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 UpdateCallDisconnectReason(callInfo.callId, RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
199 return connection.CallSupplementRequest(callInfo.slotId, type);
200 }
201 case CallSupplementType::TYPE_HANG_UP_ALL: {
202 TELEPHONY_LOGI("HangUp, hang up all call");
203 CellularCallConnectionCS connection;
204 // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
205 // so the reject interface is reused.
206 {
207 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
208 for (auto &connection : connectionMap_) {
209 connection.second.SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_TERMINATED);
210 }
211 }
212 return connection.RejectRequest(callInfo.slotId);
213 }
214 default: {
215 TELEPHONY_LOGE("HangUp warring, type is invalid");
216 CellularCallHiSysEvent::WriteHangUpFaultEvent(
217 callInfo.slotId, callInfo.callId, TELEPHONY_ERR_ARGUMENT_INVALID, "HangUp type is invalid");
218 return TELEPHONY_ERR_ARGUMENT_INVALID;
219 }
220 }
221 }
222
Answer(const CellularCallInfo & callInfo)223 int32_t CSControl::Answer(const CellularCallInfo &callInfo)
224 {
225 TELEPHONY_LOGI("CSControl::Answer start");
226 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
227 auto pConnection =
228 FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index);
229 if (pConnection == nullptr) {
230 TELEPHONY_LOGE("Answer return, error type: connection is null");
231 CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState,
232 CALL_ERR_CALL_CONNECTION_NOT_EXIST, "get connection data is null");
233 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
234 }
235
236 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) &&
237 IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
238 int32_t ret = CheckAndHangupHoldingCall();
239 if (ret != TELEPHONY_SUCCESS) {
240 TELEPHONY_LOGE("hangup holding call failed");
241 return ret;
242 }
243 }
244 /**
245 * <stat> (state of the call):
246 * 0 active
247 * 1 held
248 * 2 dialing (MO call)
249 * 3 alerting (MO call)
250 * 4 incoming (MT call)
251 * 5 waiting (MT call)
252 */
253 // There is an active call when you call, or third party call waiting
254 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE) ||
255 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
256 TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting");
257 auto con = FindConnectionByState<CsConnectionMap &, CellularCallConnectionCS *>(
258 connectionMap_, TelCallState::CALL_STATUS_ACTIVE);
259 if (con != nullptr) {
260 /**
261 * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up
262 * the call. +CMOD and +FCLASS commands indicate the current settings before dialling or answering
263 * command, not that they shall be given just before D or A command.
264 */
265 TELEPHONY_LOGI("Answer: There is an active session currently, and it needs to hold");
266 con->SwitchCallRequest(callInfo.slotId);
267 } else {
268 TELEPHONY_LOGE("Answer return, error type: con is null, there are no active calls");
269 }
270 }
271
272 if (pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING ||
273 pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING ||
274 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
275 return pConnection->AnswerRequest(callInfo.slotId);
276 }
277
278 TELEPHONY_LOGE("CSControl::Answer return, error type: call state error, phone not ringing.");
279 CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState,
280 CALL_ERR_CALL_STATE, "call state error phone not ringing");
281 return CALL_ERR_CALL_STATE;
282 }
283
CheckAndHangupHoldingCall()284 int32_t CSControl::CheckAndHangupHoldingCall()
285 {
286 for (auto &it : connectionMap_) {
287 CellularCallConnectionCS holdConn = it.second;
288 if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) {
289 auto callReportInfo = holdConn.GetCallReportInfo();
290 int32_t result = holdConn.HangUpRequest(callReportInfo.accountId);
291 if (result != TELEPHONY_SUCCESS) {
292 return result;
293 }
294 }
295 }
296 return TELEPHONY_SUCCESS;
297 }
298
Reject(const CellularCallInfo & callInfo)299 int32_t CSControl::Reject(const CellularCallInfo &callInfo)
300 {
301 TELEPHONY_LOGI("CSControl::Reject start");
302 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
303 auto pConnection =
304 FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index);
305 if (pConnection == nullptr) {
306 TELEPHONY_LOGE("CSControl::Reject, error type: connection is null");
307 CellularCallHiSysEvent::WriteHangUpFaultEvent(
308 callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "Reject pConnection is null");
309 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
310 }
311
312 /**
313 * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up the call.
314 * +CMOD and +FCLASS commands indicate the current settings before dialling or answering command,
315 * not that they shall be given just before D or A command.
316 */
317 if (!pConnection->IsRingingState()) {
318 TELEPHONY_LOGE("CSControl::Reject return, error type: call state error, phone not ringing.");
319 CellularCallHiSysEvent::WriteHangUpFaultEvent(
320 callInfo.slotId, callInfo.callId, CALL_ERR_CALL_STATE, "Reject call state error phone not ringing");
321 return CALL_ERR_CALL_STATE;
322 }
323 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
324 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
325 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
326 }
327 pConnection->SetDisconnectReason(RilDisconnectedReason::DISCONNECTED_REASON_USER_DECLINE);
328 return pConnection->RejectRequest(callInfo.slotId);
329 }
330
HoldCall(int32_t slotId)331 int32_t CSControl::HoldCall(int32_t slotId)
332 {
333 /**
334 * When the call hold service is invoked, communication is interrupted on the traffic channel and the traffic
335 * channel is released from the existing call. The traffic channel is reserved for the served mobile subscriber
336 * invoking the call hold service. The served mobile subscriber can only have one call on hold at a time.
337 */
338 TELEPHONY_LOGI("HoldCall start");
339 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
340 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
341 TELEPHONY_LOGE("HoldCall return, error type: call state error.");
342 return CALL_ERR_CALL_STATE;
343 }
344 CellularCallConnectionCS connection;
345 return connection.HoldRequest(slotId);
346 }
347
UnHoldCall(int32_t slotId)348 int32_t CSControl::UnHoldCall(int32_t slotId)
349 {
350 // A notification shall be send towards the previously held party that the call has been retrieved.
351 TELEPHONY_LOGI("UnHoldCall start");
352 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
353 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
354 TELEPHONY_LOGE("UnHoldCall return, error type: call state error.");
355 return CALL_ERR_CALL_STATE;
356 }
357 CellularCallConnectionCS connection;
358 return connection.UnHoldCallRequest(slotId);
359 }
360
SwitchCall(int32_t slotId)361 int32_t CSControl::SwitchCall(int32_t slotId)
362 {
363 /**
364 * If the served mobile subscriber is connected to an active call and has another call on hold, she can:
365 * 1) Alternate from one call to the other.
366 * 2) Disconnect the active call.
367 * 3) Disconnect the held call.
368 * 4) Disconnect both calls.
369 */
370 TELEPHONY_LOGI("SwitchCall start");
371 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
372 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
373 TELEPHONY_LOGE("SwitchCall return, error type: call state error.");
374 return CALL_ERR_CALL_STATE;
375 }
376 CellularCallConnectionCS connection;
377 return connection.SwitchCallRequest(slotId);
378 }
379
380 /**
381 * Explicitly choose one remote party to have a private communication with.
382 * This results in that remote party being removed from the multiParty call which is placed on hold,
383 * and the conversation between the served mobile subscriber and the designated remote party being a normal
384 * active call. The remaining remote parties may have communication with each other in this state.
385 */
SeparateConference(int32_t slotId,const std::string & splitString,int32_t index)386 int32_t CSControl::SeparateConference(int32_t slotId, const std::string &splitString, int32_t index)
387 {
388 TELEPHONY_LOGI("SeparateConference entry");
389 if (splitString.empty()) {
390 TELEPHONY_LOGW("SeparateConference, splitString is empty.");
391 }
392
393 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
394 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, index);
395 if (pConnection != nullptr) {
396 return pConnection->SeparateConferenceRequest(slotId, pConnection->GetIndex(), VOICE_CALL);
397 }
398
399 TELEPHONY_LOGI("SeparateConference: connection cannot be matched, use index directly");
400 CellularCallConnectionCS connection;
401 return connection.SeparateConferenceRequest(slotId, index, VOICE_CALL);
402 }
403
404 /**
405 * Add another remote party, to which a private communication has been established using
406 * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then
407 * exceed the maximum number allowed, which results in an active multiParty call.
408 */
CombineConference(int32_t slotId)409 int32_t CSControl::CombineConference(int32_t slotId)
410 {
411 CellularCallConnectionCS connectionCs;
412 return connectionCs.CombineConferenceRequest(slotId, VOICE_CALL);
413 }
414
HangUpAllConnection(int32_t slotId)415 int32_t CSControl::HangUpAllConnection(int32_t slotId)
416 {
417 TELEPHONY_LOGI("HangUpAllConnection entry");
418 CellularCallConnectionCS connection;
419 // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
420 // so the reject interface is reused.
421 return connection.RejectRequest(slotId);
422 }
423
CalculateInternationalRoaming(int32_t slotId) const424 bool CSControl::CalculateInternationalRoaming(int32_t slotId) const
425 {
426 bool ret = true;
427 ModuleServiceUtils moduleServiceUtils;
428 std::string operatorCountryIso = moduleServiceUtils.GetNetworkCountryCode(slotId);
429 std::string simCountryIso = moduleServiceUtils.GetIsoCountryCode(slotId);
430 ret = !operatorCountryIso.empty() && !simCountryIso.empty() && (operatorCountryIso != simCountryIso);
431 if (ret) {
432 if (simCountryIso == "us") {
433 ret = operatorCountryIso != "vi";
434 } else if (simCountryIso == "vi") {
435 ret = operatorCountryIso != "us";
436 }
437 }
438 return ret;
439 }
440
ReportCallsData(int32_t slotId,const CallInfoList & callInfoList)441 int32_t CSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
442 {
443 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
444 if (callInfoList.callSize <= 0) {
445 return ReportHangUpInfo(slotId);
446 } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
447 return ReportIncomingInfo(slotId, callInfoList);
448 } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
449 return ReportUpdateInfo(slotId, callInfoList);
450 }
451 return TELEPHONY_ERROR;
452 }
453
ReportCsCallsData(int32_t slotId,const CallInfoList & callInfoList,bool isNeedQuery)454 int32_t CSControl::ReportCsCallsData(int32_t slotId, const CallInfoList &callInfoList, bool isNeedQuery)
455 {
456 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
457 if (callInfoList.callSize <= 0) {
458 if (isNeedQuery && HasEndCallWithoutReason(callInfoList)) {
459 GetCallFailReason(slotId, connectionMap_);
460 return TELEPHONY_SUCCESS;
461 }
462 return ReportHangUpInfo(slotId);
463 } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
464 return ReportIncomingInfo(slotId, callInfoList);
465 } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
466 if (isNeedQuery && HasEndCallWithoutReason(callInfoList)) {
467 GetCallFailReason(slotId, connectionMap_);
468 return TELEPHONY_SUCCESS;
469 }
470 return ReportUpdateInfo(slotId, callInfoList);
471 }
472 return TELEPHONY_ERROR;
473 }
474
ReportUpdateInfo(int32_t slotId,const CallInfoList & callInfoList)475 int32_t CSControl::ReportUpdateInfo(int32_t slotId, const CallInfoList &callInfoList)
476 {
477 TELEPHONY_LOGD("ReportUpdateInfo entry");
478 CallsReportInfo callsReportInfo;
479 for (int32_t i = 0; i < callInfoList.callSize; ++i) {
480 CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
481 if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) {
482 TELEPHONY_LOGI("only one call, report incoming state instead of waiting state");
483 reportInfo.state = TelCallState::CALL_STATUS_INCOMING;
484 }
485 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(
486 connectionMap_, callInfoList.calls[i].index);
487 if (pConnection == nullptr) {
488 CellularCallConnectionCS connection;
489 connection.SetOrUpdateCallReportInfo(reportInfo);
490 connection.SetFlag(true);
491 connection.SetIndex(callInfoList.calls[i].index);
492 connection.SetNumber(callInfoList.calls[i].number);
493 SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
494 } else {
495 TelCallState preCallState = pConnection->GetStatus();
496 pConnection->SetFlag(true);
497 pConnection->SetIndex(callInfoList.calls[i].index);
498 pConnection->SetOrUpdateCallReportInfo(reportInfo);
499 pConnection->SetNumber(callInfoList.calls[i].number);
500 TelCallState curCallState = pConnection->GetStatus();
501 if (IsConnectedOut(preCallState, curCallState)) {
502 pConnection->UpdateCallNumber(pendingPhoneNumber_);
503 pendingPhoneNumber_.clear();
504 ExecutePostDial(slotId, pConnection->GetIndex());
505 }
506 }
507 callsReportInfo.callVec.push_back(reportInfo);
508 }
509 callsReportInfo.slotId = slotId;
510 DeleteConnection(callsReportInfo, callInfoList);
511 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
512 TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr.");
513 return TELEPHONY_ERR_LOCAL_PTR_NULL;
514 }
515 if (!isIgnoredIncomingCall_) {
516 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
517 }
518 return TELEPHONY_SUCCESS;
519 }
520
DeleteConnection(CallsReportInfo & callsReportInfo,const CallInfoList & callInfoList)521 void CSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const CallInfoList &callInfoList)
522 {
523 TELEPHONY_LOGI("DeleteConnection entry");
524 auto it = connectionMap_.begin();
525 while (it != connectionMap_.end()) {
526 CallReportInfo callReportInfo = it->second.GetCallReportInfo();
527 if (!it->second.GetFlag()) {
528 callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
529 callReportInfo.reason = static_cast<DisconnectedReason>(it->second.GetDisconnectReason());
530 callsReportInfo.callVec.push_back(callReportInfo);
531 it = connectionMap_.erase(it);
532 } else {
533 it->second.SetFlag(false);
534 ++it;
535 }
536 }
537 }
538
EncapsulationCallReportInfo(int32_t slotId,const CallInfo & callInfo)539 CallReportInfo CSControl::EncapsulationCallReportInfo(int32_t slotId, const CallInfo &callInfo)
540 {
541 CallReportInfo callReportInfo;
542 if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) {
543 TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail.");
544 return callReportInfo;
545 }
546 StandardizeUtils standardizeUtils;
547 std::string newString = standardizeUtils.FormatNumberAndToa(callInfo.number, callInfo.type);
548
549 /**
550 * <idx>: integer type;
551 * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1
552 * this number can be used in +CHLD command operations
553 * <dir>:
554 */
555 size_t cpyLen = strlen(newString.c_str()) + 1;
556 if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) {
557 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
558 return callReportInfo;
559 }
560 if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) {
561 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
562 return callReportInfo;
563 }
564
565 /**
566 * <stat> (state of the call):
567 * 0 active
568 * 1 held
569 * 2 dialing (MO call)
570 * 3 alerting (MO call)
571 * 4 incoming (MT call)
572 * 5 waiting (MT call)
573 */
574 callReportInfo.index = callInfo.index;
575 callReportInfo.accountId = slotId;
576 callReportInfo.voiceDomain = callInfo.voiceDomain;
577 callReportInfo.state = static_cast<TelCallState>(callInfo.state);
578 callReportInfo.callType = CallType::TYPE_CS;
579 callReportInfo.callMode = VideoStateType::TYPE_VOICE;
580 callReportInfo.mpty = callInfo.mpty;
581 callReportInfo.name = callInfo.number.empty() ? "" : callInfo.name;
582 callReportInfo.namePresentation = callInfo.namePresentation;
583 return callReportInfo;
584 }
585
ReportIncomingInfo(int32_t slotId,const CallInfoList & callInfoList)586 int32_t CSControl::ReportIncomingInfo(int32_t slotId, const CallInfoList &callInfoList)
587 {
588 TELEPHONY_LOGI("ReportIncomingInfo entry");
589 CallsReportInfo callsReportInfo;
590 for (int32_t i = 0; i < callInfoList.callSize; ++i) {
591 CallReportInfo cellularCallReportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
592
593 CellularCallConnectionCS connection;
594 connection.SetStatus(static_cast<TelCallState>(callInfoList.calls[i].state));
595 connection.SetIndex(callInfoList.calls[i].index);
596 connection.SetOrUpdateCallReportInfo(cellularCallReportInfo);
597 connection.SetNumber(callInfoList.calls[i].number);
598 SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
599
600 callsReportInfo.callVec.push_back(cellularCallReportInfo);
601 }
602 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
603 TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr.");
604 return TELEPHONY_ERR_ARGUMENT_INVALID;
605 }
606 callsReportInfo.slotId = slotId;
607 if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() &&
608 callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) {
609 isIgnoredIncomingCall_ = true;
610 } else {
611 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
612 }
613 return TELEPHONY_SUCCESS;
614 }
615
ReportHangUpInfo(int32_t slotId)616 int32_t CSControl::ReportHangUpInfo(int32_t slotId)
617 {
618 TELEPHONY_LOGD("ReportHangUpInfo entry");
619 CallsReportInfo callsReportInfo;
620 for (auto &it : connectionMap_) {
621 CallReportInfo callReportInfo = it.second.GetCallReportInfo();
622 callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
623 callReportInfo.accountId = slotId;
624 callReportInfo.reason = static_cast<DisconnectedReason>(it.second.GetDisconnectReason());
625 callsReportInfo.callVec.push_back(callReportInfo);
626 }
627 if (connectionMap_.empty()) {
628 TELEPHONY_LOGI("connectionMap_ is empty");
629 CallReportInfo reportInfo;
630 reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
631 reportInfo.accountId = slotId;
632 callsReportInfo.callVec.push_back(reportInfo);
633 }
634 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
635 TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr.");
636 return TELEPHONY_ERR_LOCAL_PTR_NULL;
637 }
638 callsReportInfo.slotId = slotId;
639 if (isIgnoredIncomingCall_) {
640 isIgnoredIncomingCall_ = false;
641 } else {
642 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
643 }
644 ReleaseAllConnection();
645 return TELEPHONY_SUCCESS;
646 }
647
ExecutePostDial(int32_t slotId,int64_t callId)648 int32_t CSControl::ExecutePostDial(int32_t slotId, int64_t callId)
649 {
650 TELEPHONY_LOGI("ExecutePostDial entry");
651 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
652 if (connectionMap_.empty()) {
653 TELEPHONY_LOGE("connectionMap_ is empty.");
654 return TELEPHONY_ERROR;
655 }
656 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callId);
657 if (pConnection == nullptr) {
658 return TELEPHONY_ERR_LOCAL_PTR_NULL;
659 }
660 char currentChar;
661 PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar);
662 switch (state) {
663 case PostDialCallState::POST_DIAL_CALL_STARTED:
664 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar);
665 break;
666 case PostDialCallState::POST_DIAL_CALL_DELAY:
667 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay(
668 pConnection->GetLeftPostDialCallString());
669 break;
670 default:
671 break;
672 }
673 return TELEPHONY_SUCCESS;
674 }
675
PostDialProceed(const CellularCallInfo & callInfo,const bool proceed)676 int32_t CSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)
677 {
678 TELEPHONY_LOGI("PostDialProceed entry");
679 std::string networkAddress;
680 std::string postDialString;
681 StandardizeUtils standardizeUtils;
682 standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString);
683 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
684 auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(
685 connectionMap_, callInfo.index);
686 if (pConnection == nullptr) {
687 TELEPHONY_LOGE("cs pConnection is nullptr!");
688 return TELEPHONY_ERR_LOCAL_PTR_NULL;
689 }
690 if (proceed) {
691 ExecutePostDial(callInfo.slotId, pConnection->GetIndex());
692 } else {
693 pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED);
694 }
695 return TELEPHONY_SUCCESS;
696 }
697
ReleaseAllConnection()698 void CSControl::ReleaseAllConnection()
699 {
700 TELEPHONY_LOGI("ReleaseAllConnection entry");
701 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
702 connectionMap_.clear();
703 }
704
GetConnectionMap()705 CsConnectionMap CSControl::GetConnectionMap()
706 {
707 TELEPHONY_LOGI("GetConnectionMap entry");
708 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
709 return connectionMap_;
710 }
711
ReportHangUp(const std::vector<CellularCallInfo> & infos,int32_t slotId)712 int32_t CSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)
713 {
714 CallsReportInfo callsReportInfo;
715 callsReportInfo.slotId = slotId;
716 for (const auto &info : infos) {
717 if (info.callType == CallType::TYPE_CS && info.slotId == slotId) {
718 CallReportInfo csCallReportInfo;
719 if (memset_s(csCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) {
720 TELEPHONY_LOGE("memset_s fail");
721 return TELEPHONY_ERR_MEMSET_FAIL;
722 }
723 if (memcpy_s(csCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) {
724 TELEPHONY_LOGE("memcpy_s fail");
725 return TELEPHONY_ERR_MEMCPY_FAIL;
726 }
727 csCallReportInfo.index = info.index;
728 csCallReportInfo.accountId = info.slotId;
729 csCallReportInfo.callType = CallType::TYPE_CS;
730 csCallReportInfo.callMode = VideoStateType::TYPE_VOICE;
731 csCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
732 callsReportInfo.callVec.push_back(csCallReportInfo);
733 }
734 }
735 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
736 TELEPHONY_LOGE("CellularCallRegister instance is nullptr");
737 return TELEPHONY_ERR_LOCAL_PTR_NULL;
738 }
739 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
740 ReleaseAllConnection();
741 return TELEPHONY_SUCCESS;
742 }
743
UpdateDisconnectedReason(const CallInfoList & callInfoList,RilDisconnectedReason reason)744 void CSControl::UpdateDisconnectedReason(const CallInfoList &callInfoList, RilDisconnectedReason reason)
745 {
746 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
747 for (auto &connection : connectionMap_) {
748 bool isFind = false;
749 if (connection.second.GetDisconnectReason() != RilDisconnectedReason::DISCONNECTED_REASON_INVALID) {
750 continue;
751 }
752 for (auto &call : callInfoList.calls) {
753 if (connection.second.GetIndex() == call.index) {
754 isFind = true;
755 break;
756 }
757 }
758 if (!isFind) {
759 connection.second.SetDisconnectReason(reason);
760 }
761 }
762 }
763
HasEndCallWithoutReason(const CallInfoList & callInfoList)764 bool CSControl::HasEndCallWithoutReason(const CallInfoList &callInfoList)
765 {
766 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
767 for (auto &connection : connectionMap_) {
768 bool isFind = false;
769 if (connection.second.GetDisconnectReason() != RilDisconnectedReason::DISCONNECTED_REASON_INVALID) {
770 continue; // This call already has a disconnect reason.
771 }
772 for (auto &call : callInfoList.calls) {
773 if (connection.second.GetIndex() == call.index) {
774 isFind = true;
775 break;
776 }
777 }
778 if (!isFind) {
779 return true; // There are still calls need query disconnect reason.
780 }
781 }
782 return false; // All calls have disconnected reason, no need to query disconnect reason.
783 }
784
UpdateCallDisconnectReason(int32_t callId,RilDisconnectedReason reason)785 void CSControl::UpdateCallDisconnectReason(int32_t callId, RilDisconnectedReason reason)
786 {
787 std::lock_guard<ffrt::recursive_mutex> lock(connectionMapMutex_);
788 for (auto &connection : connectionMap_) {
789 if (connection.second.GetIndex() == callId) {
790 connection.second.SetDisconnectReason(reason);
791 return; // call id not duplicated.
792 }
793 }
794 }
795 } // namespace Telephony
796 } // namespace OHOS
797