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 19using namespace OHOS::AppExecFwk; 20using namespace OHOS::DataShare; 21static const int INVALID_EVENT_ID = -1; 22static const int ARGS_INDEX_ONE = 1; 23static const int ARGS_INDEX_TWO = 2; 24static const int ARGS_INDEX_THREE = 3; 25 26namespace { 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} 31namespace OHOS::CalendarApi { 32napi_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 70napi_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 105struct GetCalendarContext : public ContextBase { 106 std::optional<CalendarAccount> account; 107 CalendarNapi *calendar = nullptr; 108 napi_ref ref = nullptr; 109 int id = -1; 110 111 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 132napi_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 160napi_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 208napi_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 241napi_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 276napi_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 324napi_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 350napi_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}