1 /*
2 * Copyright (C) 2021 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 "napi_state_registry.h"
17 #include <map>
18 #include <utility>
19 #include "event_listener_manager.h"
20 #include "napi_parameter_util.h"
21 #include "napi_telephony_observer.h"
22 #include "napi_util.h"
23 #include "telephony_errors.h"
24 #include "telephony_log_wrapper.h"
25 #include "telephony_state_manager.h"
26
27 namespace OHOS {
28 namespace Telephony {
29 namespace {
30 constexpr int32_t ARRAY_SIZE = 64;
31 const std::map<std::string_view, TelephonyUpdateEventType> eventMap {
32 {"networkStateChange", TelephonyUpdateEventType::EVENT_NETWORK_STATE_UPDATE},
33 {"callStateChange", TelephonyUpdateEventType::EVENT_CALL_STATE_UPDATE},
34 {"signalInfoChange", TelephonyUpdateEventType::EVENT_SIGNAL_STRENGTHS_UPDATE},
35 {"simStateChange", TelephonyUpdateEventType::EVENT_SIM_STATE_UPDATE},
36 {"cellInfoChange", TelephonyUpdateEventType::EVENT_CELL_INFO_UPDATE},
37 {"cellularDataConnectionStateChange", TelephonyUpdateEventType::EVENT_DATA_CONNECTION_UPDATE},
38 {"cellularDataFlowChange", TelephonyUpdateEventType::EVENT_CELLULAR_DATA_FLOW_UPDATE},
39 };
40
GetEventType(std::string_view event)41 TelephonyUpdateEventType GetEventType(std::string_view event)
42 {
43 auto serched = eventMap.find(event);
44 return (serched != eventMap.end() ? serched->second : TelephonyUpdateEventType::NONE_EVENT_TYPE);
45 }
46 } // namespace
47
NativeOn(napi_env env,void * data)48 static void NativeOn(napi_env env, void *data)
49 {
50 if (data == nullptr) {
51 TELEPHONY_LOGE("NativeOn data is nullptr");
52 return;
53 }
54 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
55 TELEPHONY_LOGI("NativeOn eventType = %{public}d", asyncContext->eventType);
56 EventListener listener {
57 env,
58 asyncContext->eventType,
59 asyncContext->slotId,
60 asyncContext->callbackRef,
61 };
62 std::optional<int32_t> result = EventListenerManager::RegisterEventListener(listener);
63 asyncContext->resolved = !result.has_value();
64 asyncContext->errorCode = result.value_or(ERROR_NONE);
65 }
66
OnCallback(napi_env env,napi_status status,void * data)67 static void OnCallback(napi_env env, napi_status status, void *data)
68 {
69 if (data == nullptr) {
70 TELEPHONY_LOGE("OnCallback data is nullptr");
71 return;
72 }
73 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
74 if (!asyncContext->resolved) {
75 TELEPHONY_LOGE("OnCallback error by add observer failed");
76 }
77 napi_delete_async_work(env, asyncContext->work);
78 delete asyncContext;
79 }
80
On(napi_env env,napi_callback_info info)81 static napi_value On(napi_env env, napi_callback_info info)
82 {
83 size_t parameterCount = 3;
84 napi_value parameters[] = {nullptr, nullptr, nullptr};
85 napi_get_cb_info(env, info, ¶meterCount, parameters, nullptr, nullptr);
86
87 std::unique_ptr<ObserverContext> asyncContext = std::make_unique<ObserverContext>();
88 if (asyncContext == nullptr) {
89 napi_throw_error(env, nullptr, "ObserverContext is nullptr!");
90 return nullptr;
91 }
92 std::array<char, ARRAY_SIZE> eventType {};
93 napi_value object = NapiUtil::CreateUndefined(env);
94 std::optional<NapiError> errCode;
95 if (parameterCount == std::size(parameters)) {
96 auto paraTuple = std::make_tuple(std::data(eventType), &object, &asyncContext->callbackRef);
97 errCode = MatchParameters(env, parameters, parameterCount, paraTuple);
98 if (!errCode.has_value()) {
99 napi_value slotId = NapiUtil::GetNamedProperty(env, object, "slotId");
100 if (slotId) {
101 NapiValueToCppValue(env, slotId, napi_number, &asyncContext->slotId);
102 TELEPHONY_LOGI("sate registry on slotId = %{public}d", asyncContext->slotId);
103 }
104 }
105 } else {
106 auto paraTuple = std::make_tuple(std::data(eventType), &asyncContext->callbackRef);
107 errCode = MatchParameters(env, parameters, parameterCount, paraTuple);
108 }
109
110 if (errCode.has_value()) {
111 const std::string errMsg = "type of input parameters error : " + std::to_string(errCode.value());
112 napi_throw_error(env, nullptr, errMsg.c_str());
113 return nullptr;
114 }
115
116 asyncContext->eventType = GetEventType(eventType.data());
117 if (asyncContext->eventType != TelephonyUpdateEventType::NONE_EVENT_TYPE) {
118 return NapiUtil::HandleAsyncWork(env, asyncContext.release(), "On", NativeOn, OnCallback);
119 } else {
120 napi_throw_error(env, "1", "first parameter \"type\" mismatch with the observer.d.ts");
121 }
122 return NapiUtil::CreateUndefined(env);
123 }
124
NativeOff(napi_env env,void * data)125 static void NativeOff(napi_env env, void *data)
126 {
127 if (data == nullptr) {
128 TELEPHONY_LOGE("NativeOff data is nullptr");
129 return;
130 }
131 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
132 std::optional<int32_t> result =
133 EventListenerManager::UnregisterEventListener(asyncContext->slotId, asyncContext->eventType);
134 asyncContext->resolved = !result.has_value();
135 asyncContext->errorCode = result.value_or(ERROR_NONE);
136 }
137
OffCallback(napi_env env,napi_status status,void * data)138 static void OffCallback(napi_env env, napi_status status, void *data)
139 {
140 if (data == nullptr) {
141 TELEPHONY_LOGE("OffCallback data is nullptr");
142 return;
143 }
144 ObserverContext *asyncContext = static_cast<ObserverContext *>(data);
145 EventListenerManager::RemoveListener(asyncContext->eventType);
146 if (!asyncContext->resolved) {
147 TELEPHONY_LOGE("OffCallback error by remove observer failed");
148 }
149 napi_delete_async_work(env, asyncContext->work);
150 delete asyncContext;
151 }
152
Off(napi_env env,napi_callback_info info)153 static napi_value Off(napi_env env, napi_callback_info info)
154 {
155 size_t parameterCount = 2;
156 napi_value parameters[] = {nullptr, nullptr};
157 napi_get_cb_info(env, info, ¶meterCount, parameters, nullptr, nullptr);
158
159 std::array<char, ARRAY_SIZE> eventType {};
160 std::unique_ptr<ObserverContext> asyncContext = std::make_unique<ObserverContext>();
161 if (asyncContext == nullptr) {
162 napi_throw_error(env, nullptr, "ObserverContext is nullptr!");
163 return nullptr;
164 }
165 auto paraTuple = std::make_tuple(std::data(eventType), &asyncContext->callbackRef);
166 std::optional<NapiError> errCode = MatchParameters(env, parameters, parameterCount, paraTuple);
167 if (errCode.has_value()) {
168 const std::string errMsg = "type of input parameters error : " + std::to_string(errCode.value());
169 napi_throw_error(env, nullptr, errMsg.c_str());
170 return nullptr;
171 }
172
173 asyncContext->eventType = GetEventType(eventType.data());
174 if (asyncContext->eventType != TelephonyUpdateEventType::NONE_EVENT_TYPE) {
175 return NapiUtil::HandleAsyncWork(env, asyncContext.release(), "Off", NativeOff, OffCallback);
176 } else {
177 napi_throw_error(env, "1", "first parameter \"type\" mismatch with the @ohos.telephony.observer.d.ts");
178 return NapiUtil::CreateUndefined(env);
179 }
180 }
181
182 EXTERN_C_START
InitNapiStateRegistry(napi_env env,napi_value exports)183 napi_value InitNapiStateRegistry(napi_env env, napi_value exports)
184 {
185 napi_property_descriptor desc[] = {
186 DECLARE_NAPI_FUNCTION("on", On),
187 DECLARE_NAPI_FUNCTION("off", Off),
188 };
189 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
190 return exports;
191 }
192 EXTERN_C_END
193
194 static napi_module _stateRegistryModule = {
195 .nm_version = 1,
196 .nm_flags = 0,
197 .nm_filename = nullptr,
198 .nm_register_func = InitNapiStateRegistry,
199 .nm_modname = "telephony.observer",
200 .nm_priv = ((void *)0),
201 .reserved = {(void *)0},
202 };
203
RegisterTelephonyObserverModule(void)204 extern "C" __attribute__((constructor)) void RegisterTelephonyObserverModule(void)
205 {
206 napi_module_register(&_stateRegistryModule);
207 }
208 } // namespace Telephony
209 } // namespace OHOS
210