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 "control_base.h"
17 
18 #include "cellular_call_config.h"
19 #include "cellular_call_hisysevent.h"
20 #include "cellular_call_service.h"
21 #include "core_service_client.h"
22 #include "module_service_utils.h"
23 #include "standardize_utils.h"
24 
25 namespace OHOS {
26 namespace Telephony {
27 const uint32_t WAIT_TIME_SECOND = 5;
28 
DialPreJudgment(const CellularCallInfo & callInfo,bool isEcc)29 int32_t ControlBase::DialPreJudgment(const CellularCallInfo &callInfo, bool isEcc)
30 {
31     HandleEcc(callInfo, isEcc, CheckAirplaneModeScene(callInfo), CheckActivateSimScene(callInfo.slotId));
32     std::string dialString(callInfo.phoneNum);
33     if (dialString.empty()) {
34         TELEPHONY_LOGE("DialPreJudgment return, dialString is empty.");
35         CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.accountId, static_cast<int32_t>(callInfo.callType),
36             callInfo.videoState, CALL_ERR_PHONE_NUMBER_EMPTY, "dialString is empty");
37         return CALL_ERR_PHONE_NUMBER_EMPTY;
38     }
39 
40     ModuleServiceUtils moduleServiceUtils;
41     if (!moduleServiceUtils.GetRadioState(callInfo.slotId)) {
42         TELEPHONY_LOGE("DialPreJudgment return, radio state error.");
43         CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.accountId, static_cast<int32_t>(callInfo.callType),
44             callInfo.videoState, CALL_ERR_GET_RADIO_STATE_FAILED, "radio state error");
45         return CALL_ERR_GET_RADIO_STATE_FAILED;
46     }
47     return TELEPHONY_SUCCESS;
48 }
49 
IsNeedExecuteMMI(int32_t slotId,std::string & phoneString,CLIRMode & clirMode,bool isNeedUseIms)50 bool ControlBase::IsNeedExecuteMMI(int32_t slotId, std::string &phoneString, CLIRMode &clirMode, bool isNeedUseIms)
51 {
52     TELEPHONY_LOGI("IsNeedExecuteMMI start");
53     // Also supplementary services may be controlled using dial command according to 3GPP TS 22.030 [19].
54     // An example of call forwarding on no reply for telephony with the adjustment of the
55     // no reply condition timer on 25 seconds:
56     // Parse the MMI code from the string
57     std::unique_ptr<MMICodeUtils> mmiCodeUtils = std::make_unique<MMICodeUtils>();
58     // Parse the MMI code from the string
59     if (mmiCodeUtils == nullptr) {
60         TELEPHONY_LOGE("IsNeedExecuteMMI return, mmiCodeUtils is nullptr");
61         return false;
62     }
63     if (!mmiCodeUtils->IsNeedExecuteMmi(phoneString, isNeedUseIms)) {
64         TELEPHONY_LOGI("IsNeedExecuteMMI return, isn't need to execute mmi");
65         return false;
66     }
67     if (mmiCodeUtils->GetMMIData().serviceCode == "30" && !mmiCodeUtils->GetMMIData().dialString.empty()) {
68         TELEPHONY_LOGI("IsNeedExecuteMMI, handle additional CLIR mode");
69         if (mmiCodeUtils->GetMMIData().actionString == "*") {
70             phoneString = mmiCodeUtils->GetMMIData().dialString;
71             clirMode = CLIRMode::TRANSFER;
72             return false;
73         } else if (mmiCodeUtils->GetMMIData().actionString == "#") {
74             phoneString = mmiCodeUtils->GetMMIData().dialString;
75             clirMode = CLIRMode::INHIBITION;
76             return false;
77         }
78     }
79     if (DelayedSingleton<CellularCallService>::GetInstance() == nullptr) {
80         TELEPHONY_LOGI("IsNeedExecuteMMI return, GetInstance is nullptr");
81         return false;
82     }
83     if (DelayedSingleton<CellularCallService>::GetInstance()->GetHandler(slotId) == nullptr) {
84         TELEPHONY_LOGI("IsNeedExecuteMMI return, GetHandler is nullptr");
85         return false;
86     }
87     return DelayedSingleton<CellularCallService>::GetInstance()->GetHandler(slotId)->SendEvent(
88         MMIHandlerId::EVENT_MMI_Id, mmiCodeUtils);
89 }
90 
IsDtmfKey(char c) const91 bool ControlBase::IsDtmfKey(char c) const
92 {
93     /**
94      * 1. <DTMF>. A single ASCII character in the set 0 9, #,*,A D. This is interpreted as a single ASCII character
95      * whose duration is set by the +VTD command. NOTE 2:	In GSM this operates only in voice mode.
96      */
97     return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'D') || c == '*' || c == '#';
98 }
99 
IsConnectedOut(TelCallState preState,TelCallState curState)100 bool ControlBase::IsConnectedOut(TelCallState preState, TelCallState curState)
101 {
102     if ((preState == TelCallState::CALL_STATUS_DIALING || preState == TelCallState::CALL_STATUS_ALERTING) &&
103         !(curState == TelCallState::CALL_STATUS_DIALING || curState == TelCallState::CALL_STATUS_ALERTING)) {
104         return true;
105     }
106     return false;
107 }
108 
CheckAirplaneModeScene(const CellularCallInfo & callInfo)109 bool ControlBase::CheckAirplaneModeScene(const CellularCallInfo &callInfo)
110 {
111     bool isAirplaneModeOn = false;
112     ModuleServiceUtils moduleServiceUtils;
113     return moduleServiceUtils.GetAirplaneMode(isAirplaneModeOn) == TELEPHONY_SUCCESS && isAirplaneModeOn;
114 }
115 
CheckActivateSimScene(int32_t slotId)116 bool ControlBase::CheckActivateSimScene(int32_t slotId)
117 {
118     bool hasSimCard = false;
119     DelayedRefSingleton<CoreServiceClient>::GetInstance().HasSimCard(slotId, hasSimCard);
120     bool isActivateSim = true;
121     if (hasSimCard) {
122         isActivateSim = DelayedRefSingleton<CoreServiceClient>::GetInstance().IsSimActive(slotId);
123     }
124     return isActivateSim;
125 }
126 
HandleEcc(const CellularCallInfo & callInfo,bool isEcc,bool isAirplaneModeOn,bool isActivateSim)127 int32_t ControlBase::HandleEcc(const CellularCallInfo &callInfo, bool isEcc, bool isAirplaneModeOn, bool isActivateSim)
128 {
129     if (!isEcc) {
130         TELEPHONY_LOGE("HandleEcc airplane mode is not ecc");
131         return TELEPHONY_ERR_AIRPLANE_MODE_ON;
132     }
133 
134     if (isAirplaneModeOn) {
135         ModuleServiceUtils moduleServiceUtils;
136         int32_t ret = moduleServiceUtils.UpdateRadioOn(callInfo.slotId);
137         if (ret != TELEPHONY_SUCCESS) {
138             TELEPHONY_LOGE("UpdateRadioOn fail");
139             return ret;
140         }
141     }
142     if (!isActivateSim) {
143         int32_t ret = DelayedRefSingleton<CoreServiceClient>::GetInstance().SetActiveSim(callInfo.slotId, true);
144         if (ret != TELEPHONY_SUCCESS) {
145             TELEPHONY_LOGE("UpdateSimState fail");
146             return ret;
147         }
148         int32_t otherSlotId = callInfo.slotId == SLOT_0 ? SLOT_1 : SLOT_0;
149         if (!CheckActivateSimScene(otherSlotId)) {
150             ret = DelayedRefSingleton<CoreServiceClient>::GetInstance().SetActiveSim(otherSlotId, true);
151             if (ret != TELEPHONY_SUCCESS) {
152                 TELEPHONY_LOGE("UpdateSecondSimCardState fail");
153                 return ret;
154             }
155         }
156     }
157     std::unique_lock<std::mutex> lock(mutex_);
158     CellularCallConfig cellularCallConfig;
159     while (!cellularCallConfig.IsReadyToCall(callInfo.slotId)) {
160         if (cv_.wait_for(lock, std::chrono::seconds(WAIT_TIME_SECOND)) == std::cv_status::timeout) {
161             TELEPHONY_LOGE("HandleEcc network in service timeout");
162             return CALL_ERR_DIAL_FAILED;
163         }
164     }
165 
166     return TELEPHONY_SUCCESS;
167 }
168 
SetReadyToCall(int32_t slotId,bool isReadyToCall)169 int32_t ControlBase::SetReadyToCall(int32_t slotId, bool isReadyToCall)
170 {
171     std::unique_lock<std::mutex> lock(mutex_);
172     CellularCallConfig cellularCallConfig;
173     if (!cellularCallConfig.IsReadyToCall(slotId) && isReadyToCall) {
174         cellularCallConfig.SetReadyToCall(slotId, isReadyToCall);
175         cv_.notify_all();
176     }
177     return TELEPHONY_SUCCESS;
178 }
179 } // namespace Telephony
180 } // namespace OHOS
181