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
25namespace OHOS {
26namespace Telephony {
27const uint32_t WAIT_TIME_SECOND = 5;
28
29int32_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
50bool 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
91bool 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
100bool 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
109bool ControlBase::CheckAirplaneModeScene(const CellularCallInfo &callInfo)
110{
111    bool isAirplaneModeOn = false;
112    ModuleServiceUtils moduleServiceUtils;
113    return moduleServiceUtils.GetAirplaneMode(isAirplaneModeOn) == TELEPHONY_SUCCESS && isAirplaneModeOn;
114}
115
116bool 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
127int32_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
169int32_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