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#define MLOG_TAG "AlbumNapi" 16 17#include "album_napi.h" 18 19#include "media_file_asset_columns.h" 20#include "media_file_utils.h" 21#include "media_library_napi.h" 22#include "medialibrary_client_errno.h" 23#include "medialibrary_napi_log.h" 24#include "medialibrary_tracer.h" 25#include "userfile_client.h" 26#include "userfile_manager_types.h" 27 28using OHOS::HiviewDFX::HiLog; 29using OHOS::HiviewDFX::HiLogLabel; 30 31namespace OHOS { 32namespace Media { 33using namespace std; 34using namespace OHOS::DataShare; 35thread_local napi_ref AlbumNapi::sConstructor_ = nullptr; 36thread_local AlbumAsset *AlbumNapi::sAlbumData_ = nullptr; 37using CompleteCallback = napi_async_complete_callback; 38 39thread_local napi_ref AlbumNapi::userFileMgrConstructor_ = nullptr; 40thread_local napi_ref AlbumNapi::photoAccessHelperConstructor_ = nullptr; 41 42AlbumNapi::AlbumNapi() 43 : env_(nullptr) {} 44 45AlbumNapi::~AlbumNapi() = default; 46 47void AlbumNapi::AlbumNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint) 48{ 49 AlbumNapi *album = reinterpret_cast<AlbumNapi*>(nativeObject); 50 if (album != nullptr) { 51 delete album; 52 album = nullptr; 53 } 54} 55 56napi_value AlbumNapi::Init(napi_env env, napi_value exports) 57{ 58 napi_status status; 59 napi_value ctorObj; 60 int32_t refCount = 1; 61 62 napi_property_descriptor album_props[] = { 63 DECLARE_NAPI_GETTER("albumId", JSGetAlbumId), 64 DECLARE_NAPI_GETTER_SETTER("albumName", JSGetAlbumName, JSAlbumNameSetter), 65 DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri), 66 DECLARE_NAPI_GETTER("dateModified", JSGetAlbumDateModified), 67 DECLARE_NAPI_GETTER("count", JSGetCount), 68 DECLARE_NAPI_GETTER("relativePath", JSGetAlbumRelativePath), 69 DECLARE_NAPI_GETTER("coverUri", JSGetCoverUri), 70 DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify), 71 DECLARE_NAPI_GETTER_SETTER("path", JSGetAlbumPath, JSSetAlbumPath), 72 DECLARE_NAPI_GETTER("virtual", JSGetAlbumVirtual), 73 DECLARE_NAPI_FUNCTION("getFileAssets", JSGetAlbumFileAssets) 74 }; 75 76 status = napi_define_class(env, ALBUM_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, 77 AlbumNapiConstructor, nullptr, 78 sizeof(album_props) / sizeof(album_props[PARAM0]), 79 album_props, &ctorObj); 80 if (status == napi_ok) { 81 status = napi_create_reference(env, ctorObj, refCount, &sConstructor_); 82 if (status == napi_ok) { 83 status = napi_set_named_property(env, exports, ALBUM_NAPI_CLASS_NAME.c_str(), ctorObj); 84 if (status == napi_ok) { 85 return exports; 86 } 87 } 88 } 89 90 return nullptr; 91} 92 93napi_value AlbumNapi::UserFileMgrInit(napi_env env, napi_value exports) 94{ 95 NapiClassInfo info = { 96 .name = USERFILEMGR_ALBUM_NAPI_CLASS_NAME, 97 .ref = &userFileMgrConstructor_, 98 .constructor = AlbumNapiConstructor, 99 .props = { 100 DECLARE_NAPI_FUNCTION("getPhotoAssets", UserFileMgrGetAssets), 101 DECLARE_NAPI_FUNCTION("commitModify", UserFileMgrCommitModify), 102 DECLARE_NAPI_GETTER_SETTER("albumName", JSGetAlbumName, JSAlbumNameSetter), 103 DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri), 104 DECLARE_NAPI_GETTER("dateModified", JSGetAlbumDateModified), 105 DECLARE_NAPI_GETTER("count", JSGetCount), 106 DECLARE_NAPI_GETTER("relativePath", JSGetAlbumRelativePath), 107 DECLARE_NAPI_GETTER("coverUri", JSGetCoverUri) 108 } 109 }; 110 111 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info); 112 return exports; 113} 114 115napi_value AlbumNapi::PhotoAccessHelperInit(napi_env env, napi_value exports) 116{ 117 NapiClassInfo info = { 118 .name = PHOTOACCESSHELPER_ALBUM_NAPI_CLASS_NAME, 119 .ref = &photoAccessHelperConstructor_, 120 .constructor = AlbumNapiConstructor, 121 .props = { 122 DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessHelperGetAssets), 123 DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify), 124 DECLARE_NAPI_GETTER_SETTER("albumName", JSGetAlbumName, JSAlbumNameSetter), 125 DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri), 126 DECLARE_NAPI_GETTER("count", JSGetCount), 127 DECLARE_NAPI_GETTER("coverUri", JSGetCoverUri) 128 } 129 }; 130 131 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info); 132 return exports; 133} 134 135void AlbumNapi::SetAlbumNapiProperties() 136{ 137 albumAssetPtr = std::shared_ptr<AlbumAsset>(sAlbumData_); 138} 139 140// Constructor callback 141napi_value AlbumNapi::AlbumNapiConstructor(napi_env env, napi_callback_info info) 142{ 143 napi_status status; 144 napi_value result = nullptr; 145 napi_value thisVar = nullptr; 146 147 napi_get_undefined(env, &result); 148 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 149 if (status == napi_ok && thisVar != nullptr) { 150 std::unique_ptr<AlbumNapi> obj = std::make_unique<AlbumNapi>(); 151 if (obj != nullptr) { 152 obj->env_ = env; 153 if (sAlbumData_ != nullptr) { 154 obj->SetAlbumNapiProperties(); 155 } 156 157 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()), 158 AlbumNapi::AlbumNapiDestructor, nullptr, nullptr); 159 if (status == napi_ok) { 160 obj.release(); 161 return thisVar; 162 } else { 163 NAPI_ERR_LOG("Failure wrapping js to native napi. status: %{public}d", status); 164 } 165 } 166 } 167 168 return result; 169} 170 171napi_value AlbumNapi::CreateAlbumNapi(napi_env env, unique_ptr<AlbumAsset> &albumData) 172{ 173 if (albumData == nullptr) { 174 return nullptr; 175 } 176 177 napi_value constructor; 178 napi_ref constructorRef; 179 if (albumData->GetResultNapiType() == ResultNapiType::TYPE_USERFILE_MGR) { 180 constructorRef = userFileMgrConstructor_; 181 } else if (albumData->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) { 182 constructorRef = photoAccessHelperConstructor_; 183 } else { 184 constructorRef = sConstructor_; 185 } 186 NAPI_CALL(env, napi_get_reference_value(env, constructorRef, &constructor)); 187 188 napi_value result = nullptr; 189 sAlbumData_ = albumData.release(); 190 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result)); 191 sAlbumData_ = nullptr; 192 return result; 193} 194 195std::string AlbumNapi::GetAlbumName() const 196{ 197 return albumAssetPtr->GetAlbumName(); 198} 199 200std::string AlbumNapi::GetAlbumPath() const 201{ 202 return albumAssetPtr->GetAlbumPath(); 203} 204 205int32_t AlbumNapi::GetAlbumId() const 206{ 207 return albumAssetPtr->GetAlbumId(); 208} 209 210std::string AlbumNapi::GetAlbumUri() const 211{ 212 return albumAssetPtr->GetAlbumUri(); 213} 214 215std::string AlbumNapi::GetNetworkId() const 216{ 217 return MediaFileUtils::GetNetworkIdFromUri(GetAlbumUri()); 218} 219 220#ifdef MEDIALIBRARY_COMPATIBILITY 221PhotoAlbumType AlbumNapi::GetAlbumType() const 222{ 223 return albumAssetPtr->GetAlbumType(); 224} 225PhotoAlbumSubType AlbumNapi::GetAlbumSubType() const 226{ 227 return albumAssetPtr->GetAlbumSubType(); 228} 229#endif 230 231napi_value AlbumNapi::JSGetAlbumId(napi_env env, napi_callback_info info) 232{ 233 napi_status status; 234 napi_value jsResult = nullptr; 235 napi_value undefinedResult = nullptr; 236 AlbumNapi* obj = nullptr; 237 int32_t id; 238 napi_value thisVar = nullptr; 239 240 napi_get_undefined(env, &undefinedResult); 241 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 242 if (status != napi_ok || thisVar == nullptr) { 243 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 244 return undefinedResult; 245 } 246 247 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 248 if (status == napi_ok && obj != nullptr) { 249 id = obj->GetAlbumId(); 250 status = napi_create_int32(env, id, &jsResult); 251 if (status == napi_ok) { 252 return jsResult; 253 } 254 } 255 256 return undefinedResult; 257} 258 259napi_value AlbumNapi::JSGetAlbumName(napi_env env, napi_callback_info info) 260{ 261 napi_status status; 262 napi_value jsResult = nullptr; 263 napi_value undefinedResult = nullptr; 264 AlbumNapi* obj = nullptr; 265 std::string name = ""; 266 napi_value thisVar = nullptr; 267 napi_get_undefined(env, &undefinedResult); 268 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 269 if (status != napi_ok || thisVar == nullptr) { 270 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 271 return undefinedResult; 272 } 273 274 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 275 if (status == napi_ok && obj != nullptr) { 276 name = obj->GetAlbumName(); 277 status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &jsResult); 278 if (status == napi_ok) { 279 return jsResult; 280 } 281 } 282 283 return undefinedResult; 284} 285 286napi_value AlbumNapi::JSAlbumNameSetter(napi_env env, napi_callback_info info) 287{ 288 napi_status status; 289 napi_value jsResult = nullptr; 290 size_t argc = ARGS_ONE; 291 napi_value argv[ARGS_ONE] = {0}; 292 size_t res = 0; 293 char buffer[FILENAME_MAX]; 294 AlbumNapi* obj = nullptr; 295 napi_value thisVar = nullptr; 296 napi_valuetype valueType = napi_undefined; 297 298 napi_get_undefined(env, &jsResult); 299 GET_JS_ARGS(env, info, argc, argv, thisVar); 300 NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter"); 301 if (thisVar == nullptr || napi_typeof(env, argv[PARAM0], &valueType) != napi_ok 302 || valueType != napi_string) { 303 NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType); 304 return jsResult; 305 } 306 307 napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res); 308 309 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 310 if (status == napi_ok && obj != nullptr) { 311 obj->albumAssetPtr->SetAlbumName(std::string(buffer)); 312 } else { 313 NAPI_ERR_LOG("status = %{public}d", status); 314 } 315 return jsResult; 316} 317napi_value AlbumNapi::JSGetAlbumUri(napi_env env, napi_callback_info info) 318{ 319 napi_status status; 320 napi_value jsResult = nullptr; 321 napi_value undefinedResult = nullptr; 322 AlbumNapi* obj = nullptr; 323 std::string uri = ""; 324 napi_value thisVar = nullptr; 325 326 napi_get_undefined(env, &undefinedResult); 327 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 328 if (status != napi_ok || thisVar == nullptr) { 329 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 330 return undefinedResult; 331 } 332 333 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 334 if (status == napi_ok && obj != nullptr) { 335 uri = obj->GetAlbumUri(); 336 status = napi_create_string_utf8(env, uri.c_str(), NAPI_AUTO_LENGTH, &jsResult); 337 if (status == napi_ok) { 338 return jsResult; 339 } 340 } 341 342 return undefinedResult; 343} 344napi_value AlbumNapi::JSGetAlbumDateModified(napi_env env, napi_callback_info info) 345{ 346 napi_status status; 347 napi_value jsResult = nullptr; 348 napi_value undefinedResult = nullptr; 349 AlbumNapi* obj = nullptr; 350 int64_t dateModified; 351 napi_value thisVar = nullptr; 352 353 napi_get_undefined(env, &undefinedResult); 354 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 355 if (status != napi_ok || thisVar == nullptr) { 356 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 357 return undefinedResult; 358 } 359 360 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 361 if (status == napi_ok && obj != nullptr) { 362 dateModified = obj->albumAssetPtr->GetAlbumDateModified() / MSEC_TO_SEC; 363 status = napi_create_int64(env, dateModified, &jsResult); 364 if (status == napi_ok) { 365 return jsResult; 366 } 367 } 368 369 return undefinedResult; 370} 371napi_value AlbumNapi::JSGetCount(napi_env env, napi_callback_info info) 372{ 373 napi_status status; 374 napi_value jsResult = nullptr; 375 napi_value undefinedResult = nullptr; 376 AlbumNapi *obj = nullptr; 377 int32_t count; 378 napi_value thisVar = nullptr; 379 380 napi_get_undefined(env, &undefinedResult); 381 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 382 if (status != napi_ok || thisVar == nullptr) { 383 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 384 return undefinedResult; 385 } 386 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 387 if (status == napi_ok && obj != nullptr) { 388 count = obj->albumAssetPtr->GetCount(); 389 status = napi_create_int32(env, count, &jsResult); 390 if (status == napi_ok) { 391 return jsResult; 392 } 393 } 394 return undefinedResult; 395} 396napi_value AlbumNapi::JSGetAlbumRelativePath(napi_env env, napi_callback_info info) 397{ 398 napi_status status; 399 napi_value jsResult = nullptr; 400 napi_value undefinedResult = nullptr; 401 AlbumNapi* obj = nullptr; 402 std::string relativePath = ""; 403 napi_value thisVar = nullptr; 404 405 napi_get_undefined(env, &undefinedResult); 406 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 407 if (status != napi_ok || thisVar == nullptr) { 408 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 409 return undefinedResult; 410 } 411 412 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 413 if (status == napi_ok && obj != nullptr) { 414 relativePath = obj->albumAssetPtr->GetAlbumRelativePath(); 415 status = napi_create_string_utf8(env, relativePath.c_str(), NAPI_AUTO_LENGTH, &jsResult); 416 if (status == napi_ok) { 417 return jsResult; 418 } 419 } 420 421 return undefinedResult; 422} 423napi_value AlbumNapi::JSGetCoverUri(napi_env env, napi_callback_info info) 424{ 425 napi_status status; 426 napi_value jsResult = nullptr; 427 napi_value undefinedResult = nullptr; 428 AlbumNapi* obj = nullptr; 429 std::string coverUri = ""; 430 napi_value thisVar = nullptr; 431 432 napi_get_undefined(env, &undefinedResult); 433 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 434 if (status != napi_ok || thisVar == nullptr) { 435 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 436 return undefinedResult; 437 } 438 439 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 440 if (status == napi_ok && obj != nullptr) { 441 coverUri = obj->albumAssetPtr->GetCoverUri(); 442 status = napi_create_string_utf8(env, coverUri.c_str(), NAPI_AUTO_LENGTH, &jsResult); 443 if (status == napi_ok) { 444 return jsResult; 445 } 446 } 447 448 return undefinedResult; 449} 450 451napi_value AlbumNapi::JSSetAlbumPath(napi_env env, napi_callback_info info) 452{ 453 napi_status status; 454 napi_value jsResult = nullptr; 455 size_t argc = ARGS_ONE; 456 napi_value argv[ARGS_ONE] = {0}; 457 size_t res = 0; 458 char buffer[PATH_MAX]; 459 AlbumNapi* obj = nullptr; 460 napi_value thisVar = nullptr; 461 napi_valuetype valueType = napi_undefined; 462 463 napi_get_undefined(env, &jsResult); 464 GET_JS_ARGS(env, info, argc, argv, thisVar); 465 NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter"); 466 467 if (thisVar == nullptr || napi_typeof(env, argv[PARAM0], &valueType) != napi_ok 468 || valueType != napi_string) { 469 NAPI_ERR_LOG("Invalid arguments type! type: %{public}d", valueType); 470 return jsResult; 471 } 472 473 napi_get_value_string_utf8(env, argv[PARAM0], buffer, PATH_MAX, &res); 474 475 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 476 if (status == napi_ok && obj != nullptr) { 477 obj->albumAssetPtr->SetAlbumPath(std::string(buffer)); 478 } 479 480 return jsResult; 481} 482 483napi_value AlbumNapi::JSGetAlbumPath(napi_env env, napi_callback_info info) 484{ 485 napi_status status; 486 napi_value jsResult = nullptr; 487 napi_value undefinedResult = nullptr; 488 AlbumNapi* obj = nullptr; 489 std::string path = ""; 490 napi_value thisVar = nullptr; 491 492 napi_get_undefined(env, &undefinedResult); 493 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 494 if (status != napi_ok || thisVar == nullptr) { 495 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 496 return undefinedResult; 497 } 498 499 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 500 if (status == napi_ok && obj != nullptr) { 501 path = obj->GetAlbumPath(); 502 status = napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &jsResult); 503 if (status == napi_ok) { 504 return jsResult; 505 } 506 } 507 508 return undefinedResult; 509} 510 511napi_value AlbumNapi::JSGetAlbumVirtual(napi_env env, napi_callback_info info) 512{ 513 napi_status status; 514 napi_value jsResult = nullptr; 515 napi_value undefinedResult = nullptr; 516 AlbumNapi* obj = nullptr; 517 bool virtualAlbum = false; 518 napi_value thisVar = nullptr; 519 520 napi_get_undefined(env, &undefinedResult); 521 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar); 522 if (status != napi_ok || thisVar == nullptr) { 523 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status); 524 return undefinedResult; 525 } 526 527 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj)); 528 if (status == napi_ok && obj != nullptr) { 529 virtualAlbum = obj->albumAssetPtr->GetAlbumVirtual(); 530 status = napi_get_boolean(env, virtualAlbum, &jsResult); 531 if (status == napi_ok) { 532 return jsResult; 533 } 534 } 535 536 return undefinedResult; 537} 538 539static void GetFetchOptionsParam(napi_env env, napi_value arg, const AlbumNapiAsyncContext &context, bool &err) 540{ 541 AlbumNapiAsyncContext *asyncContext = const_cast<AlbumNapiAsyncContext *>(&context); 542 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null"); 543 char buffer[PATH_MAX]; 544 size_t res; 545 uint32_t len = 0; 546 napi_value property = nullptr; 547 napi_value stringItem = nullptr; 548 bool present = false; 549 bool boolResult = false; 550 551 string propertyName = "selections"; 552 string tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName); 553 if (!tmp.empty()) { 554 asyncContext->selection = tmp; 555 } 556 557 propertyName = "order"; 558 tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName); 559 if (!tmp.empty()) { 560 asyncContext->order = tmp; 561 } 562 563 napi_has_named_property(env, arg, "selectionArgs", &present); 564 if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok && 565 napi_is_array(env, property, &boolResult) == napi_ok && boolResult) { 566 napi_get_array_length(env, property, &len); 567 for (size_t i = 0; i < len; i++) { 568 napi_get_element(env, property, i, &stringItem); 569 napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res); 570 asyncContext->selectionArgs.push_back(std::string(buffer)); 571 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed"); 572 } 573 } else { 574 NAPI_ERR_LOG("Could not get the string argument!"); 575 err = true; 576 } 577} 578 579static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[], 580 AlbumNapiAsyncContext &asyncContext) 581{ 582 string str = ""; 583 std::vector<string> strArr; 584 string order = ""; 585 bool err = false; 586 const int32_t refCount = 1; 587 napi_value result; 588 auto context = &asyncContext; 589 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null"); 590 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty"); 591 if (argc == ARGS_ONE) { 592 napi_valuetype valueType = napi_undefined; 593 if (napi_typeof(env, argv[PARAM0], &valueType) == napi_ok && 594 (valueType == napi_undefined || valueType == napi_null)) { 595 argc -= 1; 596 } 597 } 598 599 for (size_t i = PARAM0; i < argc; i++) { 600 napi_valuetype valueType = napi_undefined; 601 napi_typeof(env, argv[i], &valueType); 602 603 if (i == PARAM0 && valueType == napi_object) { 604 GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err); 605 if (err) { 606 NAPI_ASSERT(env, false, "type mismatch"); 607 } 608 } else if (i == PARAM0 && valueType == napi_function) { 609 napi_create_reference(env, argv[i], refCount, &context->callbackRef); 610 break; 611 } else if (i == PARAM1 && valueType == napi_function) { 612 napi_create_reference(env, argv[i], refCount, &context->callbackRef); 613 break; 614 } else { 615 NAPI_ASSERT(env, false, "type mismatch"); 616 } 617 } 618 619 // Return true napi_value if params are successfully obtained 620 napi_get_boolean(env, true, &result); 621 return result; 622} 623static napi_value ConvertCommitJSArgsToNative(napi_env env, size_t argc, const napi_value argv[], 624 AlbumNapiAsyncContext &asyncContext) 625{ 626 string str = ""; 627 vector<string> strArr; 628 string order = ""; 629 bool err = false; 630 const int32_t refCount = 1; 631 napi_value result; 632 auto context = &asyncContext; 633 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null"); 634 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty"); 635 636 for (size_t i = PARAM0; i < argc; i++) { 637 napi_valuetype valueType = napi_undefined; 638 napi_typeof(env, argv[i], &valueType); 639 640 if (i == PARAM0 && valueType == napi_object) { 641 GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err); 642 if (err) { 643 NAPI_ERR_LOG("fetch options retrieval failed. err %{public}d", err); 644 NAPI_ASSERT(env, false, "type mismatch"); 645 } 646 } else if (i == PARAM0 && valueType == napi_function) { 647 napi_create_reference(env, argv[i], refCount, &context->callbackRef); 648 break; 649 } else if (i == PARAM1 && valueType == napi_function) { 650 napi_create_reference(env, argv[i], refCount, &context->callbackRef); 651 break; 652 } else { 653 NAPI_ASSERT(env, false, "type mismatch"); 654 } 655 } 656 657 // Return true napi_value if params are successfully obtained 658 napi_get_boolean(env, true, &result); 659 return result; 660} 661 662#ifdef MEDIALIBRARY_COMPATIBILITY 663static void UpdateCompatAlbumSelection(AlbumNapiAsyncContext *context) 664{ 665 PhotoAlbumSubType subType = context->objectPtr->GetAlbumSubType(); 666 string filterClause; 667 switch (subType) { 668 case PhotoAlbumSubType::CAMERA: { 669 static const string CAMERA_FILTER = PhotoColumn::PHOTO_SUBTYPE + "=" + 670 to_string(static_cast<int32_t>(PhotoSubType::CAMERA)) + " AND " + MediaColumn::ASSETS_QUERY_FILTER; 671 filterClause = CAMERA_FILTER; 672 break; 673 } 674 case PhotoAlbumSubType::SCREENSHOT: { 675 static const string SCREENSHOT_FILTER = PhotoColumn::PHOTO_SUBTYPE + "=" + 676 to_string(static_cast<int32_t>(PhotoSubType::SCREENSHOT)) + " AND " + MediaColumn::ASSETS_QUERY_FILTER; 677 filterClause = SCREENSHOT_FILTER; 678 break; 679 } 680 case PhotoAlbumSubType::FAVORITE: { 681 static const string FAVORITE_FILTER = PhotoColumn::MEDIA_IS_FAV + " = 1" + " AND " + 682 MediaColumn::ASSETS_QUERY_FILTER; 683 filterClause = FAVORITE_FILTER; 684 break; 685 } 686 case PhotoAlbumSubType::TRASH: { 687 static const string TRASH_FILTER = 688 PhotoColumn::MEDIA_DATE_TRASHED + " > 0 AND " + MEDIA_DATA_DB_IS_TRASH + " <> " + 689 to_string(static_cast<int32_t>(TRASHED_DIR_CHILD)); 690 filterClause = TRASH_FILTER; 691 break; 692 } 693 default: { 694 NAPI_ERR_LOG("Album subtype not support for compatibility: %{public}d", subType); 695 context->SaveError(-EINVAL); 696 return; 697 } 698 } 699 if (!context->selection.empty()) { 700 context->selection = filterClause + " AND (" + context->selection + ")"; 701 } else { 702 context->selection = filterClause; 703 } 704 MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs, 705 MEDIA_DATA_DB_RELATIVE_PATH, MEDIA_DATA_DB_RELATIVE_PATH); 706} 707#endif 708 709static void UpdateSelection(AlbumNapiAsyncContext *context) 710{ 711 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR || 712 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) { 713 context->predicates.EqualTo(MEDIA_DATA_DB_DATE_TRASHED, 0); 714 context->predicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_ALBUM); 715 context->predicates.EqualTo(MEDIA_DATA_DB_BUCKET_ID, context->objectPtr->GetAlbumId()); 716 context->predicates.EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0)); 717 context->predicates.EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0)); 718 context->predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL, 719 to_string(static_cast<int32_t>(BurstCoverLevelType::COVER))); 720 MediaLibraryNapiUtils::UpdateMediaTypeSelections(context); 721 } else { 722#ifdef MEDIALIBRARY_COMPATIBILITY 723 UpdateCompatAlbumSelection(context); 724#else 725 string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? "; 726 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix); 727 context->selectionArgs.emplace_back("0"); 728 729 string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? "; 730 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix); 731 context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM)); 732 733 string idPrefix = MEDIA_DATA_DB_BUCKET_ID + " = ? "; 734 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix); 735 context->selectionArgs.emplace_back(std::to_string(context->objectPtr->GetAlbumId())); 736#endif 737 } 738} 739 740static void GetFileAssetsNative(napi_env env, void *data) 741{ 742 MediaLibraryTracer tracer; 743 tracer.Start("GetFileAssetsNative"); 744 745 AlbumNapiAsyncContext *context = static_cast<AlbumNapiAsyncContext*>(data); 746 747 UpdateSelection(context); 748 MediaLibraryNapiUtils::FixSpecialDateType(context->selection); 749 context->predicates.SetWhereClause(context->selection); 750 context->predicates.SetWhereArgs(context->selectionArgs); 751 context->predicates.SetOrder(context->order); 752 753 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) { 754 context->fetchColumn = FILE_ASSET_COLUMNS; 755 } else { 756 context->fetchColumn.push_back(MEDIA_DATA_DB_ID); 757 context->fetchColumn.push_back(MEDIA_DATA_DB_NAME); 758 context->fetchColumn.push_back(MEDIA_DATA_DB_MEDIA_TYPE); 759 } 760 761 string queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + 762 (MediaFileUtils::GetNetworkIdFromUri(context->objectPtr->GetAlbumUri())) + MEDIALIBRARY_DATA_URI_IDENTIFIER; 763 NAPI_DEBUG_LOG("queryUri is = %{private}s", queryUri.c_str()); 764 Uri uri(queryUri); 765 int errCode = 0; 766 std::shared_ptr<OHOS::DataShare::DataShareResultSet> resultSet = 767 UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode); 768 if (resultSet == nullptr) { 769 NAPI_ERR_LOG("GetFileAssetsNative called, UserFileClient::Query errorCode is = %{public}d", errCode); 770 context->SaveError(errCode); 771 return; 772 } 773 context->fetchResult = std::make_unique<FetchResult<FileAsset>>(move(resultSet)); 774 context->fetchResult->SetNetworkId(MediaFileUtils::GetNetworkIdFromUri(context->objectPtr->GetAlbumUri())); 775 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR || 776 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) { 777 context->fetchResult->SetResultNapiType(context->resultNapiType); 778 } 779} 780 781static void JSGetFileAssetsCompleteCallback(napi_env env, napi_status status, void *data) 782{ 783 MediaLibraryTracer tracer; 784 tracer.Start("JSGetFileAssetsCompleteCallback"); 785 786 AlbumNapiAsyncContext *context = static_cast<AlbumNapiAsyncContext*>(data); 787 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null"); 788 789 std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>(); 790 jsContext->status = false; 791 if (context->fetchResult != nullptr) { 792 if (context->fetchResult->GetCount() < 0) { 793 napi_get_undefined(env, &jsContext->data); 794 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION, 795 "find no data by options"); 796 } else { 797 napi_value fetchRes = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchResult)); 798 if (fetchRes == nullptr) { 799 NAPI_ERR_LOG("Failed to get file asset napi object"); 800 napi_get_undefined(env, &jsContext->data); 801 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION, 802 "Failed to create js object for FetchFileResult"); 803 } else { 804 jsContext->data = fetchRes; 805 napi_get_undefined(env, &jsContext->error); 806 jsContext->status = true; 807 } 808 } 809 } else { 810 NAPI_ERR_LOG("No fetch file result found!"); 811 context->HandleError(env, jsContext->error); 812 napi_get_undefined(env, &jsContext->data); 813 } 814 815 tracer.Finish(); 816 if (context->work != nullptr) { 817 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, 818 context->work, *jsContext); 819 } 820 delete context; 821} 822 823static void CommitModifyNative(napi_env env, void *data) 824{ 825 MediaLibraryTracer tracer; 826 tracer.Start("CommitModifyNative"); 827 828 auto *context = static_cast<AlbumNapiAsyncContext*>(data); 829 auto objectPtr = context->objectPtr; 830 if (MediaFileUtils::CheckAlbumName(objectPtr->GetAlbumName()) < 0) { 831 context->error = JS_E_DISPLAYNAME; 832 NAPI_ERR_LOG("album name invalid = %{private}s", objectPtr->GetAlbumName().c_str()); 833 return; 834 } 835#ifdef MEDIALIBRARY_COMPATIBILITY 836 context->changedRows = 0; 837#else 838 DataSharePredicates predicates; 839 DataShareValuesBucket valuesBucket; 840 valuesBucket.Put(MEDIA_DATA_DB_TITLE, objectPtr->GetAlbumName()); 841 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? "); 842 predicates.SetWhereArgs({ std::to_string(objectPtr->GetAlbumId()) }); 843 844 string updateUri = MEDIALIBRARY_DATA_URI + "/" + 845 MEDIA_ALBUMOPRN + "/" + MEDIA_ALBUMOPRN_MODIFYALBUM + "/" + std::to_string(objectPtr->GetAlbumId()); 846 Uri uri(updateUri); 847 int changedRows = UserFileClient::Update(uri, predicates, valuesBucket); 848 if (changedRows > 0) { 849 DataSharePredicates filePredicates; 850 DataShareValuesBucket fileValuesBucket; 851 fileValuesBucket.Put(MEDIA_DATA_DB_BUCKET_NAME, objectPtr->GetAlbumName()); 852 filePredicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? "); 853 filePredicates.SetWhereArgs({ std::to_string(objectPtr->GetAlbumId()) }); 854 855 string fileUriStr = MEDIALIBRARY_DATA_URI; 856 Uri fileUri(fileUriStr); 857 changedRows = UserFileClient::Update(fileUri, filePredicates, fileValuesBucket); 858 } 859 context->SaveError(changedRows); 860 context->changedRows = changedRows; 861#endif 862} 863 864static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data) 865{ 866 MediaLibraryTracer tracer; 867 tracer.Start("JSCommitModifyCompleteCallback"); 868 869 AlbumNapiAsyncContext *context = static_cast<AlbumNapiAsyncContext*>(data); 870 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null"); 871 std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>(); 872 jsContext->status = false; 873 if (context->error == ERR_DEFAULT) { 874 napi_create_int32(env, context->changedRows, &jsContext->data); 875 napi_get_undefined(env, &jsContext->error); 876 jsContext->status = true; 877 auto contextUri = make_unique<Uri>(MEDIALIBRARY_ALBUM_URI); 878 UserFileClient::NotifyChange(*contextUri); 879 } else { 880 napi_get_undefined(env, &jsContext->data); 881 context->HandleError(env, jsContext->error); 882 } 883 884 tracer.Finish(); 885 if (context->work != nullptr) { 886 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, 887 context->work, *jsContext); 888 } 889 890 delete context; 891} 892napi_value AlbumNapi::JSGetAlbumFileAssets(napi_env env, napi_callback_info info) 893{ 894 napi_status status; 895 napi_value result = nullptr; 896 size_t argc = ARGS_TWO; 897 napi_value argv[ARGS_TWO] = {0}; 898 napi_value thisVar = nullptr; 899 900 MediaLibraryTracer tracer; 901 tracer.Start("JSGetAlbumFileAssets"); 902 903 GET_JS_ARGS(env, info, argc, argv, thisVar); 904 NAPI_ASSERT(env, ((argc == ARGS_ZERO) || (argc == ARGS_ONE) || (argc == ARGS_TWO)), 905 "requires 2 parameter maximum"); 906 napi_get_undefined(env, &result); 907 908 std::unique_ptr<AlbumNapiAsyncContext> asyncContext = std::make_unique<AlbumNapiAsyncContext>(); 909 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY; 910 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo)); 911 if (status == napi_ok && asyncContext->objectInfo != nullptr) { 912 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext); 913 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments"); 914 asyncContext->objectPtr = asyncContext->objectInfo->albumAssetPtr; 915 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "AlbumAsset is nullptr"); 916 917 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbumFileAssets", 918 GetFileAssetsNative, JSGetFileAssetsCompleteCallback); 919 } 920 921 return result; 922} 923napi_value AlbumNapi::JSCommitModify(napi_env env, napi_callback_info info) 924{ 925 napi_status status; 926 napi_value result = nullptr; 927 size_t argc = ARGS_ONE; 928 napi_value argv[ARGS_ONE] = {0}; 929 napi_value thisVar = nullptr; 930 931 MediaLibraryTracer tracer; 932 tracer.Start("JSCommitModify"); 933 934 GET_JS_ARGS(env, info, argc, argv, thisVar); 935 NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameter maximum"); 936 napi_get_undefined(env, &result); 937 938 std::unique_ptr<AlbumNapiAsyncContext> asyncContext = std::make_unique<AlbumNapiAsyncContext>(); 939 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null"); 940 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY; 941 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo)); 942 if (status == napi_ok && asyncContext->objectInfo != nullptr) { 943 result = ConvertCommitJSArgsToNative(env, argc, argv, *asyncContext); 944 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "JSCommitModify fail "); 945 asyncContext->objectPtr = asyncContext->objectInfo->albumAssetPtr; 946 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "AlbumAsset is nullptr"); 947 948 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", CommitModifyNative, 949 JSCommitModifyCompleteCallback); 950 } 951 952 return result; 953} 954 955napi_value AlbumNapi::UserFileMgrGetAssets(napi_env env, napi_callback_info info) 956{ 957 napi_value ret = nullptr; 958 unique_ptr<AlbumNapiAsyncContext> asyncContext = make_unique<AlbumNapiAsyncContext>(); 959 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null"); 960 961 asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE); 962 asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO); 963 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAssetFetchOptCallback(env, info, asyncContext), 964 JS_ERR_PARAMETER_INVALID); 965 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR; 966 asyncContext->objectPtr = asyncContext->objectInfo->albumAssetPtr; 967 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "AlbumAsset is nullptr"); 968 969 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetAssets", GetFileAssetsNative, 970 JSGetFileAssetsCompleteCallback); 971} 972 973napi_value AlbumNapi::UserFileMgrCommitModify(napi_env env, napi_callback_info info) 974{ 975 MediaLibraryTracer tracer; 976 tracer.Start("UserFileMgrCommitModify"); 977 978 napi_value ret = nullptr; 979 unique_ptr<AlbumNapiAsyncContext> asyncContext = make_unique<AlbumNapiAsyncContext>(); 980 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null"); 981 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR; 982 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext), JS_ERR_PARAMETER_INVALID); 983 asyncContext->objectPtr = asyncContext->objectInfo->albumAssetPtr; 984 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "AlbumAsset is nullptr"); 985 986 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCommitModify", CommitModifyNative, 987 JSCommitModifyCompleteCallback); 988} 989 990napi_value AlbumNapi::PhotoAccessHelperGetAssets(napi_env env, napi_callback_info info) 991{ 992 napi_value ret = nullptr; 993 unique_ptr<AlbumNapiAsyncContext> asyncContext = make_unique<AlbumNapiAsyncContext>(); 994 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null"); 995 996 asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE); 997 asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO); 998 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAssetFetchOptCallback(env, info, asyncContext), 999 JS_ERR_PARAMETER_INVALID); 1000 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER; 1001 asyncContext->objectPtr = asyncContext->objectInfo->albumAssetPtr; 1002 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "AlbumAsset is nullptr"); 1003 1004 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetAssets", GetFileAssetsNative, 1005 JSGetFileAssetsCompleteCallback); 1006} 1007 1008napi_value AlbumNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info) 1009{ 1010 MediaLibraryTracer tracer; 1011 tracer.Start("UserFileMgrCommitModify"); 1012 1013 napi_value ret = nullptr; 1014 unique_ptr<AlbumNapiAsyncContext> asyncContext = make_unique<AlbumNapiAsyncContext>(); 1015 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null"); 1016 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER; 1017 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext), JS_ERR_PARAMETER_INVALID); 1018 asyncContext->objectPtr = asyncContext->objectInfo->albumAssetPtr; 1019 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "AlbumAsset is nullptr"); 1020 1021 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCommitModify", CommitModifyNative, 1022 JSCommitModifyCompleteCallback); 1023} 1024} // namespace Media 1025} // namespace OHOS 1026