1 /*
2 * Copyright (C) 2021-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 #define MLOG_TAG "MediaLibraryNapi"
17
18 #include "media_library_napi.h"
19 #include <fcntl.h>
20 #include <sys/sendfile.h>
21
22 #include "directory_ex.h"
23 #include "file_ex.h"
24 #include "hitrace_meter.h"
25 #include "media_file_uri.h"
26 #include "media_file_utils.h"
27 #include "medialibrary_client_errno.h"
28 #include "medialibrary_asset_operations.h"
29 #include "medialibrary_data_manager.h"
30 #include "medialibrary_db_const.h"
31 #include "medialibrary_errno.h"
32 #include "medialibrary_napi_log.h"
33 #include "medialibrary_peer_info.h"
34 #include "medialibrary_tracer.h"
35 #include "media_column.h"
36 #include "permission_utils.h"
37 #include "photo_album_column.h"
38 #include "photo_album_napi.h"
39 #include "result_set_utils.h"
40 #include "smart_album_napi.h"
41 #include "string_ex.h"
42 #include "string_wrapper.h"
43 #include "userfile_client.h"
44 #include "uv.h"
45
46 using namespace std;
47 using namespace OHOS::AppExecFwk;
48 using namespace OHOS::NativeRdb;
49 using namespace OHOS::DataShare;
50
51 namespace OHOS {
52 namespace Media {
53 using ChangeType = AAFwk::ChangeInfo::ChangeType;
54 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
55 const int32_t NUM_2 = 2;
56 const int32_t NUM_3 = 3;
57 const string DATE_FUNCTION = "DATE(";
58
59 mutex MediaLibraryNapi::sUserFileClientMutex_;
60 mutex MediaLibraryNapi::sOnOffMutex_;
61 string ChangeListenerNapi::trashAlbumUri_;
62 static map<string, ListenerType> ListenerTypeMaps = {
63 {"audioChange", AUDIO_LISTENER},
64 {"videoChange", VIDEO_LISTENER},
65 {"imageChange", IMAGE_LISTENER},
66 {"fileChange", FILE_LISTENER},
67 {"albumChange", ALBUM_LISTENER},
68 {"deviceChange", DEVICE_LISTENER},
69 {"remoteFileChange", REMOTEFILE_LISTENER}
70 };
71
72 const std::string SUBTYPE = "subType";
73 const std::string PAH_SUBTYPE = "subtype";
74 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
75 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
76 { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
77 { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
78 { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
79
80 };
81
82 const std::string TITLE = "title";
83 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
84 { TITLE, MediaColumn::MEDIA_TITLE }
85 };
86
87 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
88 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
89 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
90 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
91 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
92 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
93 thread_local napi_ref MediaLibraryNapi::sPositionTypeEnumRef_ = nullptr;
94 thread_local napi_ref MediaLibraryNapi::sPhotoSubType_ = nullptr;
95 using CompleteCallback = napi_async_complete_callback;
96 using Context = MediaLibraryAsyncContext* ;
97
98 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
99 thread_local napi_ref MediaLibraryNapi::photoAccessHelperConstructor_ = nullptr;
100 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
101 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
102 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
103 thread_local napi_ref MediaLibraryNapi::sPhotoKeysEnumRef_ = nullptr;
104 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
105 thread_local napi_ref MediaLibraryNapi::sAlbumType_ = nullptr;
106 thread_local napi_ref MediaLibraryNapi::sAlbumSubType_ = nullptr;
107 thread_local napi_ref MediaLibraryNapi::sNotifyType_ = nullptr;
108 thread_local napi_ref MediaLibraryNapi::sDefaultChangeUriRef_ = nullptr;
109 constexpr int32_t DEFAULT_REFCOUNT = 1;
110 constexpr int32_t DEFAULT_ALBUM_COUNT = 1;
MediaLibraryNapi()111 MediaLibraryNapi::MediaLibraryNapi()
112 : env_(nullptr) {}
113
114 MediaLibraryNapi::~MediaLibraryNapi() = default;
115
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)116 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
117 {
118 MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
119 if (mediaLibrary != nullptr) {
120 delete mediaLibrary;
121 mediaLibrary = nullptr;
122 }
123 }
124
Init(napi_env env,napi_value exports)125 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
126 {
127 napi_property_descriptor media_library_properties[] = {
128 DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
129 DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
130 DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
131 DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
132 DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
133 DECLARE_NAPI_FUNCTION("on", JSOnCallback),
134 DECLARE_NAPI_FUNCTION("off", JSOffCallback),
135 DECLARE_NAPI_FUNCTION("release", JSRelease),
136 DECLARE_NAPI_FUNCTION("getSmartAlbum", JSGetSmartAlbums),
137 DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
138 DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
139 DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
140 DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
141 DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
142 DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
143 DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
144 };
145 napi_property_descriptor static_prop[] = {
146 DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
147 DECLARE_NAPI_STATIC_FUNCTION("getMediaLibraryAsync", GetMediaLibraryNewInstanceAsync),
148 DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
149 DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
150 DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
151 DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env))
152 };
153 napi_value ctorObj;
154 napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
155 MediaLibraryNapiConstructor, nullptr,
156 sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
157 media_library_properties, &ctorObj);
158 if (status == napi_ok) {
159 int32_t refCount = 1;
160 if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
161 status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
162 if (status == napi_ok && napi_define_properties(env, exports,
163 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
164 return exports;
165 }
166 }
167 }
168 return nullptr;
169 }
170
UserFileMgrInit(napi_env env,napi_value exports)171 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
172 {
173 NapiClassInfo info = {
174 USERFILE_MGR_NAPI_CLASS_NAME,
175 &userFileMgrConstructor_,
176 MediaLibraryNapiConstructor,
177 {
178 DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
179 DECLARE_NAPI_FUNCTION("getAudioAssets", JSGetAudioAssets),
180 DECLARE_NAPI_FUNCTION("getPhotoAlbums", JSGetPhotoAlbums),
181 DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreatePhotoAsset),
182 DECLARE_NAPI_FUNCTION("createAudioAsset", UserFileMgrCreateAudioAsset),
183 DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
184 DECLARE_NAPI_FUNCTION("on", UserFileMgrOnCallback),
185 DECLARE_NAPI_FUNCTION("off", UserFileMgrOffCallback),
186 DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
187 DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
188 DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
189 DECLARE_NAPI_FUNCTION("release", JSRelease),
190 DECLARE_NAPI_FUNCTION("createAlbum", CreatePhotoAlbum),
191 DECLARE_NAPI_FUNCTION("deleteAlbums", DeletePhotoAlbums),
192 DECLARE_NAPI_FUNCTION("getAlbums", GetPhotoAlbums),
193 DECLARE_NAPI_FUNCTION("getPhotoIndex", JSGetPhotoIndex),
194 }
195 };
196 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
197
198 const vector<napi_property_descriptor> staticProps = {
199 DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
200 DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgrAsync", GetUserFileMgrAsync),
201 DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
202 DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
203 DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
204 DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
205 DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
206 DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
207 DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
208 DECLARE_NAPI_PROPERTY("AlbumSubType", CreateAlbumSubTypeEnum(env)),
209 DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
210 DECLARE_NAPI_PROPERTY("PhotoSubType", CreatePhotoSubTypeEnum(env)),
211 DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
212 DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env))
213 };
214 MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
215 return exports;
216 }
217
PhotoAccessHelperInit(napi_env env,napi_value exports)218 napi_value MediaLibraryNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
219 {
220 NapiClassInfo info = {
221 PHOTOACCESSHELPER_NAPI_CLASS_NAME,
222 &photoAccessHelperConstructor_,
223 MediaLibraryNapiConstructor,
224 {
225 DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
226 DECLARE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
227 DECLARE_NAPI_FUNCTION("registerChange", PhotoAccessHelperOnCallback),
228 DECLARE_NAPI_FUNCTION("unRegisterChange", PhotoAccessHelperOffCallback),
229 DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperTrashAsset),
230 DECLARE_NAPI_FUNCTION("release", JSRelease),
231 DECLARE_NAPI_FUNCTION("createAlbum", PhotoAccessCreatePhotoAlbum),
232 DECLARE_NAPI_FUNCTION("deleteAlbums", PhotoAccessDeletePhotoAlbums),
233 DECLARE_NAPI_FUNCTION("getAlbums", PhotoAccessGetPhotoAlbums),
234 DECLARE_NAPI_FUNCTION("getPhotoIndex", PhotoAccessGetPhotoIndex),
235 }
236 };
237 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
238
239 const vector<napi_property_descriptor> staticProps = {
240 DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
241 DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelperAsync", GetPhotoAccessHelperAsync),
242 DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
243 DECLARE_NAPI_PROPERTY("AlbumKeys", CreateAlbumKeyEnum(env)),
244 DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
245 DECLARE_NAPI_PROPERTY("PhotoKeys", CreatePhotoKeysEnum(env)),
246 DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
247 DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
248 DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
249 DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
250 DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env))
251 };
252 MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
253 return exports;
254 }
255
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)256 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
257 {
258 isAsync = false;
259 size_t argc = ARGS_TWO;
260 napi_value argv[ARGS_TWO] = {0};
261 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
262 if (status != napi_ok) {
263 NAPI_ERR_LOG("Error while obtaining js environment information");
264 return status;
265 }
266
267 if (argc == ARGS_ONE) {
268 return napi_ok;
269 } else if (argc == ARGS_TWO) {
270 napi_valuetype valueType = napi_undefined;
271 status = napi_typeof(env, argv[ARGS_ONE], &valueType);
272 if (status != napi_ok) {
273 NAPI_ERR_LOG("Error while obtaining js environment information");
274 return status;
275 }
276 if (valueType == napi_boolean) {
277 isAsync = true;
278 }
279 status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
280 return status;
281 } else {
282 NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
283 return napi_invalid_arg;
284 }
285 }
286
287 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)288 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
289 {
290 napi_status status;
291 napi_value result = nullptr;
292 napi_value thisVar = nullptr;
293 MediaLibraryTracer tracer;
294
295 tracer.Start("MediaLibraryNapiConstructor");
296
297 NAPI_CALL(env, napi_get_undefined(env, &result));
298 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
299 if (status != napi_ok || thisVar == nullptr) {
300 NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
301 return result;
302 }
303
304 unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
305 if (obj == nullptr) {
306 return result;
307 }
308 obj->env_ = env;
309 // Initialize the ChangeListener object
310 if (g_listObj == nullptr) {
311 g_listObj = make_unique<ChangeListenerNapi>(env);
312 }
313
314 bool isAsync = false;
315 NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
316 if (!isAsync) {
317 unique_lock<mutex> helperLock(sUserFileClientMutex_);
318 if (!UserFileClient::IsValid()) {
319 UserFileClient::Init(env, info);
320 if (!UserFileClient::IsValid()) {
321 NAPI_ERR_LOG("UserFileClient creation failed");
322 return result;
323 }
324 }
325 helperLock.unlock();
326 }
327
328 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
329 MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
330 if (status == napi_ok) {
331 obj.release();
332 return thisVar;
333 } else {
334 NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
335 }
336
337 return result;
338 }
339
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid)340 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid)
341 {
342 napi_value propertyNames;
343 uint32_t propertyLength;
344 napi_valuetype valueType = napi_undefined;
345 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
346 if (valueType != napi_object) {
347 return false;
348 }
349
350 NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
351 NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
352 if (propertyLength == 0) {
353 return false;
354 }
355 if (checkIsValid && (!UserFileClient::IsValid())) {
356 NAPI_ERR_LOG("UserFileClient is not valid");
357 return false;
358 }
359 return true;
360 }
361
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)362 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
363 bool isAsync = false)
364 {
365 constexpr size_t ARG_CONTEXT = 1;
366 size_t argc = ARG_CONTEXT;
367 napi_value argv[ARGS_TWO] = {0};
368
369 napi_value thisVar = nullptr;
370 napi_value ctor = nullptr;
371 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
372 NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
373
374 if (isAsync) {
375 argc = ARGS_TWO;
376 NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
377 argv[ARGS_ONE] = argv[ARG_CONTEXT];
378 }
379
380 napi_value result = nullptr;
381 NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
382 if (!CheckWhetherInitSuccess(env, result, !isAsync)) {
383 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
384 NAPI_CALL(env, napi_get_undefined(env, &result));
385 }
386 return result;
387 }
388
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)389 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
390 {
391 MediaLibraryTracer tracer;
392 tracer.Start("getMediaLibrary");
393
394 napi_value result = nullptr;
395 napi_value ctor;
396 size_t argc = ARGS_ONE;
397 napi_value argv[ARGS_ONE] = {0};
398 napi_value thisVar = nullptr;
399 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
400 napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
401 if (status == napi_ok) {
402 status = napi_new_instance(env, ctor, argc, argv, &result);
403 if (status == napi_ok) {
404 if (CheckWhetherInitSuccess(env, result, true)) {
405 return result;
406 } else {
407 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
408 }
409 } else {
410 NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
411 }
412 } else {
413 NAPI_ERR_LOG("status = %{public}d", status);
414 }
415
416 napi_get_undefined(env, &result);
417 return result;
418 }
419
GetMediaLibraryAsyncExecute(napi_env env,void * data)420 static void GetMediaLibraryAsyncExecute(napi_env env, void *data)
421 {
422 MediaLibraryTracer tracer;
423 tracer.Start("GetMediaLibraryAsyncExecute");
424
425 MediaLibraryInitContext *asyncContext = static_cast<MediaLibraryInitContext *>(data);
426 if (asyncContext == nullptr) {
427 NAPI_ERR_LOG("Async context is null");
428 asyncContext->error = ERR_INVALID_OUTPUT;
429 return;
430 }
431
432 asyncContext->error = ERR_DEFAULT;
433 unique_lock<mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
434 if (!UserFileClient::IsValid()) {
435 UserFileClient::Init(asyncContext->token_, true);
436 if (!UserFileClient::IsValid()) {
437 NAPI_ERR_LOG("UserFileClient creation failed");
438 asyncContext->error = ERR_INVALID_OUTPUT;
439 return;
440 }
441 }
442 helperLock.unlock();
443 }
444
GetMediaLibraryAsyncComplete(napi_env env,napi_status status,void * data)445 static void GetMediaLibraryAsyncComplete(napi_env env, napi_status status, void *data)
446 {
447 MediaLibraryInitContext *context = static_cast<MediaLibraryInitContext *>(data);
448 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
449 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
450 jsContext->status = false;
451
452 napi_value result = nullptr;
453 if (napi_get_reference_value(env, context->resultRef_, &result) != napi_ok) {
454 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
455 "Get result from context ref failed");
456 }
457 napi_valuetype valueType;
458 if (napi_typeof(env, result, &valueType) != napi_ok || valueType != napi_object) {
459 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
460 "Get result type failed " + to_string((int) valueType));
461 }
462
463 if (context->error == ERR_DEFAULT) {
464 jsContext->data = result;
465 jsContext->status = true;
466 napi_get_undefined(env, &jsContext->error);
467 } else {
468 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
469 "Failed to get MediaLibrary");
470 napi_get_undefined(env, &jsContext->data);
471 }
472
473 if (context->work != nullptr) {
474 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
475 context->work, *jsContext);
476 }
477 napi_delete_reference(env, context->resultRef_);
478 delete context;
479 }
480
GetMediaLibraryNewInstanceAsync(napi_env env,napi_callback_info info)481 napi_value MediaLibraryNapi::GetMediaLibraryNewInstanceAsync(napi_env env, napi_callback_info info)
482 {
483 MediaLibraryTracer tracer;
484 tracer.Start("getMediaLibraryAsync");
485
486 unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
487 if (asyncContext == nullptr) {
488 NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
489 return nullptr;
490 }
491 asyncContext->argc = ARGS_TWO;
492 napi_value thisVar = nullptr;
493 NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
494 &thisVar, nullptr));
495
496 napi_value result = CreateNewInstance(env, info, sConstructor_, true);
497 napi_valuetype valueType;
498 NAPI_CALL(env, napi_typeof(env, result, &valueType));
499 if (valueType == napi_undefined) {
500 NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
501 return nullptr;
502 }
503 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
504 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
505
506 bool isStage = false;
507 NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
508 if (isStage) {
509 asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
510 } else {
511 asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
512 }
513
514 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
515 GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
516 }
517
GetUserFileMgr(napi_env env,napi_callback_info info)518 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
519 {
520 MediaLibraryTracer tracer;
521 tracer.Start("getUserFileManager");
522
523 if (!MediaLibraryNapiUtils::IsSystemApp()) {
524 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
525 return nullptr;
526 }
527
528 return CreateNewInstance(env, info, userFileMgrConstructor_);
529 }
530
GetUserFileMgrAsync(napi_env env,napi_callback_info info)531 napi_value MediaLibraryNapi::GetUserFileMgrAsync(napi_env env, napi_callback_info info)
532 {
533 MediaLibraryTracer tracer;
534 tracer.Start("getUserFileManagerAsync");
535
536 if (!MediaLibraryNapiUtils::IsSystemApp()) {
537 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
538 return nullptr;
539 }
540
541 unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
542 if (asyncContext == nullptr) {
543 NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
544 return nullptr;
545 }
546 asyncContext->argc = ARGS_TWO;
547 napi_value thisVar = nullptr;
548 NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
549 &thisVar, nullptr));
550
551 napi_value result = CreateNewInstance(env, info, userFileMgrConstructor_, true);
552 napi_valuetype valueType;
553 NAPI_CALL(env, napi_typeof(env, result, &valueType));
554 if (valueType == napi_undefined) {
555 NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
556 return nullptr;
557 }
558 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
559 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
560
561 bool isStage = false;
562 NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
563 if (isStage) {
564 asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
565 } else {
566 asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
567 }
568
569 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
570 GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
571 }
572
GetPhotoAccessHelper(napi_env env,napi_callback_info info)573 napi_value MediaLibraryNapi::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
574 {
575 MediaLibraryTracer tracer;
576 tracer.Start("GetPhotoAccessHelper");
577
578 return CreateNewInstance(env, info, photoAccessHelperConstructor_);
579 }
580
GetPhotoAccessHelperAsync(napi_env env,napi_callback_info info)581 napi_value MediaLibraryNapi::GetPhotoAccessHelperAsync(napi_env env, napi_callback_info info)
582 {
583 MediaLibraryTracer tracer;
584 tracer.Start("GetPhotoAccessHelperAsync");
585
586 unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
587 if (asyncContext == nullptr) {
588 NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
589 return nullptr;
590 }
591 asyncContext->argc = ARGS_TWO;
592 napi_value thisVar = nullptr;
593 NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
594 &thisVar, nullptr));
595
596 napi_value result = CreateNewInstance(env, info, photoAccessHelperConstructor_, true);
597 napi_valuetype valueType;
598 NAPI_CALL(env, napi_typeof(env, result, &valueType));
599 if (valueType == napi_undefined) {
600 NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
601 return nullptr;
602 }
603 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
604 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
605
606 bool isStage = false;
607 NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
608 if (isStage) {
609 asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
610 } else {
611 asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
612 }
613
614 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAccessHelperAsync",
615 GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
616 }
617
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)618 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
619 const string &name, int32_t enumValue)
620 {
621 napi_value enumNapiValue;
622 napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
623 if (status == napi_ok) {
624 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
625 }
626 return status;
627 }
628
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)629 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
630 {
631 napi_value result = nullptr;
632 NAPI_CALL(env, napi_create_object(env, &result));
633 for (size_t i = 0; i < properties.size(); i++) {
634 NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], i + offset));
635 }
636 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
637 return result;
638 }
639
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)640 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
641 const string &name, string enumValue)
642 {
643 napi_value enumNapiValue;
644 napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
645 if (status == napi_ok) {
646 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
647 }
648 return status;
649 }
650
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)651 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
652 {
653 napi_value result = nullptr;
654 NAPI_CALL(env, napi_create_object(env, &result));
655 for (unsigned int i = 0; i < properties.size(); i++) {
656 NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
657 }
658 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
659 return result;
660 }
661
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)662 static void DealWithCommonParam(napi_env env, napi_value arg,
663 const MediaLibraryAsyncContext &context, bool &err, bool &present)
664 {
665 MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
666 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
667 char buffer[PATH_MAX];
668 size_t res = 0;
669 napi_value property = nullptr;
670 napi_has_named_property(env, arg, "selections", &present);
671 if (present) {
672 if ((napi_get_named_property(env, arg, "selections", &property) != napi_ok) ||
673 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
674 NAPI_ERR_LOG("Could not get the string argument!");
675 err = true;
676 return;
677 } else {
678 asyncContext->selection = buffer;
679 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
680 }
681 present = false;
682 }
683
684 napi_has_named_property(env, arg, "order", &present);
685 if (present) {
686 if ((napi_get_named_property(env, arg, "order", &property) != napi_ok) ||
687 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
688 NAPI_ERR_LOG("Could not get the string argument!");
689 err = true;
690 return;
691 } else {
692 asyncContext->order = buffer;
693 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
694 }
695 present = false;
696 }
697
698 napi_has_named_property(env, arg, "uri", &present);
699 if (present) {
700 if ((napi_get_named_property(env, arg, "uri", &property) != napi_ok)||
701 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
702 NAPI_ERR_LOG("Could not get the uri property!");
703 err = true;
704 return;
705 }
706 asyncContext->uri = buffer;
707 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
708 present = false;
709 }
710
711 napi_has_named_property(env, arg, "networkId", &present);
712 if (present) {
713 if ((napi_get_named_property(env, arg, "networkId", &property) != napi_ok) ||
714 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
715 NAPI_ERR_LOG("Could not get the networkId string argument!");
716 err = true;
717 return;
718 } else {
719 asyncContext->networkId = buffer;
720 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
721 }
722 present = false;
723 }
724 napi_has_named_property(env, arg, "extendArgs", &present);
725 if (present) {
726 if ((napi_get_named_property(env, arg, "extendArgs", &property) != napi_ok) ||
727 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
728 NAPI_ERR_LOG("Could not get the extendArgs string argument!");
729 err = true;
730 return;
731 } else {
732 asyncContext->extendArgs = buffer;
733 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
734 }
735 present = false;
736 }
737 }
738
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)739 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
740 {
741 MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
742 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
743 napi_value property = nullptr;
744 napi_value stringItem = nullptr;
745 bool present = false;
746 DealWithCommonParam(env, arg, context, err, present);
747 napi_has_named_property(env, arg, "selectionArgs", &present);
748 if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
749 uint32_t len = 0;
750 napi_get_array_length(env, property, &len);
751 char buffer[PATH_MAX];
752 for (size_t i = 0; i < len; i++) {
753 napi_get_element(env, property, i, &stringItem);
754 size_t res = 0;
755 napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
756 asyncContext->selectionArgs.push_back(string(buffer));
757 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
758 }
759 } else {
760 NAPI_ERR_LOG("Could not get the string argument!");
761 err = true;
762 }
763 }
764
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)765 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
766 MediaLibraryAsyncContext &asyncContext)
767 {
768 bool err = false;
769 const int32_t refCount = 1;
770 auto context = &asyncContext;
771
772 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
773 for (size_t i = PARAM0; i < argc; i++) {
774 napi_valuetype valueType = napi_undefined;
775 napi_typeof(env, argv[i], &valueType);
776
777 if (i == PARAM0 && valueType == napi_object) {
778 GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
779 } else if (i == PARAM0 && valueType == napi_function) {
780 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
781 break;
782 } else if (i == PARAM1 && valueType == napi_function) {
783 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
784 break;
785 } else {
786 NAPI_ASSERT(env, false, "type mismatch");
787 }
788 if (err) {
789 NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
790 NAPI_ASSERT(env, false, "type mismatch");
791 }
792 }
793
794 // Return true napi_value if params are successfully obtained
795 napi_value result;
796 napi_get_boolean(env, true, &result);
797 return result;
798 }
799
GetPublicDirectoryExecute(napi_env env,void * data)800 static void GetPublicDirectoryExecute(napi_env env, void *data)
801 {
802 MediaLibraryTracer tracer;
803 tracer.Start("GetPublicDirectoryExecute");
804
805 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
806 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
807
808 vector<string> selectionArgs;
809 vector<string> columns;
810 DataSharePredicates predicates;
811 selectionArgs.push_back(to_string(context->dirType));
812 predicates.SetWhereClause(DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
813 predicates.SetWhereArgs(selectionArgs);
814 string queryUri = MEDIALIBRARY_DIRECTORY_URI;
815 Uri uri(queryUri);
816 int errCode = 0;
817 shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
818 if (resultSet != nullptr) {
819 auto count = 0;
820 auto ret = resultSet->GetRowCount(count);
821 if (ret != NativeRdb::E_OK) {
822 NAPI_ERR_LOG("get rdbstore failed");
823 context->error = JS_INNER_FAIL;
824 return;
825 }
826 if (count == 0) {
827 NAPI_ERR_LOG("Query for get publicDirectory form db failed");
828 context->error = JS_INNER_FAIL;
829 return;
830 }
831 NAPI_INFO_LOG("Query for get publicDirectory count = %{private}d", count);
832 if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
833 context->directoryRelativePath = get<string>(
834 ResultSetUtils::GetValFromColumn(DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
835 }
836 return;
837 } else {
838 context->SaveError(errCode);
839 NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
840 }
841 }
842
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)843 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
844 {
845 MediaLibraryTracer tracer;
846 tracer.Start("GetPublicDirectoryCallbackComplete");
847
848 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
849 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
850 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
851 jsContext->status = false;
852 if (context->error == ERR_DEFAULT) {
853 napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
854 jsContext->status = true;
855 napi_get_undefined(env, &jsContext->error);
856 } else {
857 context->HandleError(env, jsContext->error);
858 napi_get_undefined(env, &jsContext->data);
859 }
860
861 tracer.Finish();
862 if (context->work != nullptr) {
863 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
864 context->work, *jsContext);
865 }
866
867 delete context;
868 }
869
JSGetPublicDirectory(napi_env env,napi_callback_info info)870 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
871 {
872 napi_status status;
873 napi_value result = nullptr;
874 size_t argc = ARGS_TWO;
875 napi_value argv[ARGS_TWO] = {0};
876 napi_value thisVar = nullptr;
877 const int32_t refCount = 1;
878
879 MediaLibraryTracer tracer;
880 tracer.Start("JSGetPublicDirectory");
881
882 GET_JS_ARGS(env, info, argc, argv, thisVar);
883 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
884 napi_get_undefined(env, &result);
885
886 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
887 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
888 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
889 for (size_t i = PARAM0; i < argc; i++) {
890 napi_valuetype valueType = napi_undefined;
891 napi_typeof(env, argv[i], &valueType);
892
893 if (i == PARAM0 && valueType == napi_number) {
894 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
895 } else if (i == PARAM1 && valueType == napi_function) {
896 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
897 break;
898 } else {
899 NAPI_ASSERT(env, false, "type mismatch");
900 }
901 }
902 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
903 GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
904 }
905
906 return result;
907 }
908
909 #ifdef MEDIALIBRARY_COMPATIBILITY
GetVirtualIdFromApi10Uri(const string & uri)910 static string GetVirtualIdFromApi10Uri(const string &uri)
911 {
912 string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(uri);
913 if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
914 return fileId;
915 }
916 int32_t id = stoi(fileId);
917 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
918 return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE));
919 } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
920 return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO));
921 } else {
922 return fileId;
923 }
924 }
925 #endif
926
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)927 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
928 {
929 if (!context->uri.empty()) {
930 NAPI_ERR_LOG("context->uri is = %{public}s", context->uri.c_str());
931 context->networkId = MediaLibraryDataManagerUtils::GetNetworkIdFromUri(context->uri);
932 #ifdef MEDIALIBRARY_COMPATIBILITY
933 string fileId = GetVirtualIdFromApi10Uri(context->uri);
934 #else
935 string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(context->uri);
936 #endif
937 if (!fileId.empty()) {
938 string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
939 #ifdef MEDIALIBRARY_COMPATIBILITY
940 context->selection = idPrefix;
941 context->selectionArgs.clear();
942 context->selectionArgs.emplace_back(fileId);
943 #else
944 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
945 context->selectionArgs.emplace_back(fileId);
946 #endif
947 }
948 }
949
950 #ifdef MEDIALIBRARY_COMPATIBILITY
951 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, MediaColumn::ASSETS_QUERY_FILTER);
952 #else
953 string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
954 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
955 context->selectionArgs.emplace_back("0");
956 #endif
957 string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
958 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
959 context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
960 }
961
GetFileAssetsExecute(napi_env env,void * data)962 static void GetFileAssetsExecute(napi_env env, void *data)
963 {
964 MediaLibraryTracer tracer;
965 tracer.Start("GetFileAssetsExecute");
966
967 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
968 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
969
970 GetFileAssetUpdateSelections(context);
971 context->fetchColumn = FILE_ASSET_COLUMNS;
972 if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
973 string group(" GROUP BY (");
974 group += context->extendArgs + " )";
975 context->selection += group;
976 context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
977 }
978
979 context->predicates.SetWhereClause(context->selection);
980 context->predicates.SetWhereArgs(context->selectionArgs);
981 context->predicates.SetOrder(context->order);
982
983 string queryUri = MEDIALIBRARY_DATA_URI;
984 if (!context->networkId.empty()) {
985 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
986 }
987 Uri uri(queryUri);
988 int errCode = 0;
989 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
990 context->predicates, context->fetchColumn, errCode);
991 if (resultSet != nullptr) {
992 // Create FetchResult object using the contents of resultSet
993 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
994 context->fetchFileResult->SetNetworkId(context->networkId);
995 return;
996 } else {
997 context->SaveError(errCode);
998 NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
999 }
1000 }
1001
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1002 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
1003 unique_ptr<JSAsyncContextOutput> &jsContext)
1004 {
1005 // Create FetchResult object using the contents of resultSet
1006 if (context->fetchFileResult == nullptr) {
1007 NAPI_ERR_LOG("No fetch file result found!");
1008 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1009 "Failed to obtain Fetch File Result");
1010 return;
1011 }
1012 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
1013 if (fileResult == nullptr) {
1014 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1015 "Failed to create js object for Fetch File Result");
1016 } else {
1017 jsContext->data = fileResult;
1018 jsContext->status = true;
1019 napi_get_undefined(env, &jsContext->error);
1020 }
1021 }
1022
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1023 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1024 {
1025 MediaLibraryTracer tracer;
1026 tracer.Start("GetFileAssetsAsyncCallbackComplete");
1027
1028 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1029 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1030
1031 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1032 jsContext->status = false;
1033 napi_get_undefined(env, &jsContext->data);
1034
1035 if (context->error != ERR_DEFAULT) {
1036 context->HandleError(env, jsContext->error);
1037 } else {
1038 GetNapiFileResult(env, context, jsContext);
1039 }
1040
1041 tracer.Finish();
1042 if (context->work != nullptr) {
1043 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1044 context->work, *jsContext);
1045 }
1046 delete context;
1047 }
1048
JSGetFileAssets(napi_env env,napi_callback_info info)1049 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
1050 {
1051 napi_status status;
1052 napi_value result = nullptr;
1053 size_t argc = ARGS_TWO;
1054 napi_value argv[ARGS_TWO] = {0};
1055 napi_value thisVar = nullptr;
1056
1057 MediaLibraryTracer tracer;
1058 tracer.Start("JSGetFileAssets");
1059
1060 GET_JS_ARGS(env, info, argc, argv, thisVar);
1061 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1062 napi_get_undefined(env, &result);
1063
1064 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1065 asyncContext->mediaTypes.clear();
1066 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1067 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1068 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1069 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1070 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1071
1072 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
1073 GetFileAssetsAsyncCallbackComplete);
1074 }
1075
1076 return result;
1077 }
1078
1079 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatSetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1080 static void CompatSetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1081 {
1082 MediaLibraryTracer tracer;
1083 tracer.Start("CompatSetAlbumCoverUri");
1084 DataSharePredicates predicates;
1085 int err;
1086 if (album->GetAlbumType() == PhotoAlbumType::USER) {
1087 err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates);
1088 } else {
1089 err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates);
1090 }
1091 if (err < 0) {
1092 NAPI_WARN_LOG("Failed to set cover uri for album subtype: %{public}d", album->GetAlbumSubType());
1093 return;
1094 }
1095 predicates.OrderByDesc(MediaColumn::MEDIA_DATE_ADDED);
1096 predicates.Limit(1, 0);
1097
1098 Uri uri(URI_QUERY_PHOTO_MAP);
1099 vector<string> columns;
1100 columns.assign(MediaColumn::DEFAULT_FETCH_COLUMNS.begin(), MediaColumn::DEFAULT_FETCH_COLUMNS.end());
1101 auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1102 if (resultSet == nullptr) {
1103 NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", err);
1104 context->SaveError(err);
1105 return;
1106 }
1107 auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1108 if (fetchResult->GetCount() == 0) {
1109 return;
1110 }
1111 auto fileAsset = fetchResult->GetFirstObject();
1112 if (fileAsset == nullptr) {
1113 NAPI_WARN_LOG("Failed to get cover asset!");
1114 return;
1115 }
1116 album->SetCoverUri(fileAsset->GetUri());
1117 }
1118
SetCompatAlbumName(AlbumAsset * albumData)1119 static void SetCompatAlbumName(AlbumAsset *albumData)
1120 {
1121 string albumName;
1122 switch (albumData->GetAlbumSubType()) {
1123 case PhotoAlbumSubType::CAMERA:
1124 albumName = CAMERA_ALBUM_NAME;
1125 break;
1126 case PhotoAlbumSubType::SCREENSHOT:
1127 albumName = SCREEN_SHOT_ALBUM_NAME;
1128 break;
1129 default:
1130 NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
1131 }
1132 albumData->SetAlbumName(albumName);
1133 }
1134
CompatSetAlbumCount(unique_ptr<AlbumAsset> & album)1135 static void CompatSetAlbumCount(unique_ptr<AlbumAsset> &album)
1136 {
1137 MediaLibraryTracer tracer;
1138 tracer.Start("CompatSetAlbumCount");
1139 DataSharePredicates predicates;
1140 int err;
1141 if (album->GetAlbumType() == PhotoAlbumType::USER) {
1142 err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates);
1143 } else {
1144 err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates);
1145 }
1146 if (err < 0) {
1147 NAPI_WARN_LOG("Failed to set count for album subtype: %{public}d", album->GetAlbumSubType());
1148 album->SetCount(0);
1149 return;
1150 }
1151
1152 Uri uri(URI_QUERY_PHOTO_MAP);
1153 vector<string> columns;
1154 auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1155 if (resultSet == nullptr) {
1156 NAPI_WARN_LOG("Query for assets failed! errorCode is = %{public}d", err);
1157 album->SetCount(0);
1158 return;
1159 }
1160 auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1161 int32_t count = fetchResult->GetCount();
1162 album->SetCount(count);
1163 }
1164 #else
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1165 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1166 {
1167 MediaLibraryTracer tracer;
1168 tracer.Start("SetAlbumCoverUri");
1169 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1170 DataShare::DataSharePredicates predicates;
1171 predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
1172 predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
1173 predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
1174 vector<string> columns;
1175 string queryUri = MEDIALIBRARY_DATA_URI;
1176 if (!context->networkId.empty()) {
1177 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1178 NAPI_DEBUG_LOG("querycoverUri is = %{public}s", queryUri.c_str());
1179 }
1180 Uri uri(queryUri);
1181 int errCode = 0;
1182 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
1183 uri, predicates, columns, errCode);
1184 if (resultSet == nullptr) {
1185 NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
1186 return;
1187 }
1188 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1189 fetchFileResult->SetNetworkId(context->networkId);
1190 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1191 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
1192 string coverUri = fileAsset->GetUri();
1193 album->SetCoverUri(coverUri);
1194 NAPI_DEBUG_LOG("coverUri is = %{public}s", album->GetCoverUri().c_str());
1195 }
1196 #endif
1197
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)1198 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1199 const string &networkId)
1200 {
1201 #ifdef MEDIALIBRARY_COMPATIBILITY
1202 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
1203 TYPE_INT32)));
1204 albumData->SetAlbumType(static_cast<PhotoAlbumType>(
1205 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
1206 albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
1207 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
1208 SetCompatAlbumName(albumData);
1209 #else
1210 // Get album id index and value
1211 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
1212 TYPE_INT32)));
1213
1214 // Get album title index and value
1215 albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
1216 TYPE_STRING)));
1217 #endif
1218
1219 // Get album asset count index and value
1220 albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
1221 MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
1222 MEDIA_API_VERSION_DEFAULT);
1223 albumData->SetAlbumUri(fileUri.ToString());
1224 // Get album relativePath index and value
1225 albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
1226 resultSet, TYPE_STRING)));
1227 albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
1228 resultSet, TYPE_INT64)));
1229 }
1230
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)1231 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
1232 {
1233 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1234 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1235 context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
1236 context->fetchAlbumResult->SetNetworkId(context->networkId);
1237 context->fetchAlbumResult->SetResultNapiType(context->resultNapiType);
1238 return;
1239 }
1240
1241 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1242 unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
1243 if (albumData != nullptr) {
1244 SetAlbumData(albumData.get(), resultSet, context->networkId);
1245 #ifdef MEDIALIBRARY_COMPATIBILITY
1246 CompatSetAlbumCoverUri(context, albumData);
1247 CompatSetAlbumCount(albumData);
1248 #else
1249 SetAlbumCoverUri(context, albumData);
1250 #endif
1251 context->albumNativeArray.push_back(move(albumData));
1252 } else {
1253 context->SaveError(E_NO_MEMORY);
1254 }
1255 }
1256 }
1257
1258 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)1259 static void ReplaceAlbumName(const string &arg, string &argInstead)
1260 {
1261 if (arg == CAMERA_ALBUM_NAME) {
1262 argInstead = to_string(PhotoAlbumSubType::CAMERA);
1263 } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
1264 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1265 } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
1266 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1267 } else {
1268 argInstead = arg;
1269 }
1270 }
1271
ReplaceRelativePath(const string & arg,string & argInstead)1272 static bool ReplaceRelativePath(const string &arg, string &argInstead)
1273 {
1274 if (arg == CAMERA_PATH) {
1275 argInstead = to_string(PhotoAlbumSubType::CAMERA);
1276 } else if (arg == SCREEN_SHOT_PATH) {
1277 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1278 } else if (arg == SCREEN_RECORD_PATH) {
1279 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1280 } else if (arg.empty()) {
1281 argInstead = arg;
1282 return false;
1283 } else {
1284 argInstead = arg;
1285 }
1286 return true;
1287 }
1288
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead)1289 static void ReplaceSelection(string &selection, vector<string> &selectionArgs,
1290 const string &key, const string &keyInstead)
1291 {
1292 for (size_t pos = 0; pos != string::npos;) {
1293 pos = selection.find(key, pos);
1294 if (pos == string::npos) {
1295 break;
1296 }
1297
1298 size_t argPos = selection.find('?', pos);
1299 if (argPos == string::npos) {
1300 break;
1301 }
1302 size_t argIndex = 0;
1303 for (size_t i = 0; i < argPos; i++) {
1304 if (selection[i] == '?') {
1305 argIndex++;
1306 }
1307 }
1308 if (argIndex > selectionArgs.size() - 1) {
1309 NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
1310 selection.c_str());
1311 break;
1312 }
1313 const string &arg = selectionArgs[argIndex];
1314 string argInstead = arg;
1315 if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
1316 bool shouldReplace = true;
1317 shouldReplace = ReplaceRelativePath(arg, argInstead);
1318 if (shouldReplace) {
1319 selection.replace(pos, key.length(), keyInstead);
1320 }
1321 } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
1322 ReplaceAlbumName(arg, argInstead);
1323 selection.replace(pos, key.length(), keyInstead);
1324 } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
1325 selection.replace(pos, key.length(), keyInstead);
1326 }
1327 selectionArgs[argIndex] = argInstead;
1328 argPos = selection.find('?', pos);
1329 if (argPos == string::npos) {
1330 break;
1331 }
1332 pos = argPos + 1;
1333 }
1334 }
1335
UpdateCompatSelection(MediaLibraryAsyncContext * context)1336 static void UpdateCompatSelection(MediaLibraryAsyncContext *context)
1337 {
1338 ReplaceSelection(context->selection, context->selectionArgs, MEDIA_DATA_DB_BUCKET_ID, PhotoAlbumColumns::ALBUM_ID);
1339 ReplaceSelection(context->selection, context->selectionArgs,
1340 MEDIA_DATA_DB_BUCKET_NAME, PhotoAlbumColumns::ALBUM_SUBTYPE);
1341 ReplaceSelection(context->selection, context->selectionArgs,
1342 MEDIA_DATA_DB_RELATIVE_PATH, PhotoAlbumColumns::ALBUM_SUBTYPE);
1343 static const string COMPAT_QUERY_FILTER = PhotoAlbumColumns::ALBUM_SUBTYPE + " IN (" +
1344 to_string(PhotoAlbumSubType::SCREENSHOT) + "," +
1345 to_string(PhotoAlbumSubType::CAMERA) + ")";
1346 if (!context->selection.empty()) {
1347 context->selection = COMPAT_QUERY_FILTER + " AND " + context->selection;
1348 } else {
1349 context->selection = COMPAT_QUERY_FILTER;
1350 }
1351 }
1352 #endif
1353
GetResultDataExecute(napi_env env,void * data)1354 static void GetResultDataExecute(napi_env env, void *data)
1355 {
1356 MediaLibraryTracer tracer;
1357 tracer.Start("GetResultDataExecute");
1358
1359 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1360
1361 #ifdef MEDIALIBRARY_COMPATIBILITY
1362 UpdateCompatSelection(context);
1363 #else
1364 MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
1365 #endif
1366 context->predicates.SetWhereClause(context->selection);
1367 context->predicates.SetWhereArgs(context->selectionArgs);
1368 if (!context->order.empty()) {
1369 context->predicates.SetOrder(context->order);
1370 }
1371
1372 #ifdef MEDIALIBRARY_COMPATIBILITY
1373 vector<string> columns;
1374 const set<string> &defaultFetchCols = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
1375 columns.assign(defaultFetchCols.begin(), defaultFetchCols.end());
1376 columns.push_back(PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
1377 #else
1378 vector<string> columns;
1379 #endif
1380 string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1381 if (!context->networkId.empty()) {
1382 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
1383 MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1384 NAPI_DEBUG_LOG("queryAlbumUri is = %{public}s", queryUri.c_str());
1385 }
1386 Uri uri(queryUri);
1387 int errCode = 0;
1388 shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode);
1389
1390 if (resultSet == nullptr) {
1391 NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr, errCode is %{public}d", errCode);
1392 context->SaveError(errCode);
1393 return;
1394 }
1395
1396 GetAlbumResult(context, resultSet);
1397 }
1398
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1399 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1400 unique_ptr<JSAsyncContextOutput> &jsContext)
1401 {
1402 if (context->albumNativeArray.empty()) {
1403 napi_value albumNoArray = nullptr;
1404 napi_create_array(env, &albumNoArray);
1405 jsContext->status = true;
1406 napi_get_undefined(env, &jsContext->error);
1407 jsContext->data = albumNoArray;
1408 } else {
1409 napi_value albumArray = nullptr;
1410 napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
1411 for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
1412 napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
1413 napi_set_element(env, albumArray, i, albumNapiObj);
1414 }
1415 jsContext->status = true;
1416 napi_get_undefined(env, &jsContext->error);
1417 jsContext->data = albumArray;
1418 }
1419 }
1420
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1421 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1422 unique_ptr<JSAsyncContextOutput> &jsContext)
1423 {
1424 if (context->fetchAlbumResult->GetCount() < 0) {
1425 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1426 "find no data by options");
1427 } else {
1428 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
1429 if (fileResult == nullptr) {
1430 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1431 "Failed to create js object for Fetch Album Result");
1432 } else {
1433 jsContext->data = fileResult;
1434 jsContext->status = true;
1435 napi_get_undefined(env, &jsContext->error);
1436 }
1437 }
1438 }
1439
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1440 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1441 unique_ptr<JSAsyncContextOutput> &jsContext)
1442 {
1443 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1444 MediaLibAlbumsAsyncResult(env, context, jsContext);
1445 } else {
1446 UserFileMgrAlbumsAsyncResult(env, context, jsContext);
1447 }
1448 }
1449
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1450 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1451 {
1452 MediaLibraryTracer tracer;
1453 tracer.Start("AlbumsAsyncCallbackComplete");
1454
1455 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1456 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1457 jsContext->status = false;
1458 napi_get_undefined(env, &jsContext->error);
1459 if (context->error != ERR_DEFAULT) {
1460 napi_get_undefined(env, &jsContext->data);
1461 context->HandleError(env, jsContext->error);
1462 } else {
1463 AlbumsAsyncResult(env, context, jsContext);
1464 }
1465
1466 tracer.Finish();
1467 if (context->work != nullptr) {
1468 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1469 context->work, *jsContext);
1470 }
1471 delete context;
1472 }
1473
JSGetAlbums(napi_env env,napi_callback_info info)1474 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
1475 {
1476 napi_status status;
1477 napi_value result = nullptr;
1478 size_t argc = ARGS_TWO;
1479 napi_value argv[ARGS_TWO] = {0};
1480 napi_value thisVar = nullptr;
1481
1482 MediaLibraryTracer tracer;
1483 tracer.Start("JSGetAlbums");
1484
1485 GET_JS_ARGS(env, info, argc, argv, thisVar);
1486 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1487 napi_get_undefined(env, &result);
1488
1489 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1490 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1491 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1492 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1493 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1494
1495 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
1496 AlbumsAsyncCallbackComplete);
1497 }
1498
1499 return result;
1500 }
1501
1502 #ifndef MEDIALIBRARY_COMPATIBILITY
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1503 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1504 {
1505 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1506 vector<string> columns;
1507 DataShare::DataSharePredicates predicates;
1508
1509 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1510 predicates.SetWhereArgs({ to_string(id) });
1511
1512 string queryUri = MEDIALIBRARY_DATA_URI;
1513 Uri uri(queryUri);
1514 int errCode = 0;
1515
1516 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
1517 CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
1518
1519 // Create FetchResult object using the contents of resultSet
1520 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1521 CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1522 context->fetchFileResult->SetNetworkId(networkId);
1523 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1524 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1525 context->fetchFileResult->SetResultNapiType(context->resultNapiType);
1526 }
1527 if (context->fetchFileResult->GetCount() < 1) {
1528 NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1529 return;
1530 }
1531 unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1532 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1533 context->fileAsset = move(fileAsset);
1534 }
1535 #endif
1536
1537 #ifdef MEDIALIBRARY_COMPATIBILITY
SetFileAssetByIdV9(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1538 static void SetFileAssetByIdV9(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1539 {
1540 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1541 bool isValid = false;
1542 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1543 if (!isValid) {
1544 NAPI_ERR_LOG("get title is invalid");
1545 return;
1546 }
1547 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1548 if (!isValid) {
1549 NAPI_ERR_LOG("get relativePath is invalid");
1550 return;
1551 }
1552 unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1553 fileAsset->SetId(id);
1554 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1555 string uri;
1556 if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
1557 MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
1558 uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(MediaType::MEDIA_TYPE_FILE,
1559 to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1560 } else {
1561 uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(mediaType,
1562 to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1563 }
1564 fileAsset->SetUri(uri);
1565 fileAsset->SetMediaType(mediaType);
1566 fileAsset->SetDisplayName(displayName);
1567 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1568 fileAsset->SetResultNapiType(ResultNapiType::TYPE_MEDIALIBRARY);
1569 fileAsset->SetRelativePath(relativePath);
1570 context->fileAsset = move(fileAsset);
1571 }
1572 #endif
1573
SetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1574 static void SetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1575 MediaLibraryAsyncContext *context)
1576 {
1577 bool isValid = false;
1578 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1579 if (!isValid) {
1580 NAPI_ERR_LOG("getting title is invalid");
1581 return;
1582 }
1583 unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1584 fileAsset->SetId(id);
1585 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1586 fileAsset->SetUri(uri);
1587 fileAsset->SetMediaType(mediaType);
1588 fileAsset->SetDisplayName(displayName);
1589 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1590 fileAsset->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1591 fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1592 context->fileAsset = move(fileAsset);
1593 }
1594
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1595 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1596 MediaLibraryAsyncContext *context)
1597 {
1598 bool isValid = false;
1599 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1600 if (!isValid) {
1601 NAPI_ERR_LOG("getting title is invalid");
1602 return;
1603 }
1604 auto fileAsset = make_unique<FileAsset>();
1605 fileAsset->SetId(id);
1606 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1607 fileAsset->SetUri(uri);
1608 fileAsset->SetMediaType(mediaType);
1609 fileAsset->SetDisplayName(displayName);
1610 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1611 fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1612 fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1613 context->fileAsset = move(fileAsset);
1614 }
1615
JSCreateUriInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1616 static void JSCreateUriInCallback(napi_env env, MediaLibraryAsyncContext *context,
1617 unique_ptr<JSAsyncContextOutput> &jsContext)
1618 {
1619 napi_value jsObject = nullptr;
1620 if (context->uri.empty()) {
1621 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1622 "Obtain file asset uri failed");
1623 napi_get_undefined(env, &jsContext->data);
1624 } else {
1625 napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1626 if (status != napi_ok || jsObject == nullptr) {
1627 NAPI_ERR_LOG("Failed to get file asset uri napi object");
1628 napi_get_undefined(env, &jsContext->data);
1629 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1630 "Failed to create js object for FileAsset");
1631 } else {
1632 jsContext->data = jsObject;
1633 napi_get_undefined(env, &jsContext->error);
1634 jsContext->status = true;
1635 }
1636 }
1637 }
1638
JSCreateAssetInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1639 static void JSCreateAssetInCallback(napi_env env, MediaLibraryAsyncContext *context,
1640 unique_ptr<JSAsyncContextOutput> &jsContext)
1641 {
1642 napi_value jsFileAsset = nullptr;
1643 if (context->fileAsset == nullptr) {
1644 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1645 "Obtain file asset failed");
1646 napi_get_undefined(env, &jsContext->data);
1647 } else {
1648 jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1649 if (jsFileAsset == nullptr) {
1650 NAPI_ERR_LOG("Failed to get file asset napi object");
1651 napi_get_undefined(env, &jsContext->data);
1652 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1653 "Failed to create js object for FileAsset");
1654 } else {
1655 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1656 jsContext->data = jsFileAsset;
1657 napi_get_undefined(env, &jsContext->error);
1658 jsContext->status = true;
1659 }
1660 }
1661 }
1662
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1663 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1664 {
1665 MediaLibraryTracer tracer;
1666 tracer.Start("JSCreateAssetCompleteCallback");
1667
1668 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
1669 auto jsContext = make_unique<JSAsyncContextOutput>();
1670 jsContext->status = false;
1671
1672 if (context->error == ERR_DEFAULT) {
1673 if (context->isCreateByComponent) {
1674 JSCreateUriInCallback(env, context, jsContext);
1675 } else {
1676 JSCreateAssetInCallback(env, context, jsContext);
1677 }
1678 } else {
1679 context->HandleError(env, jsContext->error);
1680 napi_get_undefined(env, &jsContext->data);
1681 }
1682
1683 tracer.Finish();
1684 if (context->work != nullptr) {
1685 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1686 context->work, *jsContext);
1687 }
1688 delete context;
1689 }
1690
CheckDisplayNameParams(MediaLibraryAsyncContext * context)1691 static bool CheckDisplayNameParams(MediaLibraryAsyncContext *context)
1692 {
1693 if (context == nullptr) {
1694 NAPI_ERR_LOG("Async context is null");
1695 return false;
1696 }
1697 if (!context->isCreateByComponent) {
1698 bool isValid = false;
1699 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1700 if (!isValid) {
1701 NAPI_ERR_LOG("getting displayName is invalid");
1702 return false;
1703 }
1704 if (displayName.empty()) {
1705 return false;
1706 }
1707 }
1708
1709 return true;
1710 }
1711
GetFirstDirName(const string & relativePath)1712 static string GetFirstDirName(const string &relativePath)
1713 {
1714 string firstDirName = "";
1715 if (!relativePath.empty()) {
1716 string::size_type pos = relativePath.find_first_of('/');
1717 if (pos == relativePath.length()) {
1718 return relativePath;
1719 }
1720 firstDirName = relativePath.substr(0, pos + 1);
1721 NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
1722 }
1723 return firstDirName;
1724 }
1725
IsDirectory(const string & dirName)1726 static bool IsDirectory(const string &dirName)
1727 {
1728 struct stat statInfo {};
1729 if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == SUCCESS) {
1730 if (statInfo.st_mode & S_IFDIR) {
1731 return true;
1732 }
1733 }
1734
1735 return false;
1736 }
1737
CheckTypeOfType(const string & firstDirName,int32_t fileMediaType)1738 static bool CheckTypeOfType(const string &firstDirName, int32_t fileMediaType)
1739 {
1740 // "CDSA/"
1741 if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
1742 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1743 return true;
1744 } else {
1745 return false;
1746 }
1747 }
1748 // "Movies/"
1749 if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
1750 if (fileMediaType == MEDIA_TYPE_VIDEO) {
1751 return true;
1752 } else {
1753 return false;
1754 }
1755 }
1756 if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_2].c_str())) {
1757 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1758 return true;
1759 } else {
1760 NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
1761 return false;
1762 }
1763 }
1764 if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_3].c_str())) {
1765 if (fileMediaType == MEDIA_TYPE_AUDIO) {
1766 return true;
1767 } else {
1768 return false;
1769 }
1770 }
1771 return true;
1772 }
CheckRelativePathParams(MediaLibraryAsyncContext * context)1773 static bool CheckRelativePathParams(MediaLibraryAsyncContext *context)
1774 {
1775 if (context == nullptr) {
1776 NAPI_ERR_LOG("Async context is null");
1777 return false;
1778 }
1779 bool isValid = false;
1780 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1781 if (!isValid) {
1782 NAPI_DEBUG_LOG("getting relativePath is invalid");
1783 return false;
1784 }
1785 isValid = false;
1786 int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
1787 if (!isValid) {
1788 NAPI_DEBUG_LOG("getting fileMediaType is invalid");
1789 return false;
1790 }
1791 if (relativePath.empty()) {
1792 return false;
1793 }
1794
1795 if (IsDirectory(relativePath)) {
1796 return true;
1797 }
1798
1799 string firstDirName = GetFirstDirName(relativePath);
1800 if (!firstDirName.empty() && IsDirectory(firstDirName)) {
1801 return true;
1802 }
1803
1804 if (!firstDirName.empty()) {
1805 NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1806 for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
1807 NAPI_DEBUG_LOG("directoryEnumValues%{public}d = %{public}s", i, directoryEnumValues[i].c_str());
1808 if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
1809 return CheckTypeOfType(firstDirName, fileMediaType);
1810 }
1811 }
1812 NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1813 }
1814 return false;
1815 }
1816
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1817 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
1818 MediaLibraryAsyncContext &asyncContext)
1819 {
1820 const int32_t refCount = 1;
1821 napi_value result = nullptr;
1822 auto context = &asyncContext;
1823 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1824 int32_t fileMediaType = 0;
1825 size_t res = 0;
1826 char relativePathBuffer[PATH_MAX];
1827 char titleBuffer[PATH_MAX];
1828 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1829
1830 for (size_t i = PARAM0; i < argc; i++) {
1831 napi_valuetype valueType = napi_undefined;
1832 napi_typeof(env, argv[i], &valueType);
1833 if (i == PARAM0 && valueType == napi_number) {
1834 napi_get_value_int32(env, argv[i], &fileMediaType);
1835 } else if (i == PARAM1 && valueType == napi_string) {
1836 napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
1837 NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
1838 } else if (i == PARAM2 && valueType == napi_string) {
1839 napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
1840 NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
1841 } else if (i == PARAM3 && valueType == napi_function) {
1842 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1843 } else {
1844 NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
1845 return result;
1846 }
1847 }
1848
1849 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
1850 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
1851 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
1852
1853 context->assetType = TYPE_DEFAULT;
1854 if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
1855 context->assetType = TYPE_PHOTO;
1856 } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
1857 context->assetType = TYPE_AUDIO;
1858 }
1859
1860 NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
1861 // Return true napi_value if params are successfully obtained
1862 napi_get_boolean(env, true, &result);
1863 return result;
1864 }
1865
GetCreateUri(MediaLibraryAsyncContext * context,string & uri)1866 static void GetCreateUri(MediaLibraryAsyncContext *context, string &uri)
1867 {
1868 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1869 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1870 switch (context->assetType) {
1871 case TYPE_PHOTO:
1872 uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1873 ((context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO) :
1874 ((context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT : PAH_CREATE_PHOTO);
1875 break;
1876 case TYPE_AUDIO:
1877 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
1878 break;
1879 default:
1880 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
1881 return;
1882 }
1883 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1884 } else {
1885 #ifdef MEDIALIBRARY_COMPATIBILITY
1886 bool isValid = false;
1887 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1888 if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
1889 MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
1890 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1891 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1892 return;
1893 }
1894 switch (context->assetType) {
1895 case TYPE_PHOTO:
1896 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1897 break;
1898 case TYPE_AUDIO:
1899 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1900 break;
1901 case TYPE_DEFAULT:
1902 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1903 break;
1904 default:
1905 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
1906 return;
1907 }
1908 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1909 #else
1910 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1911 #endif
1912 }
1913 }
1914
JSCreateAssetExecute(napi_env env,void * data)1915 static void JSCreateAssetExecute(napi_env env, void *data)
1916 {
1917 MediaLibraryTracer tracer;
1918 tracer.Start("JSCreateAssetExecute");
1919
1920 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
1921 if (!CheckDisplayNameParams(context)) {
1922 context->error = JS_E_DISPLAYNAME;
1923 return;
1924 }
1925 if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathParams(context))) {
1926 context->error = JS_E_RELATIVEPATH;
1927 return;
1928 }
1929
1930 string uri;
1931 GetCreateUri(context, uri);
1932 Uri createFileUri(uri);
1933 string outUri;
1934 int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
1935 if (index < 0) {
1936 context->SaveError(index);
1937 } else {
1938 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1939 if (context->isCreateByComponent) {
1940 context->uri = outUri;
1941 } else {
1942 SetFileAssetByIdV10(index, "", outUri, context);
1943 }
1944 } else {
1945 #ifdef MEDIALIBRARY_COMPATIBILITY
1946 SetFileAssetByIdV9(index, "", context);
1947 #else
1948 getFileAssetById(index, "", context);
1949 #endif
1950 }
1951 }
1952 }
1953
JSCreateAsset(napi_env env,napi_callback_info info)1954 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
1955 {
1956 napi_status status;
1957 napi_value result = nullptr;
1958 size_t argc = ARGS_FOUR;
1959 napi_value argv[ARGS_FOUR] = {0};
1960 napi_value thisVar = nullptr;
1961
1962 MediaLibraryTracer tracer;
1963 tracer.Start("JSCreateAsset");
1964
1965 GET_JS_ARGS(env, info, argc, argv, thisVar);
1966 NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
1967 napi_get_undefined(env, &result);
1968
1969 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1970 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1971 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1972 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1973 result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
1974 ASSERT_NULLPTR_CHECK(env, result);
1975
1976 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
1977 JSCreateAssetCompleteCallback);
1978 }
1979
1980 return result;
1981 }
1982
1983 #ifdef MEDIALIBRARY_COMPATIBILITY
HandleCompatDeletePhoto(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)1984 static void HandleCompatDeletePhoto(MediaLibraryAsyncContext *context,
1985 const string &mediaType, const string &deleteId)
1986 {
1987 Uri uri(URI_DELETE_PHOTOS);
1988 DataSharePredicates predicates;
1989 predicates.In(MediaColumn::MEDIA_ID, vector<string>({ deleteId }));
1990 predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
1991 DataShareValuesBucket valuesBucket;
1992 valuesBucket.Put(MediaColumn::MEDIA_ID, deleteId);
1993 int changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
1994 if (changedRows < 0) {
1995 context->SaveError(changedRows);
1996 return;
1997 }
1998 context->retVal = changedRows;
1999 }
2000
HandleCompatDelete(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2001 static inline void HandleCompatDelete(MediaLibraryAsyncContext *context,
2002 const string &mediaType, const string &deleteId)
2003 {
2004 if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE) {
2005 return HandleCompatDeletePhoto(context, mediaType, deleteId);
2006 }
2007 NAPI_WARN_LOG("Ignore unsupported media type deletion: %{public}s", mediaType.c_str());
2008 }
2009 #endif
2010
JSDeleteAssetExecute(napi_env env,void * data)2011 static void JSDeleteAssetExecute(napi_env env, void *data)
2012 {
2013 MediaLibraryTracer tracer;
2014 tracer.Start("JSDeleteAssetExecute");
2015
2016 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2017 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2018
2019 string mediaType, deleteId;
2020 bool isValid = false;
2021 string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2022 if (!isValid) {
2023 context->error = ERR_INVALID_OUTPUT;
2024 return;
2025 }
2026 #ifdef MEDIALIBRARY_COMPATIBILITY
2027 notifyUri = MediaFileUtils::GetRealUriFromVirtualUri(notifyUri);
2028 #endif
2029 size_t index = notifyUri.rfind('/');
2030 if (index != string::npos) {
2031 deleteId = notifyUri.substr(index + 1);
2032 notifyUri = notifyUri.substr(0, index);
2033 size_t indexType = notifyUri.rfind('/');
2034 if (indexType != string::npos) {
2035 mediaType = notifyUri.substr(indexType + 1);
2036 }
2037 }
2038 if (MediaFileUtils::IsUriV10(mediaType)) {
2039 NAPI_ERR_LOG("Unsupported media type: %{public}s", mediaType.c_str());
2040 context->SaveError(E_INVALID_URI);
2041 return;
2042 }
2043 #ifdef MEDIALIBRARY_COMPATIBILITY
2044 if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE || mediaType == AUDIO_ASSET_TYPE) {
2045 return HandleCompatDelete(context, mediaType, deleteId);
2046 }
2047 #endif
2048 notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
2049 string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET;
2050 Uri deleteAssetUri(deleteUri);
2051 DataSharePredicates predicates;
2052 predicates.EqualTo(MEDIA_DATA_DB_ID, deleteId);
2053 int retVal = UserFileClient::Delete(deleteAssetUri, predicates);
2054 if (retVal < 0) {
2055 context->SaveError(retVal);
2056 } else {
2057 context->retVal = retVal;
2058 Uri deleteNotify(notifyUri);
2059 UserFileClient::NotifyChange(deleteNotify);
2060 }
2061 }
2062
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)2063 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
2064 {
2065 MediaLibraryTracer tracer;
2066 tracer.Start("JSDeleteAssetCompleteCallback");
2067
2068 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2069 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2070 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2071 jsContext->status = false;
2072
2073 if (context->error == ERR_DEFAULT) {
2074 NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
2075 napi_create_int32(env, context->retVal, &jsContext->data);
2076 napi_get_undefined(env, &jsContext->error);
2077 jsContext->status = true;
2078 } else {
2079 context->HandleError(env, jsContext->error);
2080 napi_get_undefined(env, &jsContext->data);
2081 }
2082
2083 tracer.Finish();
2084 if (context->work != nullptr) {
2085 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2086 context->work, *jsContext);
2087 }
2088
2089 delete context;
2090 }
2091
JSTrashAssetExecute(napi_env env,void * data)2092 static void JSTrashAssetExecute(napi_env env, void *data)
2093 {
2094 MediaLibraryTracer tracer;
2095 tracer.Start("JSTrashAssetExecute");
2096
2097 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2098 string uri = context->uri;
2099 if (uri.empty()) {
2100 context->error = ERR_INVALID_OUTPUT;
2101 return;
2102 }
2103 MediaFileUri::RemoveAllFragment(uri);
2104 string trashId = MediaFileUtils::GetIdFromUri(uri);
2105 string trashUri;
2106 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
2107 trashUri = UFM_UPDATE_PHOTO;
2108 } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
2109 trashUri = UFM_UPDATE_AUDIO;
2110 } else {
2111 context->error = E_VIOLATION_PARAMETERS;
2112 return;
2113 }
2114 MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2115 Uri updateAssetUri(trashUri);
2116 DataSharePredicates predicates;
2117 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2118 predicates.SetWhereArgs({ trashId });
2119 DataShareValuesBucket valuesBucket;
2120 valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
2121 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2122 if (changedRows < 0) {
2123 context->SaveError(changedRows);
2124 NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
2125 }
2126 }
2127
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)2128 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
2129 {
2130 MediaLibraryTracer tracer;
2131 tracer.Start("JSTrashAssetCompleteCallback");
2132
2133 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2134 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2135 jsContext->status = false;
2136 napi_get_undefined(env, &jsContext->data);
2137 if (context->error == ERR_DEFAULT) {
2138 jsContext->status = true;
2139 } else {
2140 context->HandleError(env, jsContext->error);
2141 }
2142 if (context->work != nullptr) {
2143 tracer.Finish();
2144 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2145 context->work, *jsContext);
2146 }
2147
2148 delete context;
2149 }
2150
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2151 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
2152 MediaLibraryAsyncContext &asyncContext)
2153 {
2154 const int32_t refCount = 1;
2155 napi_value result = nullptr;
2156 auto context = &asyncContext;
2157 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2158 size_t res = 0;
2159 char buffer[PATH_MAX];
2160
2161 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2162
2163 for (size_t i = PARAM0; i < argc; i++) {
2164 napi_valuetype valueType = napi_undefined;
2165 napi_typeof(env, argv[i], &valueType);
2166
2167 if (i == PARAM0 && valueType == napi_string) {
2168 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2169 } else if (i == PARAM1 && valueType == napi_function) {
2170 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2171 break;
2172 } else {
2173 NAPI_ASSERT(env, false, "type mismatch");
2174 }
2175 }
2176
2177 context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
2178
2179 // Return true napi_value if params are successfully obtained
2180 napi_get_boolean(env, true, &result);
2181 return result;
2182 }
2183
JSDeleteAsset(napi_env env,napi_callback_info info)2184 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
2185 {
2186 napi_status status;
2187 napi_value result = nullptr;
2188 size_t argc = ARGS_TWO;
2189 napi_value argv[ARGS_TWO] = {0};
2190 napi_value thisVar = nullptr;
2191
2192 MediaLibraryTracer tracer;
2193 tracer.Start("JSDeleteAsset");
2194
2195 GET_JS_ARGS(env, info, argc, argv, thisVar);
2196 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2197 napi_get_undefined(env, &result);
2198
2199 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2200 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2201 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2202 result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
2203 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2204
2205 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
2206 JSDeleteAssetCompleteCallback);
2207 }
2208
2209 return result;
2210 }
2211
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2212 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2213 {
2214 napi_value value;
2215 napi_status status = napi_create_int32(env, intValue, &value);
2216 if (status != napi_ok) {
2217 NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2218 return status;
2219 }
2220 status = napi_set_named_property(env, result, fieldStr, value);
2221 if (status != napi_ok) {
2222 NAPI_ERR_LOG("Set int32 named property error! field: %{public}s", fieldStr);
2223 }
2224 return status;
2225 }
2226
SetValueArray(const napi_env & env,const char * fieldStr,const std::list<Uri> listValue,napi_value & result)2227 static napi_status SetValueArray(const napi_env& env,
2228 const char* fieldStr, const std::list<Uri> listValue, napi_value& result)
2229 {
2230 napi_value value = nullptr;
2231 napi_status status = napi_create_array_with_length(env, listValue.size(), &value);
2232 if (status != napi_ok) {
2233 NAPI_ERR_LOG("Create array error! field: %{public}s", fieldStr);
2234 return status;
2235 }
2236 int elementIndex = 0;
2237 for (auto uri : listValue) {
2238 napi_value uriRet = nullptr;
2239 napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &uriRet);
2240 status = napi_set_element(env, value, elementIndex++, uriRet);
2241 if (status != napi_ok) {
2242 NAPI_ERR_LOG("Set lite item failed, error: %d", status);
2243 }
2244 }
2245 status = napi_set_named_property(env, result, fieldStr, value);
2246 if (status != napi_ok) {
2247 NAPI_ERR_LOG("Set array named property error! field: %{public}s", fieldStr);
2248 }
2249
2250 return status;
2251 }
2252
SetSubUris(const napi_env & env,const shared_ptr<MessageParcel> parcel,napi_value & result)2253 static napi_status SetSubUris(const napi_env& env, const shared_ptr<MessageParcel> parcel, napi_value& result)
2254 {
2255 uint32_t len = 0;
2256 napi_status status = napi_invalid_arg;
2257 if (!parcel->ReadUint32(len)) {
2258 NAPI_ERR_LOG("Failed to read sub uri list length");
2259 return status;
2260 }
2261 napi_value subUriArray = nullptr;
2262 napi_create_array_with_length(env, len, &subUriArray);
2263 int subElementIndex = 0;
2264 for (uint32_t i = 0; i < len; i++) {
2265 string subUri = parcel->ReadString();
2266 if (subUri.empty()) {
2267 NAPI_ERR_LOG("Failed to read sub uri");
2268 return status;
2269 }
2270 napi_value subUriRet = nullptr;
2271 napi_create_string_utf8(env, subUri.c_str(), NAPI_AUTO_LENGTH, &subUriRet);
2272 napi_set_element(env, subUriArray, subElementIndex++, subUriRet);
2273 }
2274 status = napi_set_named_property(env, result, "extraUris", subUriArray);
2275 if (status != napi_ok) {
2276 NAPI_ERR_LOG("Set subUri named property error!");
2277 }
2278 return status;
2279 }
2280
GetTrashAlbumUri()2281 string ChangeListenerNapi::GetTrashAlbumUri()
2282 {
2283 if (!trashAlbumUri_.empty()) {
2284 return trashAlbumUri_;
2285 }
2286 string queryUri = UFM_QUERY_PHOTO_ALBUM;
2287 Uri uri(queryUri);
2288 int errCode = 0;
2289 DataSharePredicates predicates;
2290 predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::TRASH));
2291 vector<string> columns;
2292 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2293 unique_ptr<FetchResult<PhotoAlbum>> albumSet = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
2294 if (albumSet == nullptr) {
2295 return trashAlbumUri_;
2296 }
2297 if (albumSet->GetCount() != 1) {
2298 return trashAlbumUri_;
2299 }
2300 trashAlbumUri_ = albumSet->GetFirstObject()->GetAlbumUri();
2301 return trashAlbumUri_;
2302 }
2303
SolveOnChange(napi_env env,UvChangeMsg * msg)2304 napi_value ChangeListenerNapi::SolveOnChange(napi_env env, UvChangeMsg *msg)
2305 {
2306 static napi_value result;
2307 if (msg->changeInfo_.uris_.empty()) {
2308 napi_get_undefined(env, &result);
2309 return result;
2310 }
2311 napi_create_object(env, &result);
2312 SetValueArray(env, "uris", msg->changeInfo_.uris_, result);
2313 if (msg->changeInfo_.uris_.size() == DEFAULT_ALBUM_COUNT) {
2314 if (msg->changeInfo_.uris_.front().ToString().compare(GetTrashAlbumUri()) == 0) {
2315 if (!MediaLibraryNapiUtils::IsSystemApp()) {
2316 napi_get_undefined(env, &result);
2317 return nullptr;
2318 }
2319 }
2320 }
2321 if (msg->data_ != nullptr && msg->changeInfo_.size_ > 0) {
2322 if ((int)msg->changeInfo_.changeType_ == ChangeType::INSERT) {
2323 SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_ADD_ASSERT, result);
2324 } else {
2325 SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, result);
2326 }
2327 shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
2328 if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(msg->data_), msg->changeInfo_.size_)) {
2329 napi_status status = SetSubUris(env, parcel, result);
2330 if (status != napi_ok) {
2331 NAPI_ERR_LOG("Set subArray named property error! field: subUris");
2332 return nullptr;
2333 }
2334 }
2335 } else {
2336 SetValueInt32(env, "type", (int)msg->changeInfo_.changeType_, result);
2337 }
2338 return result;
2339 }
2340
OnChange(MediaChangeListener & listener,const napi_ref cbRef)2341 void ChangeListenerNapi::OnChange(MediaChangeListener &listener, const napi_ref cbRef)
2342 {
2343 uv_loop_s *loop = nullptr;
2344 napi_get_uv_event_loop(env_, &loop);
2345 if (loop == nullptr) {
2346 return;
2347 }
2348
2349 uv_work_t *work = new (nothrow) uv_work_t;
2350 if (work == nullptr) {
2351 return;
2352 }
2353
2354 UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef, listener.changeInfo, listener.strUri);
2355 if (msg == nullptr) {
2356 delete work;
2357 return;
2358 }
2359 if (!listener.changeInfo.uris_.empty()) {
2360 if (listener.changeInfo.changeType_ == DataShare::DataShareObserver::ChangeType::OTHER) {
2361 NAPI_ERR_LOG("changeInfo.changeType_ is other");
2362 return;
2363 }
2364 if (msg->changeInfo_.size_ > 0) {
2365 msg->data_ = (uint8_t *)malloc(msg->changeInfo_.size_);
2366 if (msg->data_ == nullptr) {
2367 NAPI_ERR_LOG("new msg->data failed");
2368 return;
2369 }
2370 int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
2371 if (copyRet != 0) {
2372 NAPI_ERR_LOG("Parcel data copy failed, err = %{public}d", copyRet);
2373 }
2374 }
2375 }
2376 work->data = reinterpret_cast<void *>(msg);
2377
2378 int ret = uv_queue_work(loop, work, [](uv_work_t *w) {}, [](uv_work_t *w, int s) {
2379 // js thread
2380 if (w == nullptr) {
2381 return;
2382 }
2383
2384 UvChangeMsg *msg = reinterpret_cast<UvChangeMsg *>(w->data);
2385 do {
2386 if (msg == nullptr) {
2387 NAPI_ERR_LOG("UvChangeMsg is null");
2388 break;
2389 }
2390 napi_env env = msg->env_;
2391
2392 napi_value jsCallback = nullptr;
2393 napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
2394 if (status != napi_ok) {
2395 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2396 break;
2397 }
2398 napi_value retVal = nullptr;
2399 napi_value result[ARGS_ONE];
2400 result[PARAM0] = ChangeListenerNapi::SolveOnChange(env, msg);
2401 if (result[PARAM0] == nullptr) {
2402 break;
2403 }
2404 napi_call_function(env, nullptr, jsCallback, ARGS_ONE, result, &retVal);
2405 if (status != napi_ok) {
2406 NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
2407 break;
2408 }
2409 } while (0);
2410 delete msg;
2411 delete w;
2412 });
2413 if (ret != 0) {
2414 NAPI_ERR_LOG("Failed to execute libuv work queue, ret: %{public}d", ret);
2415 delete msg;
2416 delete work;
2417 }
2418 }
2419
GetListenerType(const string & str) const2420 int32_t MediaLibraryNapi::GetListenerType(const string &str) const
2421 {
2422 auto iter = ListenerTypeMaps.find(str);
2423 if (iter == ListenerTypeMaps.end()) {
2424 NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
2425 return INVALID_LISTENER;
2426 }
2427
2428 return iter->second;
2429 }
2430
RegisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)2431 void MediaLibraryNapi::RegisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
2432 {
2433 NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
2434
2435 int32_t typeEnum = GetListenerType(type);
2436 switch (typeEnum) {
2437 case AUDIO_LISTENER:
2438 listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
2439 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
2440 break;
2441 case VIDEO_LISTENER:
2442 listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
2443 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
2444 break;
2445 case IMAGE_LISTENER:
2446 listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
2447 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
2448 break;
2449 case FILE_LISTENER:
2450 listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
2451 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
2452 break;
2453 case SMARTALBUM_LISTENER:
2454 listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
2455 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
2456 listObj.smartAlbumDataObserver_);
2457 break;
2458 case DEVICE_LISTENER:
2459 listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
2460 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
2461 break;
2462 case REMOTEFILE_LISTENER:
2463 listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
2464 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
2465 break;
2466 case ALBUM_LISTENER:
2467 listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
2468 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
2469 break;
2470 default:
2471 NAPI_ERR_LOG("Invalid Media Type!");
2472 }
2473 }
2474
RegisterNotifyChange(napi_env env,const std::string & uri,bool isDerived,napi_ref ref,ChangeListenerNapi & listObj)2475 void MediaLibraryNapi::RegisterNotifyChange(napi_env env,
2476 const std::string &uri, bool isDerived, napi_ref ref, ChangeListenerNapi &listObj)
2477 {
2478 Uri notifyUri(uri);
2479 shared_ptr<MediaOnNotifyObserver> observer= make_shared<MediaOnNotifyObserver>(listObj, uri, ref);
2480 UserFileClient::RegisterObserverExt(notifyUri,
2481 static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), isDerived);
2482 lock_guard<mutex> lock(sOnOffMutex_);
2483 listObj.observers_.push_back(observer);
2484 }
2485
JSOnCallback(napi_env env,napi_callback_info info)2486 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
2487 {
2488 MediaLibraryTracer tracer;
2489 tracer.Start("JSOnCallback");
2490 napi_value undefinedResult = nullptr;
2491 napi_get_undefined(env, &undefinedResult);
2492 size_t argc = ARGS_TWO;
2493 napi_value argv[ARGS_TWO] = {nullptr};
2494 napi_value thisVar = nullptr;
2495 GET_JS_ARGS(env, info, argc, argv, thisVar);
2496 NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
2497 MediaLibraryNapi *obj = nullptr;
2498 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2499 if (status == napi_ok && obj != nullptr) {
2500 napi_valuetype valueType = napi_undefined;
2501 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
2502 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2503 return undefinedResult;
2504 }
2505 char buffer[ARG_BUF_SIZE];
2506 size_t res = 0;
2507 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2508 NAPI_ERR_LOG("Failed to get value string utf8 for type");
2509 return undefinedResult;
2510 }
2511 string type = string(buffer);
2512 const int32_t refCount = 1;
2513 napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
2514 tracer.Start("RegisterChange");
2515 obj->RegisterChange(env, type, *g_listObj);
2516 tracer.Finish();
2517 }
2518 return undefinedResult;
2519 }
2520
CheckRef(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,bool isOff,const string & uri)2521 bool MediaLibraryNapi::CheckRef(napi_env env,
2522 napi_ref ref, ChangeListenerNapi &listObj, bool isOff, const string &uri)
2523 {
2524 napi_value offCallback = nullptr;
2525 napi_status status = napi_get_reference_value(env, ref, &offCallback);
2526 if (status != napi_ok) {
2527 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2528 return false;
2529 }
2530 bool isSame = false;
2531 shared_ptr<DataShare::DataShareObserver> obs;
2532 string obsUri;
2533 {
2534 lock_guard<mutex> lock(sOnOffMutex_);
2535 for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
2536 napi_value onCallback = nullptr;
2537 status = napi_get_reference_value(env, (*it)->ref_, &onCallback);
2538 if (status != napi_ok) {
2539 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2540 return false;
2541 }
2542 napi_strict_equals(env, offCallback, onCallback, &isSame);
2543 if (isSame) {
2544 obsUri = (*it)->uri_;
2545 if ((isOff) && (uri.compare(obsUri) == 0)) {
2546 obs = static_cast<shared_ptr<DataShare::DataShareObserver>>(*it);
2547 listObj.observers_.erase(it);
2548 break;
2549 }
2550 if (uri.compare(obsUri) != 0) {
2551 return true;
2552 }
2553 return false;
2554 }
2555 }
2556 }
2557 if (isSame && isOff) {
2558 if (obs != nullptr) {
2559 UserFileClient::UnregisterObserverExt(Uri(obsUri), obs);
2560 }
2561 }
2562 return true;
2563 }
2564
UserFileMgrOnCallback(napi_env env,napi_callback_info info)2565 napi_value MediaLibraryNapi::UserFileMgrOnCallback(napi_env env, napi_callback_info info)
2566 {
2567 MediaLibraryTracer tracer;
2568 tracer.Start("UserFileMgrOnCallback");
2569 napi_value undefinedResult = nullptr;
2570 napi_get_undefined(env, &undefinedResult);
2571 size_t argc = ARGS_THREE;
2572 napi_value argv[ARGS_THREE] = {nullptr};
2573 napi_value thisVar = nullptr;
2574 GET_JS_ARGS(env, info, argc, argv, thisVar);
2575 if (argc == ARGS_TWO) {
2576 return JSOnCallback(env, info);
2577 }
2578 NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
2579 MediaLibraryNapi *obj = nullptr;
2580 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2581 if (status == napi_ok && obj != nullptr) {
2582 napi_valuetype valueType = napi_undefined;
2583 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
2584 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
2585 napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
2586 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2587 return undefinedResult;
2588 }
2589 char buffer[ARG_BUF_SIZE];
2590 size_t res = 0;
2591 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2592 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2593 return undefinedResult;
2594 }
2595 string uri = string(buffer);
2596 bool isDerived = false;
2597 if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
2598 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2599 return undefinedResult;
2600 }
2601 const int32_t refCount = 1;
2602 napi_ref cbOnRef;
2603 napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
2604 tracer.Start("RegisterNotifyChange");
2605 if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
2606 obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
2607 } else {
2608 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2609 return undefinedResult;
2610 }
2611 tracer.Finish();
2612 }
2613 return undefinedResult;
2614 }
2615
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)2616 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
2617 {
2618 NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
2619
2620 MediaType mediaType;
2621 int32_t typeEnum = GetListenerType(type);
2622
2623 switch (typeEnum) {
2624 case AUDIO_LISTENER:
2625 CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
2626 mediaType = MEDIA_TYPE_AUDIO;
2627 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
2628 listObj.audioDataObserver_ = nullptr;
2629 break;
2630 case VIDEO_LISTENER:
2631 CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
2632 mediaType = MEDIA_TYPE_VIDEO;
2633 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
2634 listObj.videoDataObserver_ = nullptr;
2635 break;
2636 case IMAGE_LISTENER:
2637 CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
2638 mediaType = MEDIA_TYPE_IMAGE;
2639 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
2640 listObj.imageDataObserver_ = nullptr;
2641 break;
2642 case FILE_LISTENER:
2643 CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
2644 mediaType = MEDIA_TYPE_FILE;
2645 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
2646 listObj.fileDataObserver_ = nullptr;
2647 break;
2648 case SMARTALBUM_LISTENER:
2649 CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
2650 mediaType = MEDIA_TYPE_SMARTALBUM;
2651 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
2652 listObj.smartAlbumDataObserver_);
2653 listObj.smartAlbumDataObserver_ = nullptr;
2654 break;
2655 case DEVICE_LISTENER:
2656 CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
2657 mediaType = MEDIA_TYPE_DEVICE;
2658 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
2659 listObj.deviceDataObserver_ = nullptr;
2660 break;
2661 case REMOTEFILE_LISTENER:
2662 CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
2663 mediaType = MEDIA_TYPE_REMOTEFILE;
2664 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
2665 listObj.remoteFileDataObserver_ = nullptr;
2666 break;
2667 case ALBUM_LISTENER:
2668 CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
2669 mediaType = MEDIA_TYPE_ALBUM;
2670 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
2671 listObj.albumDataObserver_ = nullptr;
2672 break;
2673 default:
2674 NAPI_ERR_LOG("Invalid Media Type");
2675 return;
2676 }
2677
2678 if (listObj.cbOffRef_ != nullptr) {
2679 MediaChangeListener listener;
2680 listener.mediaType = mediaType;
2681 listObj.OnChange(listener, listObj.cbOffRef_);
2682 }
2683 }
2684
UnRegisterNotifyChange(napi_env env,const std::string & uri,napi_ref ref,ChangeListenerNapi & listObj)2685 void MediaLibraryNapi::UnRegisterNotifyChange(napi_env env,
2686 const std::string &uri, napi_ref ref, ChangeListenerNapi &listObj)
2687 {
2688 if (ref != nullptr) {
2689 CheckRef(env, ref, listObj, true, uri);
2690 return;
2691 }
2692 if (listObj.observers_.size() == 0) {
2693 return;
2694 }
2695 std::vector<std::shared_ptr<MediaOnNotifyObserver>> offObservers;
2696 {
2697 lock_guard<mutex> lock(sOnOffMutex_);
2698 for (auto iter = listObj.observers_.begin(); iter != listObj.observers_.end();) {
2699 if (uri.compare((*iter)->uri_) == 0) {
2700 offObservers.push_back(*iter);
2701 vector<shared_ptr<MediaOnNotifyObserver>>::iterator tmp = iter;
2702 iter = listObj.observers_.erase(tmp);
2703 } else {
2704 iter++;
2705 }
2706 }
2707 }
2708 for (auto obs : offObservers) {
2709 UserFileClient::UnregisterObserverExt(Uri(uri),
2710 static_cast<shared_ptr<DataShare::DataShareObserver>>(obs));
2711 }
2712 }
2713
JSOffCallback(napi_env env,napi_callback_info info)2714 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
2715 {
2716 MediaLibraryTracer tracer;
2717 tracer.Start("JSOffCallback");
2718 napi_value undefinedResult = nullptr;
2719 napi_get_undefined(env, &undefinedResult);
2720 size_t argc = ARGS_TWO;
2721 napi_value argv[ARGS_TWO] = {nullptr};
2722 napi_value thisVar = nullptr;
2723 GET_JS_ARGS(env, info, argc, argv, thisVar);
2724 NAPI_ASSERT(env, ARGS_ONE <= argc && argc <= ARGS_TWO, "requires one or two parameters");
2725 if (thisVar == nullptr || argv[PARAM0] == nullptr) {
2726 NAPI_ERR_LOG("Failed to retrieve details about the callback");
2727 return undefinedResult;
2728 }
2729 MediaLibraryNapi *obj = nullptr;
2730 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2731 if (status == napi_ok && obj != nullptr) {
2732 napi_valuetype valueType = napi_undefined;
2733 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
2734 return undefinedResult;
2735 }
2736 if (argc == ARGS_TWO) {
2737 auto status = napi_typeof(env, argv[PARAM1], &valueType);
2738 if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
2739 argc -= 1;
2740 }
2741 }
2742 size_t res = 0;
2743 char buffer[ARG_BUF_SIZE];
2744 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2745 NAPI_ERR_LOG("Failed to get value string utf8 for type");
2746 return undefinedResult;
2747 }
2748 string type = string(buffer);
2749 if (argc == ARGS_TWO) {
2750 if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
2751 g_listObj == nullptr) {
2752 return undefinedResult;
2753 }
2754 const int32_t refCount = 1;
2755 napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
2756 }
2757
2758 tracer.Start("UnregisterChange");
2759 obj->UnregisterChange(env, type, *g_listObj);
2760 tracer.Finish();
2761 }
2762
2763 return undefinedResult;
2764 }
2765
UserFileMgrOffCheckArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)2766 static napi_value UserFileMgrOffCheckArgs(napi_env env, napi_callback_info info,
2767 unique_ptr<MediaLibraryAsyncContext> &context)
2768 {
2769 napi_value thisVar = nullptr;
2770 context->argc = ARGS_TWO;
2771 GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
2772 NAPI_ASSERT(env, ARGS_ONE <= context->argc && context->argc<= ARGS_TWO, "requires one or two parameters");
2773 if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
2774 return nullptr;
2775 }
2776
2777 napi_valuetype valueType = napi_undefined;
2778 if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
2779 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2780 return nullptr;
2781 }
2782
2783 if (context->argc == ARGS_TWO) {
2784 auto status = napi_typeof(env, context->argv[PARAM1], &valueType);
2785 if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
2786 context->argc -= 1;
2787 }
2788 }
2789
2790 return thisVar;
2791 }
2792
UserFileMgrOffCallback(napi_env env,napi_callback_info info)2793 napi_value MediaLibraryNapi::UserFileMgrOffCallback(napi_env env, napi_callback_info info)
2794 {
2795 MediaLibraryTracer tracer;
2796 tracer.Start("UserFileMgrOffCallback");
2797 napi_value undefinedResult = nullptr;
2798 napi_get_undefined(env, &undefinedResult);
2799
2800 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2801 napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
2802 MediaLibraryNapi *obj = nullptr;
2803 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2804 if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
2805 return undefinedResult;
2806 }
2807 size_t res = 0;
2808 char buffer[ARG_BUF_SIZE];
2809 if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2810 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2811 return undefinedResult;
2812 }
2813
2814 string uri = string(buffer);
2815 napi_valuetype valueType = napi_undefined;
2816 if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
2817 if (asyncContext->argc == ARGS_TWO) {
2818 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2819 return undefinedResult;
2820 }
2821 const int32_t refCount = 1;
2822 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
2823 }
2824 obj->UnregisterChange(env, uri, *g_listObj);
2825 return undefinedResult;
2826 }
2827 napi_ref cbOffRef = nullptr;
2828 if (asyncContext->argc == ARGS_TWO) {
2829 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2830 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2831 return undefinedResult;
2832 }
2833 const int32_t refCount = 1;
2834 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
2835 }
2836 tracer.Start("UnRegisterNotifyChange");
2837 obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
2838 return undefinedResult;
2839 }
2840
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2841 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
2842 MediaLibraryAsyncContext *context)
2843 {
2844 MediaLibraryTracer tracer;
2845 tracer.Start("JSReleaseCompleteCallback");
2846
2847 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2848
2849 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2850 jsContext->status = false;
2851 if (context->objectInfo != nullptr) {
2852 context->objectInfo->~MediaLibraryNapi();
2853 napi_create_int32(env, SUCCESS, &jsContext->data);
2854 jsContext->status = true;
2855 napi_get_undefined(env, &jsContext->error);
2856 } else {
2857 NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
2858 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2859 "UserFileClient is invalid");
2860 napi_get_undefined(env, &jsContext->data);
2861 }
2862
2863 tracer.Finish();
2864 if (context->work != nullptr) {
2865 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2866 context->work, *jsContext);
2867 }
2868
2869 delete context;
2870 }
2871
JSRelease(napi_env env,napi_callback_info info)2872 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
2873 {
2874 napi_status status;
2875 napi_value result = nullptr;
2876 size_t argc = ARGS_ONE;
2877 napi_value argv[ARGS_ONE] = {0};
2878 napi_value thisVar = nullptr;
2879 napi_value resource = nullptr;
2880 int32_t refCount = 1;
2881
2882 MediaLibraryTracer tracer;
2883 tracer.Start("JSRelease");
2884
2885 GET_JS_ARGS(env, info, argc, argv, thisVar);
2886 NAPI_ERR_LOG("NAPI_ASSERT begin %{public}zu", argc);
2887 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
2888 NAPI_ERR_LOG("NAPI_ASSERT end");
2889 napi_get_undefined(env, &result);
2890
2891 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2892 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2893 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2894 if (argc == PARAM1) {
2895 napi_valuetype valueType = napi_undefined;
2896 napi_typeof(env, argv[PARAM0], &valueType);
2897 if (valueType == napi_function) {
2898 napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
2899 }
2900 }
2901 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2902
2903 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2904 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRelease", asyncContext);
2905
2906 status = napi_create_async_work(
2907 env, nullptr, resource, [](napi_env env, void *data) {},
2908 reinterpret_cast<CompleteCallback>(JSReleaseCompleteCallback),
2909 static_cast<void *>(asyncContext.get()), &asyncContext->work);
2910 if (status != napi_ok) {
2911 napi_get_undefined(env, &result);
2912 } else {
2913 napi_queue_async_work(env, asyncContext->work);
2914 asyncContext.release();
2915 }
2916 }
2917
2918 return result;
2919 }
2920
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)2921 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
2922 {
2923 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2924 if (smartAlbum == nullptr) {
2925 NAPI_ERR_LOG("SmartAlbumAsset is nullptr");
2926 return;
2927 }
2928 if (smartAlbum->GetAlbumCapacity() == 0) {
2929 return;
2930 }
2931 string trashPrefix;
2932 if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
2933 trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
2934 } else {
2935 trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
2936 }
2937 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
2938 context->selectionArgs.emplace_back("0");
2939 context->selectionArgs.emplace_back(to_string(smartAlbum->GetAlbumId()));
2940 DataShare::DataSharePredicates predicates;
2941 predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC LIMIT 0,1 ");
2942 predicates.SetWhereClause(context->selection);
2943 predicates.SetWhereArgs(context->selectionArgs);
2944 vector<string> columns;
2945 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + ASSETMAP_VIEW_NAME);
2946 int errCode = 0;
2947 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2948 if (resultSet == nullptr) {
2949 NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
2950 return;
2951 }
2952 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
2953 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
2954 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
2955 string coverUri = fileAsset->GetUri();
2956 smartAlbum->SetCoverUri(coverUri);
2957 NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
2958 }
2959
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)2960 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
2961 MediaLibraryAsyncContext *context)
2962 {
2963 CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
2964 smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
2965 smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
2966 TYPE_STRING)));
2967 smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUMASSETS_ALBUMCAPACITY,
2968 resultSet, TYPE_INT32)));
2969 MediaFileUri fileUri(MEDIA_TYPE_SMARTALBUM, to_string(smartAlbumData->GetAlbumId()), context->networkId,
2970 MEDIA_API_VERSION_DEFAULT);
2971 smartAlbumData->SetAlbumUri(fileUri.ToString());
2972 smartAlbumData->SetDescription(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_DESCRIPTION, resultSet,
2973 TYPE_STRING)));
2974 smartAlbumData->SetExpiredTime(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_EXPIRED_TIME, resultSet,
2975 TYPE_INT32)));
2976 smartAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_COVER_URI, resultSet,
2977 TYPE_STRING)));
2978 smartAlbumData->SetResultNapiType(context->resultNapiType);
2979 }
2980
2981 #ifndef MEDIALIBRARY_COMPATIBILITY
GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)2982 static void GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
2983 {
2984 MediaLibraryTracer tracer;
2985 tracer.Start("GetAllSmartAlbumResultDataExecute");
2986
2987 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2988 NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
2989
2990 if (context->privateAlbumType == TYPE_TRASH) {
2991 context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
2992 NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
2993 }
2994 if (context->privateAlbumType == TYPE_FAVORITE) {
2995 context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
2996 NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
2997 }
2998
2999 vector<string> columns;
3000 string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3001 if (!context->networkId.empty()) {
3002 uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
3003 "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3004 }
3005 Uri uri(uriStr);
3006 int errCode = 0;
3007 auto resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode);
3008 if (resultSet == nullptr) {
3009 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
3010 context->error = E_PERMISSION_DENIED;
3011 return;
3012 }
3013
3014 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
3015 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
3016 context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
3017 context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
3018 context->fetchSmartAlbumResult->SetResultNapiType(context->resultNapiType);
3019 return;
3020 }
3021 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3022 unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3023 SetSmartAlbumData(albumData.get(), resultSet, context);
3024 if (albumData->GetCoverUri().empty()) {
3025 SetSmartAlbumCoverUri(context, albumData);
3026 }
3027 context->privateSmartAlbumNativeArray.push_back(move(albumData));
3028 }
3029 }
3030
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3031 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3032 unique_ptr<JSAsyncContextOutput> &jsContext)
3033 {
3034 if (context->smartAlbumData != nullptr) {
3035 NAPI_ERR_LOG("context->smartAlbumData != nullptr");
3036 jsContext->status = true;
3037 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3038 napi_get_undefined(env, &jsContext->error);
3039 jsContext->data = albumNapiObj;
3040 } else if (!context->privateSmartAlbumNativeArray.empty()) {
3041 jsContext->status = true;
3042 napi_value albumArray = nullptr;
3043 napi_create_array(env, &albumArray);
3044 for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
3045 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3046 context->privateSmartAlbumNativeArray[i]);
3047 napi_set_element(env, albumArray, i, albumNapiObj);
3048 }
3049 napi_get_undefined(env, &jsContext->error);
3050 jsContext->data = albumArray;
3051 } else {
3052 NAPI_ERR_LOG("No fetch file result found!");
3053 napi_get_undefined(env, &jsContext->data);
3054 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3055 "Failed to obtain Fetch File Result");
3056 }
3057 }
3058
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3059 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3060 unique_ptr<JSAsyncContextOutput> &jsContext)
3061 {
3062 if (context->fetchSmartAlbumResult->GetCount() < 0) {
3063 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
3064 "find no data by options");
3065 } else {
3066 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
3067 if (fileResult == nullptr) {
3068 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3069 "Failed to create js object for Fetch SmartAlbum Result");
3070 } else {
3071 jsContext->data = fileResult;
3072 jsContext->status = true;
3073 napi_get_undefined(env, &jsContext->error);
3074 }
3075 }
3076 }
3077
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3078 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3079 unique_ptr<JSAsyncContextOutput> &jsContext)
3080 {
3081 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
3082 MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
3083 } else {
3084 UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
3085 }
3086 }
3087
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)3088 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
3089 {
3090 MediaLibraryTracer tracer;
3091 tracer.Start("GetPrivateAlbumCallbackComplete");
3092
3093 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3094 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3095 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3096 jsContext->status = false;
3097 napi_get_undefined(env, &jsContext->error);
3098 if (context->error != ERR_DEFAULT) {
3099 napi_get_undefined(env, &jsContext->data);
3100 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3101 "Query for get fileAssets failed");
3102 } else {
3103 SmartAlbumsAsyncResult(env, context, jsContext);
3104 }
3105
3106 tracer.Finish();
3107 if (context->work != nullptr) {
3108 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3109 context->work, *jsContext);
3110 }
3111 delete context;
3112 }
3113 #endif
3114
GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3115 static void GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3116 {
3117 DataShare::DataSharePredicates predicates;
3118 predicates.SetWhereClause(context->selection);
3119 predicates.SetWhereArgs(context->selectionArgs);
3120 vector<string> columns;
3121 Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3122 int errCode = 0;
3123 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3124 if (resultSet == nullptr) {
3125 NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3126 context->error = ERR_INVALID_OUTPUT;
3127 return;
3128 }
3129 if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
3130 context->smartAlbumData = make_unique<SmartAlbumAsset>();
3131 SetSmartAlbumData(context->smartAlbumData.get(), resultSet, context);
3132 SetSmartAlbumCoverUri(context, context->smartAlbumData);
3133 } else {
3134 NAPI_ERR_LOG("Failed to goToFirstRow");
3135 context->error = ERR_INVALID_OUTPUT;
3136 return;
3137 }
3138 }
3139
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)3140 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
3141 {
3142 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3143 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3144 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3145 jsContext->status = false;
3146 napi_get_undefined(env, &jsContext->error);
3147 if (context->error != ERR_DEFAULT) {
3148 napi_get_undefined(env, &jsContext->data);
3149 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3150 "Query for get smartAlbums failed");
3151 } else {
3152 if (!context->smartAlbumNativeArray.empty()) {
3153 jsContext->status = true;
3154 napi_value albumArray = nullptr;
3155 napi_create_array(env, &albumArray);
3156 for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
3157 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3158 context->smartAlbumNativeArray[i]);
3159 napi_set_element(env, albumArray, i, albumNapiObj);
3160 }
3161 napi_get_undefined(env, &jsContext->error);
3162 jsContext->data = albumArray;
3163 } else {
3164 NAPI_ERR_LOG("No SmartAlbums result found!");
3165 napi_get_undefined(env, &jsContext->data);
3166 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3167 "Failed to obtain SmartAlbums Result");
3168 }
3169 }
3170 if (context->work != nullptr) {
3171 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3172 context->work, *jsContext);
3173 }
3174 delete context;
3175 }
3176
GetJSArgsForGetSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3177 napi_value GetJSArgsForGetSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3178 MediaLibraryAsyncContext &asyncContext)
3179 {
3180 napi_value result = nullptr;
3181 auto context = &asyncContext;
3182 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3183 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3184 for (size_t i = 0; i < argc; i++) {
3185 napi_valuetype valueType = napi_undefined;
3186 napi_typeof(env, argv[i], &valueType);
3187 if (i == 0 && valueType == napi_number) {
3188 napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3189 } else if ((i == PARAM1) && valueType == napi_function) {
3190 napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3191 break;
3192 } else {
3193 NAPI_ASSERT(env, false, "type mismatch");
3194 }
3195 }
3196 if (context->parentSmartAlbumId < 0) {
3197 NAPI_ASSERT(env, false, "type mismatch");
3198 }
3199 napi_get_boolean(env, true, &result);
3200 return result;
3201 }
3202
GetSmartAlbumsResultDataExecute(napi_env env,void * data)3203 static void GetSmartAlbumsResultDataExecute(napi_env env, void *data)
3204 {
3205 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3206 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3207 if (context->parentSmartAlbumId < 0) {
3208 context->error = ERR_INVALID_OUTPUT;
3209 NAPI_ERR_LOG("ParentSmartAlbumId is invalid");
3210 return;
3211 }
3212 DataShare::DataSharePredicates predicates;
3213 if (context->parentSmartAlbumId == 0) {
3214 predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " ISNULL");
3215 } else {
3216 predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " = ? ");
3217 predicates.SetWhereArgs({ to_string(context->parentSmartAlbumId)});
3218 }
3219 vector<string> columns;
3220 Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3221 int errCode = 0;
3222 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3223 if (resultSet == nullptr) {
3224 NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3225 context->error = ERR_INVALID_OUTPUT;
3226 return;
3227 }
3228 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3229 unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3230 SetSmartAlbumData(albumData.get(), resultSet, context);
3231 if (albumData->GetCoverUri().empty()) {
3232 SetSmartAlbumCoverUri(context, albumData);
3233 }
3234 context->smartAlbumNativeArray.push_back(move(albumData));
3235 }
3236 }
3237
JSGetSmartAlbums(napi_env env,napi_callback_info info)3238 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
3239 {
3240 napi_status status;
3241 napi_value result = nullptr;
3242 size_t argc = ARGS_TWO;
3243 napi_value argv[ARGS_TWO] = {0};
3244 napi_value thisVar = nullptr;
3245
3246 GET_JS_ARGS(env, info, argc, argv, thisVar);
3247 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3248 napi_get_undefined(env, &result);
3249 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3250 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3251 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
3252 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3253 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3254 result = GetJSArgsForGetSmartAlbum(env, argc, argv, *asyncContext);
3255 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3256 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3257 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
3258 GetSmartAlbumsResultDataExecute, SmartAlbumsAsyncCallbackComplete);
3259 }
3260
3261 return result;
3262 }
3263
AddDefaultPhotoAlbumColumns(napi_env env,vector<string> & fetchColumn)3264 static napi_value AddDefaultPhotoAlbumColumns(napi_env env, vector<string> &fetchColumn)
3265 {
3266 auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
3267 for (const auto &column : fetchColumn) {
3268 if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
3269 validFetchColumns.insert(column);
3270 } else {
3271 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3272 return nullptr;
3273 }
3274 }
3275 fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
3276
3277 napi_value result = nullptr;
3278 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3279 return result;
3280 }
3281
3282 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatGetPrivateAlbumExecute(napi_env env,void * data)3283 static void CompatGetPrivateAlbumExecute(napi_env env, void *data)
3284 {
3285 MediaLibraryTracer tracer;
3286 tracer.Start("CompatGetPrivateAlbumExecute");
3287
3288 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3289 string queryUri = URI_QUERY_PHOTO_ALBUM;
3290 Uri uri(queryUri);
3291 int err = 0;
3292 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, err);
3293 if (resultSet == nullptr) {
3294 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", err);
3295 context->SaveError(err);
3296 return;
3297 }
3298 err = resultSet->GoToFirstRow();
3299 if (err != NativeRdb::E_OK) {
3300 context->SaveError(E_HAS_DB_ERROR);
3301 return;
3302 }
3303
3304 auto albumData = make_unique<AlbumAsset>();
3305 SetAlbumData(albumData.get(), resultSet, "");
3306 CompatSetAlbumCoverUri(context, albumData);
3307 context->albumNativeArray.push_back(move(albumData));
3308 }
3309
CompatGetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3310 static void CompatGetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
3311 unique_ptr<JSAsyncContextOutput> &jsContext)
3312 {
3313 jsContext->status = true;
3314 napi_value albumArray = nullptr;
3315 CHECK_ARGS_RET_VOID(env, napi_create_array(env, &albumArray), JS_INNER_FAIL);
3316 for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
3317 napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
3318 CHECK_ARGS_RET_VOID(env, napi_set_element(env, albumArray, i, albumNapiObj), JS_INNER_FAIL);
3319 }
3320 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3321 jsContext->data = albumArray;
3322 }
3323
CompatGetPrivateAlbumComplete(napi_env env,napi_status status,void * data)3324 static void CompatGetPrivateAlbumComplete(napi_env env, napi_status status, void *data)
3325 {
3326 MediaLibraryTracer tracer;
3327 tracer.Start("JSGetPhotoAlbumsCompleteCallback");
3328
3329 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3330 auto jsContext = make_unique<JSAsyncContextOutput>();
3331 jsContext->status = false;
3332
3333 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3334 if (context->error != ERR_DEFAULT || context->albumNativeArray.empty()) {
3335 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3336 context->HandleError(env, jsContext->error);
3337 } else {
3338 CompatGetPhotoAlbumQueryResult(env, context, jsContext);
3339 }
3340
3341 tracer.Finish();
3342 if (context->work != nullptr) {
3343 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3344 context->work, *jsContext);
3345 }
3346 delete context;
3347 }
3348
ParseArgsGetPrivateAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3349 napi_value ParseArgsGetPrivateAlbum(napi_env env, napi_callback_info info,
3350 unique_ptr<MediaLibraryAsyncContext> &context)
3351 {
3352 int32_t privateAlbumType = -1;
3353 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, context, privateAlbumType),
3354 JS_ERR_PARAMETER_INVALID);
3355 if (privateAlbumType != PrivateAlbumType::TYPE_FAVORITE && privateAlbumType != PrivateAlbumType::TYPE_TRASH) {
3356 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3357 return nullptr;
3358 }
3359
3360 PhotoAlbumSubType subType = ANY;
3361 switch (privateAlbumType) {
3362 case PrivateAlbumType::TYPE_FAVORITE: {
3363 subType = PhotoAlbumSubType::FAVORITE;
3364 break;
3365 }
3366 case PrivateAlbumType::TYPE_TRASH: {
3367 subType = PhotoAlbumSubType::TRASH;
3368 break;
3369 }
3370 default: {
3371 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3372 return nullptr;
3373 }
3374 }
3375 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
3376 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subType));
3377 CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
3378
3379 napi_value result = nullptr;
3380 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3381 return result;
3382 }
3383
CompatGetPrivateAlbum(napi_env env,napi_callback_info info)3384 napi_value CompatGetPrivateAlbum(napi_env env, napi_callback_info info)
3385 {
3386 auto asyncContext = make_unique<MediaLibraryAsyncContext>();
3387 CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
3388
3389 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CompatGetPrivateAlbum",
3390 CompatGetPrivateAlbumExecute, CompatGetPrivateAlbumComplete);
3391 }
3392 #endif // MEDIALIBRARY_COMPATIBILITY
3393
JSGetPrivateAlbum(napi_env env,napi_callback_info info)3394 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
3395 {
3396 #ifdef MEDIALIBRARY_COMPATIBILITY
3397 return CompatGetPrivateAlbum(env, info);
3398 #else
3399 napi_status status;
3400 napi_value result = nullptr;
3401 size_t argc = ARGS_TWO;
3402 napi_value argv[ARGS_TWO] = {0};
3403 napi_value thisVar = nullptr;
3404 const int32_t refCount = 1;
3405
3406 GET_JS_ARGS(env, info, argc, argv, thisVar);
3407 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3408 napi_get_undefined(env, &result);
3409 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3410 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3411 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3412 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3413 for (size_t i = PARAM0; i < argc; i++) {
3414 napi_valuetype valueType = napi_undefined;
3415 napi_typeof(env, argv[i], &valueType);
3416 if (i == PARAM0 && valueType == napi_number) {
3417 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
3418 } else if (i == PARAM1 && valueType == napi_function) {
3419 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
3420 break;
3421 } else {
3422 NAPI_ASSERT(env, false, "type mismatch");
3423 }
3424 }
3425 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
3426 [](napi_env env, void *data) {
3427 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3428 GetAllSmartAlbumResultDataExecute(context);
3429 }, GetPrivateAlbumCallbackComplete);
3430 }
3431 return result;
3432 #endif
3433 }
3434
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3435 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3436 MediaLibraryAsyncContext &asyncContext)
3437 {
3438 const int32_t refCount = 1;
3439 napi_value result = nullptr;
3440 auto context = &asyncContext;
3441 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3442 size_t res = 0;
3443 char buffer[PATH_MAX];
3444 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3445 for (size_t i = 0; i < argc; i++) {
3446 napi_valuetype valueType = napi_undefined;
3447 napi_typeof(env, argv[i], &valueType);
3448 if (i == 0 && valueType == napi_number) {
3449 napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3450 } else if (i == PARAM1 && valueType == napi_string) {
3451 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
3452 } else if (i == PARAM2 && valueType == napi_function) {
3453 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
3454 break;
3455 } else {
3456 NAPI_ASSERT(env, false, "type mismatch");
3457 }
3458 }
3459 if (context->parentSmartAlbumId < 0) {
3460 NAPI_ASSERT(env, false, "type mismatch");
3461 }
3462 string smartName = string(buffer);
3463 if (smartName.empty()) {
3464 NAPI_ASSERT(env, false, "type mismatch");
3465 }
3466 context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
3467 napi_get_boolean(env, true, &result);
3468 return result;
3469 }
3470
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3471 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
3472 MediaLibraryAsyncContext *context)
3473 {
3474 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3475 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3476 jsContext->status = false;
3477 if (context->error == ERR_DEFAULT) {
3478 if (context->smartAlbumData == nullptr) {
3479 NAPI_ERR_LOG("No albums found");
3480 napi_get_undefined(env, &jsContext->data);
3481 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3482 "No albums found");
3483 } else {
3484 jsContext->status = true;
3485 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3486 jsContext->data = albumNapiObj;
3487 napi_get_undefined(env, &jsContext->error);
3488 }
3489 } else {
3490 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3491 "File asset creation failed");
3492 napi_get_undefined(env, &jsContext->data);
3493 }
3494 if (context->work != nullptr) {
3495 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3496 context->work, *jsContext);
3497 }
3498 delete context;
3499 }
3500
CreateSmartAlbumExecute(MediaLibraryAsyncContext * context)3501 static void CreateSmartAlbumExecute(MediaLibraryAsyncContext *context)
3502 {
3503 context->valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
3504 Uri CreateSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMOPRN + "/" +
3505 MEDIA_SMARTALBUMOPRN_CREATEALBUM);
3506 int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
3507 if (retVal < 0) {
3508 context->SaveError(retVal);
3509 NAPI_ERR_LOG("CreateSmartAlbum failed, retVal = %{private}d", retVal);
3510 return;
3511 }
3512 context->selection = SMARTALBUM_DB_ID + " = ?";
3513 context->selectionArgs = { to_string(retVal) };
3514 GetSmartAlbumResultDataExecute(context);
3515 // If parentSmartAlbumId == 0 do not need to add to smart map
3516 if (context->parentSmartAlbumId != 0) {
3517 DataShare::DataShareValuesBucket valuesBucket;
3518 valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
3519 valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ALBUM_ID, retVal);
3520 NAPI_DEBUG_LOG("CreateSmartAlbumExecute retVal = %{public}d, parentSmartAlbumId = %{public}d",
3521 retVal, context->parentSmartAlbumId);
3522 Uri addAsseturi(MEDIALIBRARY_DATA_URI +
3523 "/" + MEDIA_SMARTALBUMMAPOPRN + "/" + MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM);
3524 int32_t changedRows = UserFileClient::Insert(addAsseturi, valuesBucket);
3525 context->SaveError(changedRows);
3526 }
3527 }
3528
JSCreateSmartAlbum(napi_env env,napi_callback_info info)3529 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
3530 {
3531 napi_status status;
3532 napi_value result = nullptr;
3533 size_t argc = ARGS_THREE;
3534 napi_value argv[ARGS_THREE] = {0};
3535 napi_value thisVar = nullptr;
3536 napi_value resource = nullptr;
3537
3538 GET_JS_ARGS(env, info, argc, argv, thisVar);
3539 NAPI_ASSERT(env, (argc == ARGS_TWO || argc == ARGS_THREE), "requires 3 parameters maximum");
3540 napi_get_undefined(env, &result);
3541 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3542 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3543 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3544 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3545 result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
3546 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3547 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3548 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
3549 status = napi_create_async_work(
3550 env, nullptr, resource, [](napi_env env, void *data) {
3551 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3552 CreateSmartAlbumExecute(context);
3553 },
3554 reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
3555 static_cast<void *>(asyncContext.get()), &asyncContext->work);
3556 if (status != napi_ok) {
3557 napi_get_undefined(env, &result);
3558 } else {
3559 napi_queue_async_work(env, asyncContext->work);
3560 asyncContext.release();
3561 }
3562 }
3563 return result;
3564 }
3565
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)3566 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
3567 {
3568 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3569 if (context->smartAlbumId == TYPE_TRASH) {
3570 NAPI_ERR_LOG("Trash smartalbum can not be deleted");
3571 context->error = E_TRASHALBUM_CAN_NOT_DELETE;
3572 return;
3573 }
3574 if (context->smartAlbumId == TYPE_FAVORITE) {
3575 NAPI_ERR_LOG("Facorite smartalbum can not be deleted");
3576 context->error = E_FAVORITEALBUM_CAN_NOT_DELETE;
3577 return;
3578 }
3579 DataShare::DataShareValuesBucket valuesBucket;
3580 valuesBucket.Put(SMARTALBUM_DB_ID, context->smartAlbumId);
3581 Uri DeleteSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" +
3582 MEDIA_SMARTALBUMOPRN + "/" + MEDIA_SMARTALBUMOPRN_DELETEALBUM);
3583 int retVal = UserFileClient::Insert(DeleteSmartAlbumUri, valuesBucket);
3584 NAPI_DEBUG_LOG("JSDeleteSmartAlbumExecute retVal = %{private}d, smartAlbumId = %{private}d",
3585 retVal, context->smartAlbumId);
3586 if (retVal < 0) {
3587 context->SaveError(retVal);
3588 } else {
3589 context->retVal = retVal;
3590 }
3591 }
3592
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3593 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3594 MediaLibraryAsyncContext &asyncContext)
3595 {
3596 napi_value result = nullptr;
3597 auto context = &asyncContext;
3598 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3599 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3600 for (size_t i = 0; i < argc; i++) {
3601 napi_valuetype valueType = napi_undefined;
3602 napi_typeof(env, argv[i], &valueType);
3603 if (i == 0 && valueType == napi_number) {
3604 napi_get_value_int32(env, argv[i], &context->smartAlbumId);
3605 } else if (i == PARAM1 && valueType == napi_function) {
3606 napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3607 break;
3608 } else {
3609 NAPI_ASSERT(env, false, "type mismatch");
3610 }
3611 }
3612 if (context->smartAlbumId < 0) {
3613 NAPI_ASSERT(env, false, "type mismatch");
3614 }
3615 napi_get_boolean(env, true, &result);
3616 return result;
3617 }
3618
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3619 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
3620 MediaLibraryAsyncContext *context)
3621 {
3622 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3623 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3624 jsContext->status = false;
3625 if (context->error == ERR_DEFAULT) {
3626 napi_create_int32(env, context->retVal, &jsContext->data);
3627 napi_get_undefined(env, &jsContext->error);
3628 jsContext->status = true;
3629 } else {
3630 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3631 "UserFileClient is invalid");
3632 napi_get_undefined(env, &jsContext->data);
3633 }
3634 if (context->work != nullptr) {
3635 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3636 context->work, *jsContext);
3637 }
3638 delete context;
3639 }
3640
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)3641 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
3642 {
3643 napi_status status;
3644 napi_value result = nullptr;
3645 size_t argc = ARGS_TWO;
3646 napi_value argv[ARGS_TWO] = {0};
3647 napi_value thisVar = nullptr;
3648 napi_value resource = nullptr;
3649
3650 GET_JS_ARGS(env, info, argc, argv, thisVar);
3651 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3652 napi_get_undefined(env, &result);
3653 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3654 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3655 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3656 result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
3657 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3658 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3659 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
3660 status = napi_create_async_work(
3661 env, nullptr, resource, [](napi_env env, void *data) {
3662 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3663 JSDeleteSmartAlbumExecute(context);
3664 },
3665 reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
3666 static_cast<void *>(asyncContext.get()), &asyncContext->work);
3667 if (status != napi_ok) {
3668 napi_get_undefined(env, &result);
3669 } else {
3670 napi_queue_async_work(env, asyncContext->work);
3671 asyncContext.release();
3672 }
3673 }
3674 return result;
3675 }
3676
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)3677 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
3678 {
3679 napi_value value;
3680 napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
3681 if (status != napi_ok) {
3682 NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
3683 return status;
3684 }
3685 status = napi_set_named_property(env, result, fieldStr, value);
3686 if (status != napi_ok) {
3687 NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
3688 }
3689 return status;
3690 }
3691
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)3692 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
3693 {
3694 napi_value value = nullptr;
3695 napi_status status = napi_get_boolean(env, boolvalue, &value);
3696 if (status != napi_ok) {
3697 NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
3698 return status;
3699 }
3700 status = napi_set_named_property(env, result, fieldStr, value);
3701 if (status != napi_ok) {
3702 NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
3703 }
3704 return status;
3705 }
3706
PeerInfoToJsArray(const napi_env & env,const vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)3707 static void PeerInfoToJsArray(const napi_env &env, const vector<unique_ptr<PeerInfo>> &vecPeerInfo,
3708 const int32_t idx, napi_value &arrayResult)
3709 {
3710 if (idx >= (int32_t) vecPeerInfo.size()) {
3711 return;
3712 }
3713 auto info = vecPeerInfo[idx].get();
3714 if (info == nullptr) {
3715 return;
3716 }
3717 napi_value result = nullptr;
3718 napi_create_object(env, &result);
3719 SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
3720 SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
3721 SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
3722 SetValueBool(env, "isOnline", info->isOnline, result);
3723
3724 napi_status status = napi_set_element(env, arrayResult, idx, result);
3725 if (status != napi_ok) {
3726 NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
3727 }
3728 }
3729
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3730 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
3731 MediaLibraryAsyncContext *context)
3732 {
3733 napi_value jsPeerInfoArray = nullptr;
3734
3735 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3736
3737 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3738 jsContext->status = false;
3739 napi_get_undefined(env, &jsContext->data);
3740
3741 vector<string> columns;
3742 DataShare::DataSharePredicates predicates;
3743 string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
3744 predicates.SetWhereClause(strQueryCondition);
3745 predicates.SetWhereArgs(context->selectionArgs);
3746
3747 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE);
3748 int errCode = 0;
3749 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
3750 uri, predicates, columns, errCode);
3751
3752 if (resultSet == nullptr) {
3753 NAPI_ERR_LOG("JSGetActivePeers resultSet is null, errCode is %{public}d", errCode);
3754 delete context;
3755 return;
3756 }
3757
3758 vector<unique_ptr<PeerInfo>> peerInfoArray;
3759 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3760 unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
3761 if (peerInfo != nullptr) {
3762 peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
3763 TYPE_STRING));
3764 peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
3765 TYPE_STRING));
3766 peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
3767 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
3768 peerInfo->isOnline = true;
3769 peerInfoArray.push_back(move(peerInfo));
3770 }
3771 }
3772
3773 if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
3774 for (size_t i = 0; i < peerInfoArray.size(); ++i) {
3775 PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
3776 }
3777
3778 jsContext->data = jsPeerInfoArray;
3779 napi_get_undefined(env, &jsContext->error);
3780 jsContext->status = true;
3781 } else {
3782 NAPI_DEBUG_LOG("No peer info found!");
3783 napi_get_undefined(env, &jsContext->data);
3784 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3785 "Failed to obtain peer info array from DB");
3786 }
3787
3788 if (context->work != nullptr) {
3789 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3790 context->work, *jsContext);
3791 }
3792
3793 delete context;
3794 }
3795
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3796 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
3797 MediaLibraryAsyncContext *context)
3798 {
3799 napi_value jsPeerInfoArray = nullptr;
3800
3801 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3802
3803 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3804 jsContext->status = false;
3805 napi_get_undefined(env, &jsContext->data);
3806
3807 vector<string> columns;
3808 DataShare::DataSharePredicates predicates;
3809 predicates.SetWhereClause(context->selection);
3810 predicates.SetWhereArgs(context->selectionArgs);
3811
3812 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE);
3813 int errCode = 0;
3814 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
3815 uri, predicates, columns, errCode);
3816
3817 if (resultSet == nullptr) {
3818 NAPI_ERR_LOG("JSGetAllPeers resultSet is null, errCode is %{public}d", errCode);
3819 delete context;
3820 return;
3821 }
3822
3823 vector<unique_ptr<PeerInfo>> peerInfoArray;
3824 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3825 unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
3826 if (peerInfo != nullptr) {
3827 peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
3828 TYPE_STRING));
3829 peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
3830 TYPE_STRING));
3831 peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
3832 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
3833 peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
3834 TYPE_INT32)) == 0);
3835 peerInfoArray.push_back(move(peerInfo));
3836 }
3837 }
3838
3839 if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
3840 for (size_t i = 0; i < peerInfoArray.size(); ++i) {
3841 PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
3842 }
3843
3844 jsContext->data = jsPeerInfoArray;
3845 napi_get_undefined(env, &jsContext->error);
3846 jsContext->status = true;
3847 } else {
3848 NAPI_DEBUG_LOG("No peer info found!");
3849 napi_get_undefined(env, &jsContext->data);
3850 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3851 "Failed to obtain peer info array from DB");
3852 }
3853
3854 if (context->work != nullptr) {
3855 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3856 context->work, *jsContext);
3857 }
3858 delete context;
3859 }
3860
JSGetActivePeers(napi_env env,napi_callback_info info)3861 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
3862 {
3863 napi_status status;
3864 napi_value result = nullptr;
3865 const int32_t refCount = 1;
3866 napi_value resource = nullptr;
3867 size_t argc = ARGS_ONE;
3868 napi_value argv[ARGS_ONE] = {0};
3869 napi_value thisVar = nullptr;
3870
3871 MediaLibraryTracer tracer;
3872 tracer.Start("JSGetActivePeers");
3873
3874 GET_JS_ARGS(env, info, argc, argv, thisVar);
3875 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
3876 napi_get_undefined(env, &result);
3877
3878 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3879 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3880 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3881 if (argc == ARGS_ONE) {
3882 GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
3883 }
3884
3885 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3886 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetActivePeers", asyncContext);
3887 status = napi_create_async_work(
3888 env, nullptr, resource, [](napi_env env, void *data) {},
3889 reinterpret_cast<CompleteCallback>(JSGetActivePeersCompleteCallback),
3890 static_cast<void *>(asyncContext.get()), &asyncContext->work);
3891 if (status != napi_ok) {
3892 napi_get_undefined(env, &result);
3893 } else {
3894 napi_queue_async_work(env, asyncContext->work);
3895 asyncContext.release();
3896 }
3897 }
3898
3899 return result;
3900 }
3901
JSGetAllPeers(napi_env env,napi_callback_info info)3902 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
3903 {
3904 napi_status status;
3905 napi_value result = nullptr;
3906 const int32_t refCount = 1;
3907 napi_value resource = nullptr;
3908 size_t argc = ARGS_ONE;
3909 napi_value argv[ARGS_ONE] = {0};
3910 napi_value thisVar = nullptr;
3911
3912 MediaLibraryTracer tracer;
3913 tracer.Start("JSGetAllPeers");
3914
3915 GET_JS_ARGS(env, info, argc, argv, thisVar);
3916 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
3917 napi_get_undefined(env, &result);
3918
3919 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3920 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3921 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3922 if (argc == ARGS_ONE) {
3923 GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
3924 }
3925
3926 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3927 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetAllPeers", asyncContext);
3928 status = napi_create_async_work(
3929 env, nullptr, resource, [](napi_env env, void *data) {},
3930 reinterpret_cast<CompleteCallback>(JSGetAllPeersCompleteCallback),
3931 static_cast<void *>(asyncContext.get()), &asyncContext->work);
3932 if (status != napi_ok) {
3933 napi_get_undefined(env, &result);
3934 } else {
3935 napi_queue_async_work(env, asyncContext->work);
3936 asyncContext.release();
3937 }
3938 }
3939
3940 return result;
3941 }
3942
CloseAsset(MediaLibraryAsyncContext * context,string uri)3943 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
3944 {
3945 string abilityUri = MEDIALIBRARY_DATA_URI;
3946 Uri closeAssetUri(URI_CLOSE_FILE);
3947 context->valuesBucket.Clear();
3948 context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
3949 int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3950 NAPI_DEBUG_LOG("File close asset %{public}d", ret);
3951 if (ret != E_SUCCESS) {
3952 context->error = ret;
3953 NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
3954 }
3955 return ret;
3956 }
3957
GetStoreMediaAssetUri(MediaLibraryAsyncContext * context,string & uri)3958 static void GetStoreMediaAssetUri(MediaLibraryAsyncContext *context, string &uri)
3959 {
3960 bool isValid = false;
3961 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
3962 if (relativePath.find(CAMERA_DIR_VALUES) == 0 ||
3963 relativePath.find(VIDEO_DIR_VALUES) == 0 ||
3964 relativePath.find(PIC_DIR_VALUES) == 0) {
3965 uri = URI_CREATE_PHOTO;
3966 } else if (relativePath.find(AUDIO_DIR_VALUES) == 0) {
3967 uri = URI_CREATE_AUDIO;
3968 } else {
3969 uri = URI_CREATE_FILE;
3970 }
3971 }
3972
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)3973 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
3974 {
3975 string realPath;
3976 if (!PathToRealPath(context->storeMediaSrc, realPath)) {
3977 NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
3978 context->error = JS_ERR_NO_SUCH_FILE;
3979 return;
3980 }
3981 context->error = JS_E_RELATIVEPATH;
3982 int32_t srcFd = open(realPath.c_str(), O_RDWR);
3983 if (srcFd == -1) {
3984 NAPI_ERR_LOG("src path open fail, %{public}d", errno);
3985 return;
3986 }
3987 struct stat statSrc;
3988 if (fstat(srcFd, &statSrc) == -1) {
3989 close(srcFd);
3990 NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
3991 return;
3992 }
3993 string uriString;
3994 GetStoreMediaAssetUri(context, uriString);
3995 Uri createFileUri(uriString);
3996 int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
3997 if (index < 0) {
3998 close(srcFd);
3999 NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
4000 return;
4001 }
4002 SetFileAssetByIdV9(index, "", context);
4003 CHECK_NULL_PTR_RETURN_VOID(context->fileAsset, "JSGetStoreMediaAssetExecute: context->fileAsset is nullptr");
4004 Uri openFileUri(context->fileAsset->GetUri());
4005 int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE);
4006 if (destFd < 0) {
4007 context->error = destFd;
4008 NAPI_DEBUG_LOG("File open asset failed");
4009 close(srcFd);
4010 return;
4011 }
4012 if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
4013 close(srcFd);
4014 close(destFd);
4015 CloseAsset(context, context->fileAsset->GetUri());
4016 NAPI_ERR_LOG("copy file fail %{public}d ", errno);
4017 return;
4018 }
4019 close(srcFd);
4020 close(destFd);
4021 CloseAsset(context, context->fileAsset->GetUri());
4022 context->error = ERR_DEFAULT;
4023 }
4024
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4025 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
4026 MediaLibraryAsyncContext *context)
4027 {
4028 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4029 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4030 CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
4031 jsContext->status = false;
4032 napi_get_undefined(env, &jsContext->data);
4033 if (context->error != ERR_DEFAULT) {
4034 NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
4035 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4036 "storeMediaAsset fail");
4037 } else {
4038 napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4039 jsContext->status = true;
4040 napi_get_undefined(env, &jsContext->error);
4041 }
4042
4043 if (context->work != nullptr) {
4044 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4045 context->work, *jsContext);
4046 }
4047 delete context;
4048 }
4049
ConvertMediaType(const string & mimeType)4050 static int ConvertMediaType(const string &mimeType)
4051 {
4052 string res;
4053 // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
4054 size_t slash = mimeType.find('/');
4055 if (slash != string::npos) {
4056 res = mimeType.substr(0, slash);
4057 if (res.empty()) {
4058 return MediaType::MEDIA_TYPE_FILE;
4059 }
4060 }
4061 if (res == "image") {
4062 return MediaType::MEDIA_TYPE_IMAGE;
4063 } else if (res == "video") {
4064 return MediaType::MEDIA_TYPE_VIDEO;
4065 } else if (res == "audio") {
4066 return MediaType::MEDIA_TYPE_AUDIO;
4067 }
4068 return MediaType::MEDIA_TYPE_FILE;
4069 }
4070
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)4071 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
4072 {
4073 napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
4074 if (value == nullptr) {
4075 NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
4076 return false;
4077 }
4078 unique_ptr<char[]> tmp;
4079 bool succ;
4080 tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
4081 if (!succ) {
4082 NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
4083 return false;
4084 }
4085 res = string(tmp.get());
4086 return true;
4087 }
4088
GetDefaultDirectory(int mediaType)4089 static string GetDefaultDirectory(int mediaType)
4090 {
4091 string relativePath;
4092 if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
4093 relativePath = "Pictures/";
4094 } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
4095 relativePath = "Videos/";
4096 } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
4097 relativePath = "Audios/";
4098 } else {
4099 relativePath = "Documents/";
4100 }
4101 return relativePath;
4102 }
4103
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)4104 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
4105 MediaLibraryAsyncContext &asyncContext)
4106 {
4107 auto context = &asyncContext;
4108 if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
4109 NAPI_ERR_LOG("param get fail");
4110 return nullptr;
4111 }
4112 string fileName = MediaFileUtils::GetFileName(context->storeMediaSrc);
4113 if (fileName.empty() || (fileName.at(0) == '.')) {
4114 NAPI_ERR_LOG("src file name is not proper");
4115 context->error = JS_E_RELATIVEPATH;
4116 return nullptr;
4117 };
4118 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
4119 string mimeType;
4120 if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
4121 NAPI_ERR_LOG("param get fail");
4122 return nullptr;
4123 }
4124 auto mediaType = ConvertMediaType(mimeType);
4125 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
4126 string relativePath;
4127 if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
4128 NAPI_DEBUG_LOG("optional relativePath param empty");
4129 relativePath = GetDefaultDirectory(mediaType);
4130 }
4131 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
4132 NAPI_DEBUG_LOG("src:%{public}s mime:%{public}s relp:%{private}s filename:%{private}s",
4133 context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
4134 napi_value result = nullptr;
4135 napi_get_undefined(env, &result);
4136 return result;
4137 }
4138
JSStoreMediaAsset(napi_env env,napi_callback_info info)4139 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
4140 {
4141 size_t argc = ARGS_TWO;
4142 napi_value argv[ARGS_TWO] = {0};
4143 napi_value thisVar = nullptr;
4144 GET_JS_ARGS(env, info, argc, argv, thisVar);
4145 napi_value result = nullptr;
4146 napi_get_undefined(env, &result);
4147 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4148 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4149 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4150 if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
4151 napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
4152 CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
4153 if (argc == ARGS_TWO) {
4154 const int32_t refCount = 1;
4155 GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4156 }
4157 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4158 napi_value resource = nullptr;
4159 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
4160 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4161 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4162 JSGetStoreMediaAssetExecute(context);
4163 },
4164 reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
4165 static_cast<void *>(asyncContext.get()), &asyncContext->work);
4166 if (status != napi_ok) {
4167 napi_get_undefined(env, &result);
4168 } else {
4169 napi_queue_async_work(env, asyncContext->work);
4170 asyncContext.release();
4171 }
4172 }
4173 return result;
4174 }
4175
CreateAsyncCallbackInfo(napi_env env)4176 static Ability *CreateAsyncCallbackInfo(napi_env env)
4177 {
4178 if (env == nullptr) {
4179 NAPI_ERR_LOG("env == nullptr.");
4180 return nullptr;
4181 }
4182 napi_status ret;
4183 napi_value global = 0;
4184 const napi_extended_error_info *errorInfo = nullptr;
4185 ret = napi_get_global(env, &global);
4186 if (ret != napi_ok) {
4187 napi_get_last_error_info(env, &errorInfo);
4188 NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
4189 }
4190 napi_value abilityObj = 0;
4191 ret = napi_get_named_property(env, global, "ability", &abilityObj);
4192 if (ret != napi_ok) {
4193 napi_get_last_error_info(env, &errorInfo);
4194 NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
4195 }
4196 Ability *ability = nullptr;
4197 ret = napi_get_value_external(env, abilityObj, (void **)&ability);
4198 if (ret != napi_ok) {
4199 napi_get_last_error_info(env, &errorInfo);
4200 NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
4201 }
4202 return ability;
4203 }
4204
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4205 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4206 {
4207 uint32_t arraySize = 0;
4208 if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
4209 NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
4210 return nullptr;
4211 }
4212 string uri = "";
4213 for (uint32_t i = 0; i < arraySize; i++) {
4214 napi_value jsValue = nullptr;
4215 if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
4216 NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
4217 return nullptr;
4218 }
4219 unique_ptr<char[]> inputStr;
4220 bool succ;
4221 tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
4222 if (!succ) {
4223 NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
4224 return nullptr;
4225 }
4226 uri += string(inputStr.get());
4227 uri += ",";
4228 }
4229 context.uri = uri.substr(0, uri.length() - 1);
4230 NAPI_DEBUG_LOG("GetImagePreviewArgs res %{public}s", context.uri.c_str());
4231 napi_value res;
4232 napi_get_undefined(env, &res);
4233 return res;
4234 }
4235
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4236 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4237 {
4238 context.imagePreviewIndex = 0;
4239 napi_valuetype valueType = napi_undefined;
4240 napi_typeof(env, param, &valueType);
4241 if (valueType != napi_number) {
4242 NAPI_ERR_LOG("not napi value");
4243 return nullptr;
4244 }
4245 if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
4246 NAPI_ERR_LOG("get property value fail");
4247 }
4248 NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
4249 napi_value res;
4250 napi_get_undefined(env, &res);
4251 return res;
4252 }
4253
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)4254 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
4255 {
4256 if (context->ability_ == nullptr) {
4257 NAPI_ERR_LOG("ability_ is not exist");
4258 context->error = ERR_INVALID_OUTPUT;
4259 return;
4260 }
4261 Want want;
4262 want.SetType("image/jpeg");
4263 want.SetAction("ohos.want.action.viewData");
4264 want.SetParam("uri", context->uri);
4265 want.SetParam("viewIndex", context->imagePreviewIndex + 1);
4266 context->error = context->ability_->StartAbility(want);
4267 }
4268
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4269 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
4270 MediaLibraryAsyncContext *context)
4271 {
4272 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4273 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4274 CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
4275 jsContext->status = true;
4276 napi_get_undefined(env, &jsContext->data);
4277 if (context->error != 0) {
4278 jsContext->status = false;
4279 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4280 "startImagePreview currently fail");
4281 }
4282 if (context->work != nullptr) {
4283 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4284 context->work, *jsContext);
4285 }
4286 delete context;
4287 }
4288
JSStartImagePreview(napi_env env,napi_callback_info info)4289 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
4290 {
4291 size_t argc = ARGS_THREE;
4292 napi_value argv[ARGS_THREE] = {0};
4293 napi_value thisVar = nullptr;
4294 GET_JS_ARGS(env, info, argc, argv, thisVar);
4295 napi_value result = nullptr;
4296 napi_get_undefined(env, &result);
4297 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4298 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4299 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4300 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4301 napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
4302 CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
4303 GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
4304 asyncContext->ability_ = CreateAsyncCallbackInfo(env);
4305 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
4306 const int32_t refCount = 1;
4307 if (argc == ARGS_THREE) {
4308 GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
4309 } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
4310 GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4311 }
4312 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4313 napi_value resource = nullptr;
4314 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
4315 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4316 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4317 JSStartImagePreviewExecute(context);
4318 },
4319 reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
4320 static_cast<void *>(asyncContext.get()), &asyncContext->work);
4321 if (status != napi_ok) {
4322 napi_get_undefined(env, &result);
4323 } else {
4324 napi_queue_async_work(env, asyncContext->work);
4325 asyncContext.release();
4326 }
4327 }
4328 return result;
4329 }
4330
CheckCreateOption(MediaLibraryAsyncContext & context)4331 static napi_status CheckCreateOption(MediaLibraryAsyncContext &context)
4332 {
4333 bool isValid = false;
4334 int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
4335 string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
4336 if (isValid == true) {
4337 if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
4338 NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
4339 return napi_invalid_arg;
4340 }
4341 if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
4342 NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
4343 return napi_invalid_arg;
4344 } else {
4345 context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
4346 }
4347 }
4348
4349 return napi_ok;
4350 }
4351
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4352 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4353 {
4354 for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
4355 string param = iter.first;
4356 bool present = false;
4357 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4358 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4359 if (!present) {
4360 continue;
4361 }
4362 napi_value value;
4363 result = napi_get_named_property(env, arg, param.c_str(), &value);
4364 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
4365 napi_valuetype valueType = napi_undefined;
4366 result = napi_typeof(env, value, &valueType);
4367 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
4368 if (valueType == napi_number) {
4369 int32_t number = 0;
4370 result = napi_get_value_int32(env, value, &number);
4371 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
4372 context.valuesBucket.Put(iter.second, number);
4373 } else if (valueType == napi_boolean) {
4374 bool isTrue = false;
4375 result = napi_get_value_bool(env, value, &isTrue);
4376 CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
4377 context.valuesBucket.Put(iter.second, isTrue);
4378 } else if (valueType == napi_string) {
4379 char buffer[ARG_BUF_SIZE];
4380 size_t res = 0;
4381 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
4382 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
4383 context.valuesBucket.Put(iter.second, string(buffer));
4384 } else if (valueType == napi_undefined || valueType == napi_null) {
4385 continue;
4386 } else {
4387 NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
4388 return napi_invalid_arg;
4389 }
4390 }
4391
4392 return CheckCreateOption(context);
4393 }
4394
ParseCreateOptions(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4395 static napi_status ParseCreateOptions(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4396 {
4397 for (const auto &iter : CREATE_OPTIONS_PARAM) {
4398 string param = iter.first;
4399 bool present = false;
4400 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4401 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4402 if (!present) {
4403 continue;
4404 }
4405 napi_value value;
4406 result = napi_get_named_property(env, arg, param.c_str(), &value);
4407 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
4408 napi_valuetype valueType = napi_undefined;
4409 result = napi_typeof(env, value, &valueType);
4410 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
4411 if (valueType == napi_number) {
4412 int32_t number = 0;
4413 result = napi_get_value_int32(env, value, &number);
4414 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
4415 context.valuesBucket.Put(iter.second, number);
4416 } else if (valueType == napi_boolean) {
4417 bool isTrue = false;
4418 result = napi_get_value_bool(env, value, &isTrue);
4419 CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
4420 context.valuesBucket.Put(iter.second, isTrue);
4421 } else if (valueType == napi_string) {
4422 char buffer[ARG_BUF_SIZE];
4423 size_t res = 0;
4424 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
4425 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
4426 context.valuesBucket.Put(iter.second, string(buffer));
4427 } else if (valueType == napi_undefined || valueType == napi_null) {
4428 continue;
4429 } else {
4430 NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
4431 static_cast<int>(valueType));
4432 return napi_invalid_arg;
4433 }
4434 }
4435
4436 return napi_ok;
4437 }
4438
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4439 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
4440 unique_ptr<MediaLibraryAsyncContext> &context)
4441 {
4442 /* Parse the first argument into displayName */
4443 napi_valuetype valueType;
4444 MediaType mediaType;
4445 string displayName;
4446 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
4447 napi_ok, "Failed to get displayName");
4448 mediaType = MediaFileUtils::GetMediaType(displayName);
4449 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
4450 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
4451
4452 /* Parse the second argument into albumUri if exists */
4453 string albumUri;
4454 if ((context->argc >= ARGS_TWO)) {
4455 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
4456 if (valueType == napi_string) {
4457 if (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok) {
4458 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
4459 }
4460 } else if (valueType == napi_object) {
4461 NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
4462 "Parse asset create option failed");
4463 }
4464 }
4465
4466 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4467 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
4468
4469 napi_value result = nullptr;
4470 NAPI_CALL(env, napi_get_boolean(env, true, &result));
4471 return result;
4472 }
4473
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4474 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
4475 unique_ptr<MediaLibraryAsyncContext> &context)
4476 {
4477 /* Parse the first argument into displayName */
4478 napi_valuetype valueType;
4479 MediaType mediaType;
4480 int32_t type = 0;
4481 NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
4482 "Failed to get type value");
4483 mediaType = static_cast<MediaType>(type);
4484 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
4485
4486 /* Parse the second argument into albumUri if exists */
4487 string extention;
4488 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
4489 napi_ok, "Failed to get extention");
4490 context->valuesBucket.Put(ASSET_EXTENTION, extention);
4491
4492 /* Parse the third argument into albumUri if exists */
4493 if (context->argc >= ARGS_THREE) {
4494 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
4495 if (valueType == napi_object) {
4496 NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
4497 "Parse asset create option failed");
4498 } else if (valueType != napi_function) {
4499 NAPI_ERR_LOG("Napi type is wrong in create options");
4500 return nullptr;
4501 }
4502 }
4503
4504 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4505
4506 napi_value result = nullptr;
4507 NAPI_CALL(env, napi_get_boolean(env, true, &result));
4508 return result;
4509 }
4510
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4511 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
4512 unique_ptr<MediaLibraryAsyncContext> &context)
4513 {
4514 constexpr size_t minArgs = ARGS_ONE;
4515 constexpr size_t maxArgs = ARGS_FOUR;
4516 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
4517 napi_ok, "Failed to get object info");
4518
4519 napi_valuetype valueType;
4520 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
4521 if (valueType == napi_string) {
4522 context->isCreateByComponent = false;
4523 return ParseArgsCreatePhotoAssetSystem(env, info, context);
4524 } else if (valueType == napi_number) {
4525 context->isCreateByComponent = true;
4526 return ParseArgsCreatePhotoAssetComponent(env, info, context);
4527 } else {
4528 NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
4529 return nullptr;
4530 }
4531 }
4532
ParseArgsCreateAudioAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4533 static napi_value ParseArgsCreateAudioAssetSystem(napi_env env, napi_callback_info info,
4534 unique_ptr<MediaLibraryAsyncContext> &context)
4535 {
4536 /* Parse the first argument into displayName */
4537 string displayName;
4538 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
4539 napi_ok, "Failed to get displayName");
4540
4541 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_AUDIO);
4542 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
4543
4544 napi_value result = nullptr;
4545 NAPI_CALL(env, napi_get_boolean(env, true, &result));
4546 return result;
4547 }
4548
ParseArgsCreateAudioAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4549 static napi_value ParseArgsCreateAudioAssetComponent(napi_env env, napi_callback_info info,
4550 unique_ptr<MediaLibraryAsyncContext> &context)
4551 {
4552 /* Parse the first argument into displayName */
4553 napi_valuetype valueType;
4554 MediaType mediaType;
4555 int32_t type = 0;
4556 NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
4557 "Failed to get type value");
4558 mediaType = static_cast<MediaType>(type);
4559 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_AUDIO), "invalid file type");
4560
4561 /* Parse the second argument into albumUri if exists */
4562 string extention;
4563 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
4564 napi_ok, "Failed to get extention");
4565 context->valuesBucket.Put(ASSET_EXTENTION, extention);
4566
4567 /* Parse the third argument into albumUri if exists */
4568 if (context->argc >= ARGS_THREE) {
4569 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
4570 if (valueType == napi_object) {
4571 NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
4572 "Parse asset create option failed");
4573 } else if (valueType != napi_function) {
4574 NAPI_ERR_LOG("Napi type is wrong in create options");
4575 return nullptr;
4576 }
4577 }
4578
4579 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4580 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
4581
4582 napi_value result = nullptr;
4583 NAPI_CALL(env, napi_get_boolean(env, true, &result));
4584 return result;
4585 }
4586
ParseArgsCreateAudioAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4587 static napi_value ParseArgsCreateAudioAsset(napi_env env, napi_callback_info info,
4588 unique_ptr<MediaLibraryAsyncContext> &context)
4589 {
4590 constexpr size_t minArgs = ARGS_ONE;
4591 constexpr size_t maxArgs = ARGS_FOUR;
4592 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
4593 napi_ok, "Failed to get object info");
4594
4595 napi_valuetype valueType;
4596 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
4597 if (valueType == napi_string) {
4598 context->isCreateByComponent = false;
4599 return ParseArgsCreateAudioAssetSystem(env, info, context);
4600 } else if (valueType == napi_number) {
4601 context->isCreateByComponent = true;
4602 return ParseArgsCreateAudioAssetComponent(env, info, context);
4603 } else {
4604 NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
4605 return nullptr;
4606 }
4607 }
4608
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4609 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
4610 unique_ptr<MediaLibraryAsyncContext> &context)
4611 {
4612 constexpr size_t minArgs = ARGS_ONE;
4613 constexpr size_t maxArgs = ARGS_TWO;
4614 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
4615 JS_ERR_PARAMETER_INVALID);
4616
4617 /* Parse the first argument */
4618 CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
4619 JS_INNER_FAIL);
4620 auto &predicates = context->predicates;
4621 switch (context->assetType) {
4622 case TYPE_AUDIO: {
4623 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
4624 AudioColumn::IsAudioColumn));
4625 break;
4626 }
4627 case TYPE_PHOTO: {
4628 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
4629 PhotoColumn::IsPhotoColumn));
4630 break;
4631 }
4632 default: {
4633 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
4634 return nullptr;
4635 }
4636 }
4637 predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
4638 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
4639 if (context->assetType == TYPE_PHOTO) {
4640 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
4641 }
4642
4643 napi_value result = nullptr;
4644 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4645 return result;
4646 }
4647
ParseArgsIndexUri(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,string & uri,string & albumUri)4648 static napi_status ParseArgsIndexUri(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, string &uri,
4649 string &albumUri)
4650 {
4651 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], uri),
4652 "Failed to get first string argument");
4653 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri),
4654 "Failed to get second string argument");
4655 return napi_ok;
4656 }
4657
ParseArgsIndexof(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4658 static napi_value ParseArgsIndexof(napi_env env, napi_callback_info info,
4659 unique_ptr<MediaLibraryAsyncContext> &context)
4660 {
4661 constexpr size_t minArgs = ARGS_THREE;
4662 constexpr size_t maxArgs = ARGS_FOUR;
4663 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
4664 JS_ERR_PARAMETER_INVALID);
4665
4666 string uri;
4667 string album;
4668 CHECK_ARGS(env, ParseArgsIndexUri(env, context, uri, album), JS_INNER_FAIL);
4669 CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM2], ASSET_FETCH_OPT, context),
4670 JS_INNER_FAIL);
4671 auto &predicates = context->predicates;
4672 predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
4673 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
4674 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
4675
4676 context->fetchColumn.clear();
4677 MediaFileUri photoUri(uri);
4678 CHECK_COND(env, photoUri.GetUriType() == API10_PHOTO_URI, JS_ERR_PARAMETER_INVALID);
4679 context->fetchColumn.emplace_back(photoUri.GetFileId());
4680 if (!album.empty()) {
4681 MediaFileUri albumUri(album);
4682 CHECK_COND(env, albumUri.GetUriType() == API10_PHOTOALBUM_URI, JS_ERR_PARAMETER_INVALID);
4683 context->fetchColumn.emplace_back(albumUri.GetFileId());
4684 } else {
4685 context->fetchColumn.emplace_back(album);
4686 }
4687 napi_value result = nullptr;
4688 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4689 return result;
4690 }
4691
JSGetAssetsExecute(napi_env env,void * data)4692 static void JSGetAssetsExecute(napi_env env, void *data)
4693 {
4694 MediaLibraryTracer tracer;
4695 tracer.Start("JSGetAssetsExecute");
4696
4697 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4698 string queryUri;
4699 switch (context->assetType) {
4700 case TYPE_AUDIO: {
4701 queryUri = UFM_QUERY_AUDIO;
4702 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4703 break;
4704 }
4705 case TYPE_PHOTO: {
4706 queryUri = UFM_QUERY_PHOTO;
4707 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4708 break;
4709 }
4710 default: {
4711 context->SaveError(-EINVAL);
4712 return;
4713 }
4714 }
4715
4716 Uri uri(queryUri);
4717 int errCode = 0;
4718 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
4719 context->predicates, context->fetchColumn, errCode);
4720 if (resultSet == nullptr) {
4721 context->SaveError(errCode);
4722 return;
4723 }
4724 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4725 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
4726 }
4727
GetPhotoIndexAsyncCallbackComplete(napi_env env,napi_status status,void * data)4728 static void GetPhotoIndexAsyncCallbackComplete(napi_env env, napi_status status, void *data)
4729 {
4730 MediaLibraryTracer tracer;
4731 tracer.Start("GetPhotoIndexAsyncCallbackComplete");
4732
4733 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4734 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4735
4736 auto jsContext = make_unique<JSAsyncContextOutput>();
4737 jsContext->status = false;
4738 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
4739 if (context->error != ERR_DEFAULT) {
4740 context->HandleError(env, jsContext->error);
4741 } else {
4742 auto fileAsset = context->fetchFileResult->GetFirstObject();
4743 int32_t count = -1;
4744 if (fileAsset != nullptr) {
4745 count = fileAsset->GetPhotoIndex();
4746 }
4747 jsContext->status = true;
4748 napi_create_int32(env, count, &jsContext->data);
4749 }
4750
4751 tracer.Finish();
4752 if (context->work != nullptr) {
4753 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4754 context->work, *jsContext);
4755 }
4756 delete context;
4757 }
4758
GetPhotoIndexExec(napi_env env,void * data,ResultNapiType type)4759 static void GetPhotoIndexExec(napi_env env, void *data, ResultNapiType type)
4760 {
4761 MediaLibraryTracer tracer;
4762 tracer.Start("JsGetPhotoIndexExec");
4763 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4764 string queryUri = UFM_GET_INDEX;
4765 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4766 Uri uri(queryUri);
4767 int errCode = 0;
4768 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
4769 if (resultSet == nullptr) {
4770 context->SaveError(errCode);
4771 return;
4772 }
4773 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4774 context->fetchFileResult->SetResultNapiType(type);
4775 }
4776
PhotoAccessGetPhotoIndexExec(napi_env env,void * data)4777 static void PhotoAccessGetPhotoIndexExec(napi_env env, void *data)
4778 {
4779 GetPhotoIndexExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
4780 }
4781
JsGetPhotoIndexExec(napi_env env,void * data)4782 static void JsGetPhotoIndexExec(napi_env env, void *data)
4783 {
4784 GetPhotoIndexExec(env, data, ResultNapiType::TYPE_USERFILE_MGR);
4785 }
4786
JSGetPhotoIndex(napi_env env,napi_callback_info info)4787 napi_value MediaLibraryNapi::JSGetPhotoIndex(napi_env env, napi_callback_info info)
4788 {
4789 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4790 CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
4791 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
4792 JsGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
4793 }
4794
PhotoAccessGetPhotoIndex(napi_env env,napi_callback_info info)4795 napi_value MediaLibraryNapi::PhotoAccessGetPhotoIndex(napi_env env, napi_callback_info info)
4796 {
4797 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4798 CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
4799 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
4800 PhotoAccessGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
4801 }
4802
JSGetPhotoAssets(napi_env env,napi_callback_info info)4803 napi_value MediaLibraryNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
4804 {
4805 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4806 asyncContext->assetType = TYPE_PHOTO;
4807 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
4808
4809 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
4810 JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
4811 }
4812
PhotoAccessGetAssetsExecute(napi_env env,void * data)4813 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
4814 {
4815 MediaLibraryTracer tracer;
4816 tracer.Start("JSGetAssetsExecute");
4817
4818 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4819 string queryUri;
4820 switch (context->assetType) {
4821 case TYPE_PHOTO: {
4822 queryUri = PAH_QUERY_PHOTO;
4823 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4824 break;
4825 }
4826 default: {
4827 context->SaveError(-EINVAL);
4828 return;
4829 }
4830 }
4831
4832 Uri uri(queryUri);
4833 int errCode = 0;
4834 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
4835 context->predicates, context->fetchColumn, errCode);
4836 if (resultSet == nullptr) {
4837 context->SaveError(errCode);
4838 return;
4839 }
4840 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4841 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
4842 }
4843
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)4844 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
4845 {
4846 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4847 asyncContext->assetType = TYPE_PHOTO;
4848 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
4849
4850 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
4851 PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
4852 }
4853
JSGetAudioAssets(napi_env env,napi_callback_info info)4854 napi_value MediaLibraryNapi::JSGetAudioAssets(napi_env env, napi_callback_info info)
4855 {
4856 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4857 asyncContext->assetType = TYPE_AUDIO;
4858 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
4859
4860 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAudioAssets",
4861 JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
4862 }
4863
GetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)4864 static void GetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
4865 unique_ptr<JSAsyncContextOutput> &jsContext)
4866 {
4867 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
4868 if (fileResult == nullptr) {
4869 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4870 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4871 "Failed to create js object for Fetch Album Result");
4872 return;
4873 }
4874 jsContext->data = fileResult;
4875 jsContext->status = true;
4876 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4877 }
4878
JSGetPhotoAlbumsExecute(napi_env env,void * data)4879 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
4880 {
4881 MediaLibraryTracer tracer;
4882 tracer.Start("JSGetPhotoAlbumsExecute");
4883
4884 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4885 string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
4886 UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
4887 Uri uri(queryUri);
4888 int errCode = 0;
4889 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
4890 if (resultSet == nullptr) {
4891 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
4892 context->SaveError(E_HAS_DB_ERROR);
4893 return;
4894 }
4895
4896 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
4897 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
4898 }
4899
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)4900 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
4901 {
4902 MediaLibraryTracer tracer;
4903 tracer.Start("JSGetPhotoAlbumsCompleteCallback");
4904
4905 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
4906 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4907 jsContext->status = false;
4908 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4909 if (context->error != ERR_DEFAULT || context->fetchPhotoAlbumResult == nullptr) {
4910 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4911 context->HandleError(env, jsContext->error);
4912 } else {
4913 GetPhotoAlbumQueryResult(env, context, jsContext);
4914 }
4915
4916 tracer.Finish();
4917 if (context->work != nullptr) {
4918 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4919 context->work, *jsContext);
4920 }
4921 delete context;
4922 }
4923
JSGetPhotoAlbums(napi_env env,napi_callback_info info)4924 napi_value MediaLibraryNapi::JSGetPhotoAlbums(napi_env env, napi_callback_info info)
4925 {
4926 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4927 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext),
4928 JS_ERR_PARAMETER_INVALID);
4929 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4930
4931 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAlbums", JSGetPhotoAlbumsExecute,
4932 JSGetPhotoAlbumsCompleteCallback);
4933 }
4934
UserFileMgrCreatePhotoAsset(napi_env env,napi_callback_info info)4935 napi_value MediaLibraryNapi::UserFileMgrCreatePhotoAsset(napi_env env, napi_callback_info info)
4936 {
4937 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4938 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4939 asyncContext->assetType = TYPE_PHOTO;
4940 NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
4941
4942 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreatePhotoAsset",
4943 JSCreateAssetExecute, JSCreateAssetCompleteCallback);
4944 }
4945
UserFileMgrCreateAudioAsset(napi_env env,napi_callback_info info)4946 napi_value MediaLibraryNapi::UserFileMgrCreateAudioAsset(napi_env env, napi_callback_info info)
4947 {
4948 napi_value ret = nullptr;
4949 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4950 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4951 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4952 asyncContext->assetType = TYPE_AUDIO;
4953 NAPI_ASSERT(env, ParseArgsCreateAudioAsset(env, info, asyncContext), "Failed to parse js args");
4954
4955 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAudioAsset",
4956 JSCreateAssetExecute, JSCreateAssetCompleteCallback);
4957 }
4958
ParseArgsTrashAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4959 napi_value ParseArgsTrashAsset(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
4960 {
4961 string uri;
4962 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
4963 JS_ERR_PARAMETER_INVALID);
4964 if (uri.empty()) {
4965 NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
4966 return nullptr;
4967 }
4968 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
4969 NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
4970 return nullptr;
4971 }
4972 context->uri = uri;
4973
4974 napi_value result = nullptr;
4975 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4976 return result;
4977 }
4978
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)4979 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
4980 {
4981 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4982 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4983 CHECK_NULLPTR_RET(ParseArgsTrashAsset(env, info, asyncContext));
4984 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
4985 JSTrashAssetCompleteCallback);
4986 }
4987
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)4988 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
4989 {
4990 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4991 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4992 CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
4993
4994 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
4995 JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
4996 }
4997
CreateMediaTypeEnum(napi_env env)4998 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
4999 {
5000 return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
5001 }
5002
CreateMediaTypeUserFileEnum(napi_env env)5003 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
5004 {
5005 const int32_t startIdx = 1;
5006 return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
5007 }
5008
CreateDirectoryTypeEnum(napi_env env)5009 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
5010 {
5011 return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
5012 }
5013
CreateVirtualAlbumTypeEnum(napi_env env)5014 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
5015 {
5016 return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
5017 }
5018
CreatePrivateAlbumTypeEnum(napi_env env)5019 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
5020 {
5021 return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
5022 }
5023
CreateFileKeyEnum(napi_env env)5024 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
5025 {
5026 return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
5027 }
5028
UserFileMgrCreateFileKeyEnum(napi_env env)5029 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
5030 {
5031 return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
5032 }
5033
CreateAudioKeyEnum(napi_env env)5034 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
5035 {
5036 return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
5037 }
5038
CreateImageVideoKeyEnum(napi_env env)5039 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
5040 {
5041 return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
5042 }
5043
CreatePhotoKeysEnum(napi_env env)5044 napi_value MediaLibraryNapi::CreatePhotoKeysEnum(napi_env env)
5045 {
5046 return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sPhotoKeysEnumRef_);
5047 }
5048
CreateAlbumKeyEnum(napi_env env)5049 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
5050 {
5051 return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
5052 }
5053
CreateAlbumTypeEnum(napi_env env)5054 napi_value MediaLibraryNapi::CreateAlbumTypeEnum(napi_env env)
5055 {
5056 napi_value result = nullptr;
5057 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
5058
5059 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
5060 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
5061
5062 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
5063 return result;
5064 }
5065
CreateAlbumSubTypeEnum(napi_env env)5066 napi_value MediaLibraryNapi::CreateAlbumSubTypeEnum(napi_env env)
5067 {
5068 napi_value result = nullptr;
5069 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
5070
5071 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
5072 JS_INNER_FAIL);
5073 for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
5074 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
5075 PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
5076 }
5077 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
5078
5079 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
5080 return result;
5081 }
CreateDefaultChangeUriEnum(napi_env env)5082 napi_value MediaLibraryNapi::CreateDefaultChangeUriEnum(napi_env env)
5083 {
5084 return CreateStringEnumProperty(env, DEFAULT_URI_ENUM_PROPERTIES, sDefaultChangeUriRef_);
5085 }
5086
CreateNotifyTypeEnum(napi_env env)5087 napi_value MediaLibraryNapi::CreateNotifyTypeEnum(napi_env env)
5088 {
5089 return CreateNumberEnumProperty(env, notifyTypeEnum, sNotifyType_);
5090 }
5091
ParseArgsCreatePhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5092 static napi_value ParseArgsCreatePhotoAlbum(napi_env env, napi_callback_info info,
5093 unique_ptr<MediaLibraryAsyncContext> &context)
5094 {
5095 constexpr size_t minArgs = ARGS_ONE;
5096 constexpr size_t maxArgs = ARGS_TWO;
5097 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5098 JS_ERR_PARAMETER_INVALID);
5099
5100 /* Parse the first argument into albumName */
5101 string albumName;
5102 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], albumName),
5103 JS_ERR_PARAMETER_INVALID);
5104
5105 if (MediaFileUtils::CheckAlbumName(albumName) < 0) {
5106 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5107 return nullptr;
5108 }
5109 context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, albumName);
5110
5111 napi_value result = nullptr;
5112 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5113 return result;
5114 }
5115
GetExistsPhotoAlbum(const string & albumName,MediaLibraryAsyncContext * context)5116 static void GetExistsPhotoAlbum(const string &albumName, MediaLibraryAsyncContext *context)
5117 {
5118 string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
5119 UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
5120 Uri uri(queryUri);
5121 DataSharePredicates predicates;
5122 predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
5123 vector<string> columns;
5124 int errCode = 0;
5125 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
5126 auto fetchResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
5127 fetchResult->SetResultNapiType(context->resultNapiType);
5128 context->photoAlbumData = fetchResult->GetFirstObject();
5129 }
5130
GetPhotoAlbumById(const int32_t id,const string & albumName,MediaLibraryAsyncContext * context)5131 static void GetPhotoAlbumById(const int32_t id, const string &albumName, MediaLibraryAsyncContext *context)
5132 {
5133 auto photoAlbum = make_unique<PhotoAlbum>();
5134 photoAlbum->SetAlbumId(id);
5135 photoAlbum->SetPhotoAlbumType(USER);
5136 photoAlbum->SetPhotoAlbumSubType(USER_GENERIC);
5137 photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(id));
5138 photoAlbum->SetAlbumName(albumName);
5139 photoAlbum->SetResultNapiType(context->resultNapiType);
5140 context->photoAlbumData = move(photoAlbum);
5141 }
5142
JSCreatePhotoAlbumExecute(napi_env env,void * data)5143 static void JSCreatePhotoAlbumExecute(napi_env env, void *data)
5144 {
5145 MediaLibraryTracer tracer;
5146 tracer.Start("JSCreatePhotoAlbumExecute");
5147
5148 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5149 string createAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
5150 UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
5151 Uri createPhotoAlbumUri(createAlbumUri);
5152 auto ret = UserFileClient::Insert(createPhotoAlbumUri, context->valuesBucket);
5153
5154 bool isValid = false;
5155 string albumName = context->valuesBucket.Get(PhotoAlbumColumns::ALBUM_NAME, isValid);
5156 if (!isValid) {
5157 context->SaveError(-EINVAL);
5158 return;
5159 }
5160 if (ret == -1) {
5161 // The album is already existed
5162 context->SaveError(-EEXIST);
5163 GetExistsPhotoAlbum(albumName, context);
5164 return;
5165 }
5166 if (ret < 0) {
5167 context->SaveError(ret);
5168 return;
5169 }
5170 GetPhotoAlbumById(ret, albumName, context);
5171 }
5172
GetPhotoAlbumCreateResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)5173 static void GetPhotoAlbumCreateResult(napi_env env, MediaLibraryAsyncContext *context,
5174 unique_ptr<JSAsyncContextOutput> &jsContext)
5175 {
5176 if (context->photoAlbumData == nullptr) {
5177 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5178 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
5179 "Obtain photo album asset failed");
5180 return;
5181 }
5182 napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
5183 if (jsPhotoAlbum == nullptr) {
5184 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5185 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
5186 "Failed to create js object for PhotoAlbum");
5187 return;
5188 }
5189 jsContext->data = jsPhotoAlbum;
5190 jsContext->status = true;
5191 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5192 }
5193
HandleExistsError(napi_env env,MediaLibraryAsyncContext * context,napi_value & error)5194 static void HandleExistsError(napi_env env, MediaLibraryAsyncContext *context, napi_value &error)
5195 {
5196 if (context->photoAlbumData == nullptr) {
5197 MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_INVALID_OUTPUT,
5198 "Obtain photo album asset failed");
5199 return;
5200 }
5201 napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
5202 if (jsPhotoAlbum == nullptr) {
5203 MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_MEM_ALLOCATION,
5204 "Failed to create js object for PhotoAlbum");
5205 return;
5206 }
5207 MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, JS_ERR_FILE_EXIST, "Album has existed");
5208 napi_value propertyName;
5209 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &propertyName), JS_INNER_FAIL);
5210 CHECK_ARGS_RET_VOID(env, napi_set_property(env, error, propertyName, jsPhotoAlbum), JS_INNER_FAIL);
5211 }
5212
JSCreatePhotoAlbumCompleteCallback(napi_env env,napi_status status,void * data)5213 static void JSCreatePhotoAlbumCompleteCallback(napi_env env, napi_status status, void *data)
5214 {
5215 MediaLibraryTracer tracer;
5216 tracer.Start("JSCreatePhotoAlbumCompleteCallback");
5217
5218 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5219 auto jsContext = make_unique<JSAsyncContextOutput>();
5220 jsContext->status = false;
5221 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5222 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5223 if (context->error == ERR_DEFAULT) {
5224 GetPhotoAlbumCreateResult(env, context, jsContext);
5225 } else if (context->error == JS_ERR_FILE_EXIST) {
5226 HandleExistsError(env, context, jsContext->error);
5227 } else {
5228 context->HandleError(env, jsContext->error);
5229 }
5230
5231 tracer.Finish();
5232 if (context->work != nullptr) {
5233 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5234 context->work, *jsContext);
5235 }
5236 delete context;
5237 }
5238
CreatePhotoAlbum(napi_env env,napi_callback_info info)5239 napi_value MediaLibraryNapi::CreatePhotoAlbum(napi_env env, napi_callback_info info)
5240 {
5241 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5242 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
5243 CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
5244
5245 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
5246 JSCreatePhotoAlbumCompleteCallback);
5247 }
5248
PhotoAccessCreatePhotoAlbum(napi_env env,napi_callback_info info)5249 napi_value MediaLibraryNapi::PhotoAccessCreatePhotoAlbum(napi_env env, napi_callback_info info)
5250 {
5251 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5252 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5253 CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
5254
5255 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
5256 JSCreatePhotoAlbumCompleteCallback);
5257 }
5258
ParseArgsDeletePhotoAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5259 static napi_value ParseArgsDeletePhotoAlbums(napi_env env, napi_callback_info info,
5260 unique_ptr<MediaLibraryAsyncContext> &context)
5261 {
5262 constexpr size_t minArgs = ARGS_ONE;
5263 constexpr size_t maxArgs = ARGS_TWO;
5264 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5265 JS_ERR_PARAMETER_INVALID);
5266
5267 /* Parse the first argument into delete album id array */
5268 vector<string> deleteIds;
5269
5270 uint32_t len = 0;
5271 CHECK_ARGS(env, napi_get_array_length(env, context->argv[PARAM0], &len), JS_INNER_FAIL);
5272 for (uint32_t i = 0; i < len; i++) {
5273 napi_value album = nullptr;
5274 CHECK_ARGS(env, napi_get_element(env, context->argv[PARAM0], i, &album), JS_INNER_FAIL);
5275 if (album == nullptr) {
5276 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5277 return nullptr;
5278 }
5279 PhotoAlbumNapi *obj = nullptr;
5280 CHECK_ARGS(env, napi_unwrap(env, album, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
5281 if (obj == nullptr) {
5282 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5283 return nullptr;
5284 }
5285 if (!PhotoAlbum::IsUserPhotoAlbum(obj->GetPhotoAlbumType(), obj->GetPhotoAlbumSubType())) {
5286 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5287 return nullptr;
5288 }
5289 deleteIds.push_back(to_string(obj->GetAlbumId()));
5290 }
5291 if (deleteIds.empty()) {
5292 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5293 return nullptr;
5294 }
5295 context->predicates.In(PhotoAlbumColumns::ALBUM_ID, deleteIds);
5296
5297 napi_value result = nullptr;
5298 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5299 return result;
5300 }
5301
JSDeletePhotoAlbumsExecute(napi_env env,void * data)5302 static void JSDeletePhotoAlbumsExecute(napi_env env, void *data)
5303 {
5304 MediaLibraryTracer tracer;
5305 tracer.Start("JSDeletePhotoAlbumsExecute");
5306
5307 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5308 string deleteAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
5309 UFM_DELETE_PHOTO_ALBUM : PAH_DELETE_PHOTO_ALBUM;
5310 Uri uri(deleteAlbumUri);
5311 int ret = UserFileClient::Delete(uri, context->predicates);
5312 if (ret < 0) {
5313 context->SaveError(ret);
5314 } else {
5315 context->retVal = ret;
5316 }
5317 }
5318
JSDeletePhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)5319 static void JSDeletePhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
5320 {
5321 MediaLibraryTracer tracer;
5322 tracer.Start("JSDeletePhotoAlbumsCompleteCallback");
5323
5324 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
5325 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5326
5327 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
5328 jsContext->status = false;
5329
5330 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5331 if (context->error != ERR_DEFAULT) {
5332 context->HandleError(env, jsContext->error);
5333 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5334 } else {
5335 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
5336 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5337 jsContext->status = true;
5338 }
5339
5340 tracer.Finish();
5341 if (context->work != nullptr) {
5342 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5343 context->work, *jsContext);
5344 }
5345 delete context;
5346 }
5347
DeletePhotoAlbums(napi_env env,napi_callback_info info)5348 napi_value MediaLibraryNapi::DeletePhotoAlbums(napi_env env, napi_callback_info info)
5349 {
5350 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5351 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
5352 CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
5353
5354 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
5355 JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
5356 }
5357
PhotoAccessDeletePhotoAlbums(napi_env env,napi_callback_info info)5358 napi_value MediaLibraryNapi::PhotoAccessDeletePhotoAlbums(napi_env env, napi_callback_info info)
5359 {
5360 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5361 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5362 CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
5363
5364 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
5365 JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
5366 }
5367
GetAlbumFetchOption(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)5368 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
5369 {
5370 if (context->argc < (ARGS_ONE + hasCallback)) {
5371 NAPI_ERR_LOG("No arguments to parse");
5372 return nullptr;
5373 }
5374
5375 // The index of fetchOption should always be the last arg besides callback
5376 napi_value fetchOption = context->argv[context->argc - 1 - hasCallback];
5377 CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT, context), JS_INNER_FAIL);
5378
5379 napi_value result = nullptr;
5380 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5381 return result;
5382 }
5383
ParseAlbumTypes(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context)5384 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context)
5385 {
5386 if (context->argc < ARGS_TWO) {
5387 NAPI_ERR_LOG("No arguments to parse");
5388 return nullptr;
5389 }
5390
5391 /* Parse the first argument to photo album type */
5392 int32_t albumType;
5393 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
5394 if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
5395 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5396 return nullptr;
5397 }
5398 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
5399
5400 /* Parse the second argument to photo album subType */
5401 int32_t albumSubType;
5402 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
5403 if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
5404 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5405 return nullptr;
5406 }
5407 if (albumSubType != ANY) {
5408 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
5409 }
5410
5411 napi_value result = nullptr;
5412 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5413 return result;
5414 }
5415
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5416 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
5417 unique_ptr<MediaLibraryAsyncContext> &context)
5418 {
5419 constexpr size_t minArgs = ARGS_ZERO;
5420 constexpr size_t maxArgs = ARGS_FOUR;
5421 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5422 JS_ERR_PARAMETER_INVALID);
5423
5424 bool hasCallback = false;
5425 CHECK_ARGS(env, MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
5426 JS_ERR_PARAMETER_INVALID);
5427 if (context->argc == ARGS_THREE) {
5428 napi_valuetype valueType = napi_undefined;
5429 if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
5430 (valueType == napi_undefined || valueType == napi_null)) {
5431 context->argc -= 1;
5432 }
5433 }
5434 switch (context->argc - hasCallback) {
5435 case ARGS_ZERO:
5436 break;
5437 case ARGS_ONE:
5438 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
5439 break;
5440 case ARGS_TWO:
5441 CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
5442 break;
5443 case ARGS_THREE:
5444 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
5445 CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
5446 break;
5447 default:
5448 return nullptr;
5449 }
5450 CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
5451
5452 napi_value result = nullptr;
5453 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5454 return result;
5455 }
5456
GetPhotoAlbums(napi_env env,napi_callback_info info)5457 napi_value MediaLibraryNapi::GetPhotoAlbums(napi_env env, napi_callback_info info)
5458 {
5459 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5460 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
5461 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
5462
5463 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
5464 JSGetPhotoAlbumsCompleteCallback);
5465 }
5466
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)5467 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
5468 {
5469 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5470 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5471 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
5472
5473 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
5474 JSGetPhotoAlbumsCompleteCallback);
5475 }
5476
CreatePositionTypeEnum(napi_env env)5477 napi_value MediaLibraryNapi::CreatePositionTypeEnum(napi_env env)
5478 {
5479 const int32_t startIdx = 1;
5480 return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
5481 }
5482
CreatePhotoSubTypeEnum(napi_env env)5483 napi_value MediaLibraryNapi::CreatePhotoSubTypeEnum(napi_env env)
5484 {
5485 return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
5486 }
5487
PhotoAccessCreateAssetExecute(napi_env env,void * data)5488 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
5489 {
5490 MediaLibraryTracer tracer;
5491 tracer.Start("JSCreateAssetExecute");
5492
5493 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5494 if (!CheckDisplayNameParams(context)) {
5495 context->error = JS_E_DISPLAYNAME;
5496 return;
5497 }
5498 if ((context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) && (!CheckRelativePathParams(context))) {
5499 context->error = JS_E_RELATIVEPATH;
5500 return;
5501 }
5502
5503 string uri;
5504 GetCreateUri(context, uri);
5505 Uri createFileUri(uri);
5506 string outUri;
5507 int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
5508 if (index < 0) {
5509 context->SaveError(index);
5510 } else {
5511 if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
5512 if (context->isCreateByComponent) {
5513 context->uri = outUri;
5514 } else {
5515 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
5516 }
5517 } else {
5518 #ifdef MEDIALIBRARY_COMPATIBILITY
5519 SetFileAssetByIdV9(index, "", context);
5520 #else
5521 getFileAssetById(index, "", context);
5522 #endif
5523 }
5524 }
5525 }
5526
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)5527 napi_value MediaLibraryNapi::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
5528 {
5529 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5530 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5531 asyncContext->assetType = TYPE_PHOTO;
5532 NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
5533
5534 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
5535 PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
5536 }
5537
PhotoAccessHelperOnCallback(napi_env env,napi_callback_info info)5538 napi_value MediaLibraryNapi::PhotoAccessHelperOnCallback(napi_env env, napi_callback_info info)
5539 {
5540 MediaLibraryTracer tracer;
5541 tracer.Start("PhotoAccessHelperOnCallback");
5542 napi_value undefinedResult = nullptr;
5543 napi_get_undefined(env, &undefinedResult);
5544 size_t argc = ARGS_THREE;
5545 napi_value argv[ARGS_THREE] = {nullptr};
5546 napi_value thisVar = nullptr;
5547 GET_JS_ARGS(env, info, argc, argv, thisVar);
5548 if (argc == ARGS_TWO) {
5549 return JSOnCallback(env, info);
5550 }
5551 NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
5552 MediaLibraryNapi *obj = nullptr;
5553 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
5554 if (status == napi_ok && obj != nullptr) {
5555 napi_valuetype valueType = napi_undefined;
5556 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
5557 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
5558 napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
5559 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5560 return undefinedResult;
5561 }
5562 char buffer[ARG_BUF_SIZE];
5563 size_t res = 0;
5564 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
5565 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5566 return undefinedResult;
5567 }
5568 string uri = string(buffer);
5569 bool isDerived = false;
5570 if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
5571 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5572 return undefinedResult;
5573 }
5574 const int32_t refCount = 1;
5575 napi_ref cbOnRef;
5576 napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
5577 tracer.Start("RegisterNotifyChange");
5578 if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
5579 obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
5580 } else {
5581 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5582 return undefinedResult;
5583 }
5584 tracer.Finish();
5585 }
5586 return undefinedResult;
5587 }
5588
PhotoAccessHelperOffCallback(napi_env env,napi_callback_info info)5589 napi_value MediaLibraryNapi::PhotoAccessHelperOffCallback(napi_env env, napi_callback_info info)
5590 {
5591 MediaLibraryTracer tracer;
5592 tracer.Start("PhotoAccessHelperOffCallback");
5593 napi_value undefinedResult = nullptr;
5594 napi_get_undefined(env, &undefinedResult);
5595
5596 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5597 napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
5598 MediaLibraryNapi *obj = nullptr;
5599 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
5600 if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
5601 return undefinedResult;
5602 }
5603 size_t res = 0;
5604 char buffer[ARG_BUF_SIZE];
5605 if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
5606 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5607 return undefinedResult;
5608 }
5609
5610 string uri = string(buffer);
5611 napi_valuetype valueType = napi_undefined;
5612 if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
5613 if (asyncContext->argc == ARGS_TWO) {
5614 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
5615 return undefinedResult;
5616 }
5617 const int32_t refCount = 1;
5618 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
5619 }
5620 obj->UnregisterChange(env, uri, *g_listObj);
5621 return undefinedResult;
5622 }
5623 napi_ref cbOffRef = nullptr;
5624 if (asyncContext->argc == ARGS_TWO) {
5625 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
5626 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5627 return undefinedResult;
5628 }
5629 const int32_t refCount = 1;
5630 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
5631 }
5632 tracer.Start("UnRegisterNotifyChange");
5633 obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
5634 return undefinedResult;
5635 }
5636
ParseArgsPHAccessHelperTrash(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5637 napi_value ParseArgsPHAccessHelperTrash(napi_env env, napi_callback_info info,
5638 unique_ptr<MediaLibraryAsyncContext> &context)
5639 {
5640 vector<string> uris;
5641 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringArrayCallback(env, info, context, uris),
5642 JS_ERR_PARAMETER_INVALID);
5643 if (uris.empty()) {
5644 NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
5645 return nullptr;
5646 }
5647 for (const auto &uri : uris) {
5648 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
5649 NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
5650 return nullptr;
5651 }
5652 }
5653 context->uris = uris;
5654
5655 napi_value result = nullptr;
5656 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5657 return result;
5658 }
5659
PhotoAccessHelperTrashExecute(napi_env env,void * data)5660 static void PhotoAccessHelperTrashExecute(napi_env env, void *data)
5661 {
5662 MediaLibraryTracer tracer;
5663 tracer.Start("PhotoAccessHelperTrashExecute");
5664
5665 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5666 const vector<string> &uris = context->uris;
5667 string tmpUri;
5668 vector<string> trashIds;
5669 for (const auto &uri : uris) {
5670 tmpUri = uri;
5671 MediaFileUri::RemoveAllFragment(tmpUri);
5672 string trashId = MediaFileUtils::GetIdFromUri(tmpUri);
5673 trashIds.push_back(trashId);
5674 }
5675 string trashUri = PAH_TRASH_PHOTO;
5676 MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5677 Uri updateAssetUri(trashUri);
5678 DataSharePredicates predicates;
5679 predicates.In(MediaColumn::MEDIA_ID, trashIds);
5680 DataShareValuesBucket valuesBucket;
5681 valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeSeconds());
5682 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
5683 if (changedRows < 0) {
5684 context->SaveError(changedRows);
5685 NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
5686 }
5687 }
5688
PhotoAccessHelperTrashAsset(napi_env env,napi_callback_info info)5689 napi_value MediaLibraryNapi::PhotoAccessHelperTrashAsset(napi_env env, napi_callback_info info)
5690 {
5691 napi_value ret = nullptr;
5692 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5693 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
5694 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5695 CHECK_NULLPTR_RET(ParseArgsPHAccessHelperTrash(env, info, asyncContext));
5696 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperTrashAsset",
5697 PhotoAccessHelperTrashExecute, JSTrashAssetCompleteCallback);
5698 }
5699 } // namespace Media
5700 } // namespace OHOS
5701