1 /*
2 * Copyright (c) 2023 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 "calendar_manager_napi.h"
17 #include <optional>
18
19 using namespace OHOS::AppExecFwk;
20 using namespace OHOS::DataShare;
21 static const int INVALID_EVENT_ID = -1;
22 static const int ARGS_INDEX_ONE = 1;
23 static const int ARGS_INDEX_TWO = 2;
24 static const int ARGS_INDEX_THREE = 3;
25
26 namespace {
27 const std::string CALENDAR_MANAGER_CLASS_NAME = "CalendarManager";
28 static thread_local napi_ref g_constructorRef = nullptr;
29 constexpr uint32_t INITIAL_REFCOUNT = 1;
30 }
31 namespace OHOS::CalendarApi {
CreateCalendar(napi_env env,napi_callback_info info)32 napi_value CalendarManagerNapi::CreateCalendar(napi_env env, napi_callback_info info)
33 {
34 LOG_INFO("napi CreateCalendar called");
35 struct CreateCalendarContext : public ContextBase {
36 CalendarAccount account;
37 CalendarNapi *calendar;
38 int id;
39 napi_ref ref = nullptr;
40 };
41 auto ctxt = std::make_shared<CreateCalendarContext>();
42 auto input = [env, ctxt](size_t argc, napi_value* argv) {
43 // required 1 arguments :: <CalendarAccount>
44 CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
45 NapiUtil::GetValue(env, argv[0], ctxt->account);
46 CHECK_STATUS_RETURN_VOID(ctxt, "invalid arg[0], i.e. invalid keys!");
47 ctxt->ref = NapiUtil::NewWithRef(env, argc, argv, reinterpret_cast<void**>(&ctxt->calendar),
48 CalendarNapi::Constructor(env));
49 };
50 ctxt->GetCbInfo(env, info, input);
51
52 auto execute = [ctxt]() {
53 auto nativteCalendar = Native::CalendarManager::GetInstance().CreateCalendar(ctxt->account);
54 ctxt->status = (nativteCalendar != nullptr) ? napi_ok : napi_generic_failure;
55 CHECK_STATUS_RETURN_VOID(ctxt, "CreateCalendar failed!");
56 ctxt->calendar->SetNative(nativteCalendar);
57 ctxt->id = nativteCalendar->GetId();
58 };
59 auto output = [env, ctxt](napi_value& result) {
60 ctxt->status = napi_get_reference_value(env, ctxt->ref, &result);
61 CHECK_STATUS_RETURN_VOID(ctxt, "CreateCalendar output get ref value failed");
62 ctxt->status = NapiUtil::SetNamedProperty(env, "id", ctxt->id, result);
63 CHECK_STATUS_RETURN_VOID(ctxt, "CreateCalendar SetNamedProperty id failed");
64 ctxt->status = napi_delete_reference(env, ctxt->ref);
65 CHECK_STATUS_RETURN_VOID(ctxt, "CreateCalendar output del ref failed");
66 };
67 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
68 }
69
DeleteCalendar(napi_env env,napi_callback_info info)70 napi_value CalendarManagerNapi::DeleteCalendar(napi_env env, napi_callback_info info)
71 {
72 LOG_INFO("napi DeleteCalendar called");
73 struct DelCalendarContext : public ContextBase {
74 CalendarAccount account;
75 CalendarNapi *calendar;
76 bool delResult = false;
77 };
78 auto ctxt = std::make_shared<DelCalendarContext>();
79 auto input = [env, ctxt](size_t argc, napi_value* argv) {
80 // required 1 arguments :: <Calendar>
81 CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
82 napi_valuetype type = napi_undefined;
83 napi_typeof(env, argv[0], &type);
84 CHECK_ARGS_RETURN_VOID(ctxt, type == napi_object, "type error!");
85 ctxt->status = CalendarNapi::ToJson(env, argv[0], ctxt->calendar);
86 CHECK_STATUS_RETURN_VOID(ctxt, "invalid arg[0], i.e. invalid keys!");
87 };
88 ctxt->GetCbInfo(env, info, input);
89
90 auto execute = [ctxt]() {
91 CHECK_RETURN_VOID(ctxt->calendar, "calendar is nullptr");
92 auto nativeCalendar = ctxt->calendar->GetNative();
93 CHECK_RETURN_VOID(nativeCalendar, "calendar is nullptr");
94 ctxt->delResult = Native::CalendarManager::GetInstance()
95 .DeleteCalendar(*(nativeCalendar.get()));
96 CHECK_RETURN_VOID(ctxt->delResult, "DeleteCalendar failed!");
97 };
98 auto output = [env, ctxt](napi_value& result) {
99 NapiUtil::SetValue(env, ctxt->delResult, result);
100 CHECK_STATUS_RETURN_VOID(ctxt, "output del ref failed");
101 };
102 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
103 }
104
105 struct GetCalendarContext : public ContextBase {
106 std::optional<CalendarAccount> account;
107 CalendarNapi *calendar = nullptr;
108 napi_ref ref = nullptr;
109 int id = -1;
110
GetCbInfoOHOS::CalendarApi::GetCalendarContext111 void GetCbInfo(napi_env env, napi_callback_info info)
112 {
113 auto input = [env, this](size_t argc, napi_value* argv) {
114 // required at least 1 arguments :: <CalendarAccount>
115 CHECK_ARGS_RETURN_VOID(this, argc <= 1, "invalid arguments!");
116 if (argc == 0) {
117 this->account = std::nullopt;
118 } else {
119 CalendarAccount tmpAccount;
120 NapiUtil::GetValue(env, argv[0], tmpAccount);
121 this->account = tmpAccount;
122 }
123 CHECK_STATUS_RETURN_VOID(this, "invalid arg[0], i.e. invalid keys!");
124 ref = NapiUtil::NewWithRef(env, argc, argv, reinterpret_cast<void**>(&calendar),
125 CalendarNapi::Constructor(env));
126 };
127 LOG_DEBUG("call ContextBase::GetCbInfo");
128 ContextBase::GetCbInfo(env, info, input);
129 }
130 };
131
GetCalendar(napi_env env,napi_callback_info info)132 napi_value CalendarManagerNapi::GetCalendar(napi_env env, napi_callback_info info)
133 {
134 LOG_DEBUG("GetCalendar in");
135 auto ctxt = std::make_shared<GetCalendarContext>();
136 ctxt->GetCbInfo(env, info);
137
138 auto execute = [ctxt]() {
139 auto nativteCalendar = Native::CalendarManager::GetInstance().GetCalendar(ctxt->account);
140 ctxt->status = (nativteCalendar != nullptr) ? napi_ok : napi_generic_failure;
141 CHECK_STATUS_RETURN_VOID(ctxt, "GetCalendar error!");
142 if (nativteCalendar->GetId() == -1) {
143 ctxt->status = napi_generic_failure;
144 CHECK_STATUS_RETURN_VOID(ctxt, "GetCalendar failed!");
145 }
146 ctxt->calendar->SetNative(nativteCalendar);
147 ctxt->id = nativteCalendar->GetId();
148 };
149 auto output = [env, ctxt](napi_value& result) {
150 ctxt->status = napi_get_reference_value(env, ctxt->ref, &result);
151 CHECK_STATUS_RETURN_VOID(ctxt, "GetCalendar output get ref value failed");
152 ctxt->status = NapiUtil::SetNamedProperty(env, "id", ctxt->id, result);
153 CHECK_STATUS_RETURN_VOID(ctxt, "GetCalendar SetNamedProperty id failed");
154 ctxt->status = napi_delete_reference(env, ctxt->ref);
155 CHECK_STATUS_RETURN_VOID(ctxt, "GetCalendar output del ref failed");
156 };
157 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
158 }
159
GetAllCalendars(napi_env env,napi_callback_info info)160 napi_value CalendarManagerNapi::GetAllCalendars(napi_env env, napi_callback_info info)
161 {
162 LOG_DEBUG("napi GetAllCalendars called");
163 struct GetAllCalendarContext : public ContextBase {
164 napi_callback_info info;
165 std::vector<napi_ref> refs;
166 };
167
168 auto ctxt = std::make_shared<GetAllCalendarContext>();
169 auto input = [env, ctxt](size_t argc, napi_value* argv) {
170 CHECK_ARGS_RETURN_VOID(ctxt, argc == 0, "invalid arguments!");
171 auto nativteCalendars = Native::CalendarManager::GetInstance().GetAllCalendars();
172 for (auto &calendar : nativteCalendars) {
173 CalendarNapi *calendarNapi = nullptr;
174 auto ref = NapiUtil::NewWithRef(env, argc, argv, reinterpret_cast<void**>(&calendarNapi),
175 CalendarNapi::Constructor(env));
176 CHECK_RETURN_VOID(calendarNapi != nullptr, "new CalendarNapi failed!");
177 calendarNapi->SetNative(calendar);
178 napi_value value;
179 ctxt->status = napi_get_reference_value(env, ref, &value);
180 CHECK_STATUS_RETURN_VOID(ctxt, "napi_get_reference_value failed");
181 ctxt->status = NapiUtil::SetNamedProperty(env, "id", calendar->GetId(), value);
182 CHECK_STATUS_RETURN_VOID(ctxt, "SetNamedProperty id failed");
183 ctxt->refs.emplace_back(ref);
184 }
185 };
186 ctxt->GetCbInfo(env, info, input);
187
188 auto execute = [env, ctxt]()->void {
189 };
190
191 auto output = [env, ctxt](napi_value& result) {
192 ctxt->status = napi_create_array_with_length(env, ctxt->refs.size(), &result);
193 CHECK_STATUS_RETURN_VOID(ctxt, "create array failed!");
194 int index = 0;
195 for (auto& ref : ctxt->refs) {
196 napi_value value;
197 ctxt->status = napi_get_reference_value(env, ref, &value);
198 CHECK_STATUS_RETURN_VOID(ctxt, "get ref value failed!");
199 ctxt->status = napi_set_element(env, result, index++, value);
200 CHECK_STATUS_RETURN_VOID(ctxt, "napi_set_element failed!");
201 ctxt->status = napi_delete_reference(env, ref);
202 CHECK_STATUS_RETURN_VOID(ctxt, "napi_delete_reference failed!");
203 }
204 };
205 return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
206 }
207
GetCalendarManager(napi_env env,napi_callback_info info)208 napi_value GetCalendarManager(napi_env env, napi_callback_info info)
209 {
210 LOG_INFO("napi GetCalendarManager called");
211 const int argsOne = 1;
212 napi_value result = nullptr;
213 napi_value cons = nullptr;
214 size_t requireArgc = argsOne;
215 size_t argc = argsOne;
216 napi_value args[argsOne] = {nullptr};
217 if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) {
218 return nullptr;
219 }
220
221 if (argc > requireArgc || napi_get_reference_value(env, g_constructorRef, &cons) != napi_ok) {
222 return nullptr;
223 }
224
225 if (napi_new_instance(env, cons, argsOne, args, &result) != napi_ok) {
226 return nullptr;
227 }
228 CalendarManagerNapi *calendarManager = nullptr;
229 if (napi_unwrap(env, result, (void **)&calendarManager) != napi_ok) {
230 LOG_ERROR("Faild to get fileAccessHelper");
231 return nullptr;
232 }
233
234 if (calendarManager == nullptr) {
235 LOG_ERROR("fileAccessHelper is nullptr");
236 return nullptr;
237 }
238 return result;
239 }
240
EditEvent(napi_env env,napi_callback_info info)241 napi_value CalendarManagerNapi::EditEvent(napi_env env, napi_callback_info info)
242 {
243 LOG_INFO("editEvent called");
244 napi_value eventId = nullptr;
245 NapiUtil::SetValue(env, INVALID_EVENT_ID, eventId);
246 auto ctxt = std::make_shared<EditEventContext>();
247 auto input = [env, ctxt](size_t argc, napi_value* argv) {
248 CHECK_ARGS_RETURN_VOID(ctxt, argc == ARGS_INDEX_THREE, "invalid arguments!");
249 ctxt-> _jsContext = argv[0];
250 NapiUtil::GetValue(env, argv[ARGS_INDEX_ONE], ctxt->event);
251 NapiUtil::GetValue(env, argv[ARGS_INDEX_TWO], ctxt->caller);
252 };
253 ctxt->GetCbInfo(env, info, input, true);
254
255 bool isStageMode = false;
256 auto jsContext = ctxt->_jsContext;
257 auto status = OHOS::AbilityRuntime::IsStageContext(env, jsContext, isStageMode);
258 if (status != napi_ok || !isStageMode) {
259 LOG_ERROR("editEvent No support FA Model");
260 return eventId;
261 }
262 auto stageContext = OHOS::AbilityRuntime::GetStageModeContext(env, jsContext);
263 if (stageContext == nullptr) {
264 LOG_ERROR("editEvent stageContext == nullptr.");
265 return eventId;
266 }
267 auto abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(stageContext);
268 if (abilityContext == nullptr) {
269 LOG_ERROR("editEvent only support for UIAbility Context.");
270 return eventId;
271 }
272 ctxt->_uiContent = abilityContext->GetUIContent();
273 return LaunchEditorPage(env, ctxt);
274 }
275
LaunchEditorPage(napi_env env,std::shared_ptr<EditEventContext> ctxt)276 napi_value CalendarManagerNapi::LaunchEditorPage(napi_env env, std::shared_ptr<EditEventContext> ctxt)
277 {
278 napi_value promise = nullptr;
279 napi_deferred deferred = nullptr;
280 napi_create_promise(env, &deferred, &promise);
281 AAFwk::Want want;
282 want.SetElementName("com.ohos.calendardata", "EditorUIExtensionAbility");
283 const std::string uiExtType = "sys/commonUI";
284 want.SetParam("ability.want.params.uiExtensionType", uiExtType);
285 want.SetParam("event", ctxt->event);
286 want.SetParam("caller", ctxt->caller);
287 Ace::ModalUIExtensionCallbacks callbacks;
288 callbacks = {
289 .onRelease = [env, ctxt, deferred](int32_t code) {
290 LOG_INFO("editEvent onRelease callback.");
291 ctxt->_uiContent->CloseModalUIExtension(ctxt->_sessionId);
292 napi_resolve_deferred(env, deferred, ctxt->id);
293 LOG_INFO("editEvent onRelease done.");
294 },
295 .onResult = [env, ctxt, deferred](int32_t code, const AAFwk::Want &wantRes) {
296 auto eventId = wantRes.GetIntParam("eventId", INVALID_EVENT_ID);
297 LOG_INFO("editEvent onResult. eventId=%{public}d", eventId);
298 NapiUtil::SetValue(env, eventId, ctxt->id);
299 },
300 .onReceive = [env, ctxt](const AAFwk::WantParams &wantParams) {
301 LOG_INFO("editEvent onReceive.");
302 },
303 .onError = [env, ctxt, deferred](int32_t code, const std::string &event, const std::string &msg) {
304 LOG_ERROR("editEvent onError.%{public}s", msg.c_str());
305 ctxt->_uiContent->CloseModalUIExtension(ctxt->_sessionId);
306 napi_reject_deferred(env, deferred, ctxt->id);
307 },
308 .onRemoteReady = [env, ctxt, deferred](const std::shared_ptr<Ace::ModalUIExtensionProxy> &proxy) {
309 LOG_INFO("editEvent onRemoteReady.");
310 },
311 .onDestroy = [env, ctxt, deferred]{
312 LOG_INFO("editEvent onDestroy.");
313 },
314 };
315 Ace::ModalUIExtensionConfig config;
316 config = {
317 .isProhibitBack = false,
318 };
319 ctxt->_sessionId = ctxt->_uiContent->CreateModalUIExtension(want, callbacks, config);
320 LOG_INFO("editEvent CreateModalUI sessionId=%{public}d", ctxt->_sessionId);
321 return promise;
322 }
323
New(napi_env env,napi_callback_info info)324 napi_value CalendarManagerNapi::New(napi_env env, napi_callback_info info)
325 {
326 auto ctxt = std::make_shared<ContextBase>();
327 auto input = [env, ctxt](size_t argc, napi_value* argv) {
328 CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
329 CalendarEnvNapi::GetInstance().Init(env, argv[0]);
330 };
331 ctxt->GetCbInfoSync(env, info, input);
332 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
333
334 auto calendarManager = new (std::nothrow) CalendarManagerNapi();
335 NAPI_ASSERT(env, calendarManager != nullptr, "no memory for calendarManager");
336 auto finalize = [](napi_env env, void *data, void *hint) {
337 CalendarManagerNapi *objectInfo = static_cast<CalendarManagerNapi *>(data);
338 if (objectInfo != nullptr) {
339 delete objectInfo;
340 objectInfo = nullptr;
341 }
342 };
343 if (napi_wrap(env, ctxt->self, calendarManager, finalize, nullptr, nullptr) != napi_ok) {
344 finalize(env, calendarManager, nullptr);
345 return nullptr;
346 }
347 return ctxt->self;
348 }
349
Init(napi_env env,napi_value exports)350 napi_value CalendarManagerNapi::Init(napi_env env, napi_value exports)
351 {
352 napi_property_descriptor properties[] = {
353 DECLARE_NAPI_FUNCTION("createCalendar", CreateCalendar),
354 DECLARE_NAPI_FUNCTION("deleteCalendar", DeleteCalendar),
355 DECLARE_NAPI_FUNCTION("getCalendar", GetCalendar),
356 DECLARE_NAPI_FUNCTION("getAllCalendars", GetAllCalendars),
357 DECLARE_NAPI_FUNCTION("editEvent", EditEvent),
358 };
359 napi_value cons = nullptr;
360 NAPI_CALL(env,
361 napi_define_class(env,
362 CALENDAR_MANAGER_CLASS_NAME.c_str(),
363 NAPI_AUTO_LENGTH,
364 New,
365 nullptr,
366 sizeof(properties) / sizeof(*properties),
367 properties,
368 &cons));
369 NAPI_CALL(env, napi_create_reference(env, cons, INITIAL_REFCOUNT, &g_constructorRef));
370 NAPI_CALL(env, napi_set_named_property(env, exports, CALENDAR_MANAGER_CLASS_NAME.c_str(), cons));
371
372 napi_property_descriptor export_properties[] = {
373 DECLARE_NAPI_FUNCTION("getCalendarManager", GetCalendarManager),
374 };
375 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(export_properties) / sizeof(export_properties[0]),
376 export_properties));
377 return exports;
378 }
379 }