• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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