1 /*
2 * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #define MLOG_TAG "MediaLibraryNapi"
16
17 #include "media_library_napi.h"
18
19 #include <fcntl.h>
20 #include <sys/sendfile.h>
21 #include "media_file_utils.h"
22 #include "hitrace_meter.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_data_manager.h"
25 #include "medialibrary_db_const.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_napi_log.h"
28 #include "medialibrary_peer_info.h"
29 #include "medialibrary_tracer.h"
30 #include "smart_album_napi.h"
31 #include "directory_ex.h"
32 #include "file_ex.h"
33 #include "uv.h"
34 #include "result_set_utils.h"
35 #include "string_ex.h"
36 #include "string_wrapper.h"
37 #include "userfile_client.h"
38
39 using namespace std;
40 using namespace OHOS::AppExecFwk;
41 using namespace OHOS::NativeRdb;
42 using namespace OHOS::DataShare;
43
44 namespace OHOS {
45 namespace Media {
46 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
47 const int32_t NUM_2 = 2;
48 const int32_t NUM_3 = 3;
49 const string DATE_FUNCTION = "DATE(";
50
51 std::mutex MediaLibraryNapi::sUserFileClientMutex_;
52
53 static map<string, ListenerType> ListenerTypeMaps = {
54 {"audioChange", AUDIO_LISTENER},
55 {"videoChange", VIDEO_LISTENER},
56 {"imageChange", IMAGE_LISTENER},
57 {"fileChange", FILE_LISTENER},
58 {"albumChange", ALBUM_LISTENER},
59 {"deviceChange", DEVICE_LISTENER},
60 {"remoteFileChange", REMOTEFILE_LISTENER}
61 };
62
63 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
64 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
65 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
66 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
67 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
68 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
69 using CompleteCallback = napi_async_complete_callback;
70 using Context = MediaLibraryAsyncContext* ;
71
72 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
73 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
74 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
75 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
76 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
77
MediaLibraryNapi()78 MediaLibraryNapi::MediaLibraryNapi()
79 : resultNapiType_(ResultNapiType::TYPE_NAPI_MAX), env_(nullptr) {}
80
81 MediaLibraryNapi::~MediaLibraryNapi() = default;
82
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)83 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
84 {
85 MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
86 if (mediaLibrary != nullptr) {
87 delete mediaLibrary;
88 mediaLibrary = nullptr;
89 }
90 }
91
Init(napi_env env,napi_value exports)92 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
93 {
94 napi_property_descriptor media_library_properties[] = {
95 DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
96 DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
97 DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
98 DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
99 DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
100 DECLARE_NAPI_FUNCTION("on", JSOnCallback),
101 DECLARE_NAPI_FUNCTION("off", JSOffCallback),
102 DECLARE_NAPI_FUNCTION("release", JSRelease),
103 DECLARE_NAPI_FUNCTION("getSmartAlbums", JSGetSmartAlbums),
104 DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
105 DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
106 DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
107 DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
108 DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
109 DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
110 DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
111 };
112 napi_property_descriptor static_prop[] = {
113 DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
114 DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
115 DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
116 DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
117 DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env))
118 };
119 napi_value ctorObj;
120 napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
121 MediaLibraryNapiConstructor, nullptr,
122 sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
123 media_library_properties, &ctorObj);
124 if (status == napi_ok) {
125 int32_t refCount = 1;
126 if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
127 status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
128 if (status == napi_ok && napi_define_properties(env, exports,
129 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
130 return exports;
131 }
132 }
133 }
134 return nullptr;
135 }
136
UserFileMgrInit(napi_env env,napi_value exports)137 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
138 {
139 NapiClassInfo info = {
140 USERFILE_MGR_NAPI_CLASS_NAME,
141 &userFileMgrConstructor_,
142 MediaLibraryNapiConstructor,
143 {
144 DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
145 DECLARE_NAPI_FUNCTION("getPhotoAssets", UserFileMgrGetPhotoAssets),
146 DECLARE_NAPI_FUNCTION("getAudioAssets", UserFileMgrGetAudioAssets),
147 DECLARE_NAPI_FUNCTION("getPhotoAlbums", UserFileMgrGetAlbums),
148 DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreateAsset),
149 DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
150 DECLARE_NAPI_FUNCTION("on", JSOnCallback),
151 DECLARE_NAPI_FUNCTION("off", JSOffCallback),
152 DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
153 DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
154 DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
155 DECLARE_NAPI_FUNCTION("release", JSRelease),
156 }
157 };
158 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
159
160 const std::vector<napi_property_descriptor> staticProps = {
161 DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
162 DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
163 DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
164 DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
165 DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
166 DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
167 DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env))
168 };
169 MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
170 return exports;
171 }
172
173 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)174 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
175 {
176 napi_status status;
177 napi_value result = nullptr;
178 napi_value thisVar = nullptr;
179 MediaLibraryTracer tracer;
180
181 tracer.Start("MediaLibraryNapiConstructor");
182
183 NAPI_CALL(env, napi_get_undefined(env, &result));
184 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
185 if (status != napi_ok || thisVar == nullptr) {
186 NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
187 return result;
188 }
189
190 unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
191 if (obj == nullptr) {
192 return result;
193 }
194 obj->env_ = env;
195 // Initialize the ChangeListener object
196 if (g_listObj == nullptr) {
197 g_listObj = make_unique<ChangeListenerNapi>(env);
198 }
199
200 std::unique_lock<std::mutex> helperLock(sUserFileClientMutex_);
201 if (!UserFileClient::IsValid()) {
202 UserFileClient::Init(env, info);
203 if (!UserFileClient::IsValid()) {
204 NAPI_ERR_LOG("UserFileClient creation failed");
205 napi_get_undefined(env, &(result));
206 return result;
207 }
208 }
209 helperLock.unlock();
210
211 status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
212 MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
213 if (status == napi_ok) {
214 obj.release();
215 return thisVar;
216 } else {
217 NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
218 }
219
220 return result;
221 }
222
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref)223 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref)
224 {
225 constexpr size_t ARG_CONTEXT = 1;
226 size_t argc = ARG_CONTEXT;
227 napi_value argv[ARG_CONTEXT] = {0};
228
229 napi_value thisVar = nullptr;
230 napi_value ctor = nullptr;
231 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
232 NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
233
234 napi_value result = nullptr;
235 NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
236 return result;
237 }
238
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)239 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
240 {
241 MediaLibraryTracer tracer;
242 tracer.Start("getMediaLibrary");
243
244 napi_value result = nullptr;
245 napi_value ctor;
246 size_t argc = ARGS_ONE;
247 napi_value argv[ARGS_ONE] = {0};
248 napi_value thisVar = nullptr;
249 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
250 napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
251 if (status == napi_ok) {
252 status = napi_new_instance(env, ctor, argc, argv, &result);
253 if (status == napi_ok) {
254 return result;
255 } else {
256 NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
257 }
258 } else {
259 NAPI_ERR_LOG("status = %{public}d", status);
260 }
261
262 napi_get_undefined(env, &result);
263
264 return result;
265 }
266
GetUserFileMgr(napi_env env,napi_callback_info info)267 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
268 {
269 MediaLibraryTracer tracer;
270 tracer.Start("getUserFileManager");
271
272 return CreateNewInstance(env, info, userFileMgrConstructor_);
273 }
274
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)275 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
276 const string &name, int32_t enumValue)
277 {
278 napi_value enumNapiValue;
279 napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
280 if (status == napi_ok) {
281 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
282 }
283 return status;
284 }
285
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)286 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
287 {
288 napi_value result = nullptr;
289 NAPI_CALL(env, napi_create_object(env, &result));
290 for (size_t i = 0; i < properties.size(); i++) {
291 NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], i + offset));
292 }
293 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
294 return result;
295 }
296
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)297 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
298 const string &name, string enumValue)
299 {
300 napi_value enumNapiValue;
301 napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
302 if (status == napi_ok) {
303 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
304 }
305 return status;
306 }
307
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)308 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
309 {
310 napi_value result = nullptr;
311 NAPI_CALL(env, napi_create_object(env, &result));
312 for (unsigned int i = 0; i < properties.size(); i++) {
313 NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
314 }
315 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
316 return result;
317 }
318
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)319 static void DealWithCommonParam(napi_env env, napi_value arg,
320 const MediaLibraryAsyncContext &context, bool &err, bool &present)
321 {
322 MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
323 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
324 char buffer[PATH_MAX];
325 size_t res = 0;
326 napi_value property = nullptr;
327 napi_has_named_property(env, arg, "selections", &present);
328 if (present) {
329 if ((napi_get_named_property(env, arg, "selections", &property) != napi_ok) ||
330 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
331 NAPI_ERR_LOG("Could not get the string argument!");
332 err = true;
333 return;
334 } else {
335 asyncContext->selection = buffer;
336 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
337 }
338 present = false;
339 }
340
341 napi_has_named_property(env, arg, "order", &present);
342 if (present) {
343 if ((napi_get_named_property(env, arg, "order", &property) != napi_ok) ||
344 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
345 NAPI_ERR_LOG("Could not get the string argument!");
346 err = true;
347 return;
348 } else {
349 asyncContext->order = buffer;
350 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
351 }
352 present = false;
353 }
354
355 napi_has_named_property(env, arg, "uri", &present);
356 if (present) {
357 if ((napi_get_named_property(env, arg, "uri", &property) != napi_ok)||
358 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
359 NAPI_ERR_LOG("Could not get the uri property!");
360 err = true;
361 return;
362 }
363 asyncContext->uri = buffer;
364 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
365 present = false;
366 }
367
368 napi_has_named_property(env, arg, "networkId", &present);
369 if (present) {
370 if ((napi_get_named_property(env, arg, "networkId", &property) != napi_ok) ||
371 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
372 NAPI_ERR_LOG("Could not get the networkId string argument!");
373 err = true;
374 return;
375 } else {
376 asyncContext->networkId = buffer;
377 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
378 }
379 present = false;
380 }
381 napi_has_named_property(env, arg, "extendArgs", &present);
382 if (present) {
383 if ((napi_get_named_property(env, arg, "extendArgs", &property) != napi_ok) ||
384 (napi_get_value_string_utf8(env, property, buffer, PATH_MAX, &res) != napi_ok)) {
385 NAPI_ERR_LOG("Could not get the extendArgs string argument!");
386 err = true;
387 return;
388 } else {
389 asyncContext->extendArgs = buffer;
390 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
391 }
392 present = false;
393 }
394 }
395
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)396 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
397 {
398 MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
399 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
400 napi_value property = nullptr;
401 napi_value stringItem = nullptr;
402 bool present = false;
403 DealWithCommonParam(env, arg, context, err, present);
404 napi_has_named_property(env, arg, "selectionArgs", &present);
405 if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
406 uint32_t len = 0;
407 napi_get_array_length(env, property, &len);
408 char buffer[PATH_MAX];
409 for (size_t i = 0; i < len; i++) {
410 napi_get_element(env, property, i, &stringItem);
411 size_t res = 0;
412 napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
413 asyncContext->selectionArgs.push_back(string(buffer));
414 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
415 }
416 } else {
417 NAPI_ERR_LOG("Could not get the string argument!");
418 err = true;
419 }
420 }
421
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)422 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
423 MediaLibraryAsyncContext &asyncContext)
424 {
425 bool err = false;
426 const int32_t refCount = 1;
427 auto context = &asyncContext;
428
429 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
430 for (size_t i = PARAM0; i < argc; i++) {
431 napi_valuetype valueType = napi_undefined;
432 napi_typeof(env, argv[i], &valueType);
433
434 if (i == PARAM0 && valueType == napi_object) {
435 GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
436 } else if (i == PARAM0 && valueType == napi_function) {
437 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
438 break;
439 } else if (i == PARAM1 && valueType == napi_function) {
440 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
441 break;
442 } else {
443 NAPI_ASSERT(env, false, "type mismatch");
444 }
445 if (err) {
446 NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
447 NAPI_ASSERT(env, false, "type mismatch");
448 }
449 }
450
451 // Return true napi_value if params are successfully obtained
452 napi_value result;
453 napi_get_boolean(env, true, &result);
454 return result;
455 }
456
GetPublicDirectoryExecute(napi_env env,void * data)457 static void GetPublicDirectoryExecute(napi_env env, void *data)
458 {
459 MediaLibraryTracer tracer;
460 tracer.Start("GetPublicDirectoryExecute");
461
462 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
463 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
464
465 vector<string> selectionArgs;
466 vector<string> columns;
467 DataSharePredicates predicates;
468 NAPI_ERR_LOG("context->dirType is = %{public}d", context->dirType);
469 selectionArgs.push_back(to_string(context->dirType));
470 predicates.SetWhereClause(CATEGORY_MEDIATYPE_DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
471 predicates.SetWhereArgs(selectionArgs);
472 string queryUri = MEDIALIBRARY_DIRECTORY_URI;
473 Uri uri(queryUri);
474
475 shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns);
476 if (resultSet != nullptr) {
477 auto count = 0;
478 auto ret = resultSet->GetRowCount(count);
479 if (ret != NativeRdb::E_OK) {
480 NAPI_ERR_LOG("get rdbstore failed");
481 context->error = JS_INNER_FAIL;
482 return;
483 }
484 if (count == 0) {
485 NAPI_ERR_LOG("Query for get publicDirectory form db failed");
486 context->error = JS_INNER_FAIL;
487 return;
488 }
489 NAPI_ERR_LOG("Query for get publicDirectory count = %{private}d", count);
490 if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
491 context->directoryRelativePath = get<string>(
492 ResultSetUtils::GetValFromColumn(CATEGORY_MEDIATYPE_DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
493 }
494 return;
495 } else {
496 context->SaveError(resultSet);
497 NAPI_ERR_LOG("Query for get publicDirectory failed");
498 }
499 }
500
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)501 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
502 {
503 MediaLibraryTracer tracer;
504 tracer.Start("GetPublicDirectoryCallbackComplete");
505
506 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
507 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
508 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
509 jsContext->status = false;
510 if (context->error == ERR_DEFAULT) {
511 napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
512 jsContext->status = true;
513 napi_get_undefined(env, &jsContext->error);
514 } else {
515 context->HandleError(env, jsContext->error);
516 napi_get_undefined(env, &jsContext->data);
517 }
518
519 tracer.Finish();
520 if (context->work != nullptr) {
521 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
522 context->work, *jsContext);
523 }
524
525 delete context;
526 }
527
JSGetPublicDirectory(napi_env env,napi_callback_info info)528 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
529 {
530 napi_status status;
531 napi_value result = nullptr;
532 size_t argc = ARGS_TWO;
533 napi_value argv[ARGS_TWO] = {0};
534 napi_value thisVar = nullptr;
535 const int32_t refCount = 1;
536
537 MediaLibraryTracer tracer;
538 tracer.Start("JSGetPublicDirectory");
539
540 GET_JS_ARGS(env, info, argc, argv, thisVar);
541 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
542 napi_get_undefined(env, &result);
543
544 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
545 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
546 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
547 for (size_t i = PARAM0; i < argc; i++) {
548 napi_valuetype valueType = napi_undefined;
549 napi_typeof(env, argv[i], &valueType);
550
551 if (i == PARAM0 && valueType == napi_number) {
552 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
553 } else if (i == PARAM1 && valueType == napi_function) {
554 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
555 break;
556 } else {
557 NAPI_ASSERT(env, false, "type mismatch");
558 }
559 }
560 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
561 GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
562 }
563
564 return result;
565 }
566
GetFileAssetUpdatePredicates(MediaLibraryAsyncContext * context)567 static void GetFileAssetUpdatePredicates(MediaLibraryAsyncContext *context)
568 {
569 context->predicates.NotEqualTo(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_ALBUM);
570 context->predicates.EqualTo(MEDIA_DATA_DB_DATE_TRASHED, 0);
571 MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
572 if (!context->uri.empty()) {
573 NAPI_ERR_LOG("context->uri is = %{public}s", context->uri.c_str());
574 string fileId;
575 MediaLibraryNapiUtils::GetNetworkIdAndFileIdFromUri(context->uri, context->networkId, fileId);
576 if (!fileId.empty()) {
577 context->predicates.EqualTo(MEDIA_DATA_DB_ID, fileId);
578 }
579 }
580 }
581
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)582 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
583 {
584 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
585 GetFileAssetUpdatePredicates(context);
586 return;
587 }
588
589 string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
590 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
591 context->selectionArgs.emplace_back("0");
592
593 string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
594 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
595 context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
596
597 if (!context->uri.empty()) {
598 NAPI_ERR_LOG("context->uri is = %{public}s", context->uri.c_str());
599 context->networkId = MediaLibraryDataManagerUtils::GetNetworkIdFromUri(context->uri);
600 string fileId = MediaLibraryDataManagerUtils::GetIdFromUri(context->uri);
601 if (!fileId.empty()) {
602 string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
603 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
604 context->selectionArgs.emplace_back(fileId);
605 }
606 }
607 }
608
GetFileAssetsExecute(napi_env env,void * data)609 static void GetFileAssetsExecute(napi_env env, void *data)
610 {
611 MediaLibraryTracer tracer;
612 tracer.Start("GetFileAssetsExecute");
613
614 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
615 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
616
617 GetFileAssetUpdateSelections(context);
618
619 // fetch columns from fileAsset in medialibrary.d.ts
620 static const vector<string> FILE_ASSET_COLUMNS = {
621 MEDIA_DATA_DB_ID, MEDIA_DATA_DB_URI, MEDIA_DATA_DB_MIME_TYPE, MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_DATA_DB_NAME,
622 MEDIA_DATA_DB_TITLE, MEDIA_DATA_DB_RELATIVE_PATH, MEDIA_DATA_DB_PARENT_ID, MEDIA_DATA_DB_SIZE,
623 MEDIA_DATA_DB_DATE_ADDED, MEDIA_DATA_DB_DATE_MODIFIED, MEDIA_DATA_DB_DATE_TAKEN, MEDIA_DATA_DB_ARTIST,
624 MEDIA_DATA_DB_WIDTH, MEDIA_DATA_DB_HEIGHT, MEDIA_DATA_DB_ORIENTATION, MEDIA_DATA_DB_DURATION,
625 MEDIA_DATA_DB_BUCKET_ID, MEDIA_DATA_DB_BUCKET_NAME, MEDIA_DATA_DB_IS_TRASH, MEDIA_DATA_DB_IS_FAV
626 };
627 if (context->fetchColumn.size() == 0) {
628 context->fetchColumn = FILE_ASSET_COLUMNS;
629 }
630
631 if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
632 string group(" GROUP BY (");
633 group += context->extendArgs + " )";
634 context->selection += group;
635 context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
636 }
637
638 context->predicates.SetWhereClause(context->selection);
639 context->predicates.SetWhereArgs(context->selectionArgs);
640 context->predicates.SetOrder(context->order);
641
642 string queryUri = MEDIALIBRARY_DATA_URI;
643 if (!context->networkId.empty()) {
644 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
645 }
646 MediaLibraryNapiUtils::UriAddFragmentTypeMask(queryUri, context->typeMask);
647 NAPI_DEBUG_LOG("queryUri is = %{public}s", queryUri.c_str());
648 Uri uri(queryUri);
649 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
650 context->predicates, context->fetchColumn);
651 if (resultSet != nullptr) {
652 // Create FetchResult object using the contents of resultSet
653 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
654 context->fetchFileResult->SetNetworkId(context->networkId);
655 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
656 context->fetchFileResult->resultNapiType_ = context->resultNapiType;
657 }
658 return;
659 } else {
660 context->SaveError(resultSet);
661 NAPI_ERR_LOG("Query for get fileAssets failed");
662 }
663 }
664
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)665 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
666 unique_ptr<JSAsyncContextOutput> &jsContext)
667 {
668 // Create FetchResult object using the contents of resultSet
669 if (context->fetchFileResult == nullptr) {
670 NAPI_ERR_LOG("No fetch file result found!");
671 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
672 "Failed to obtain Fetch File Result");
673 return;
674 }
675 if (context->fetchFileResult->GetCount() < 0) {
676 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
677 "find no data by options");
678 return;
679 }
680 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
681 if (fileResult == nullptr) {
682 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
683 "Failed to create js object for Fetch File Result");
684 } else {
685 jsContext->data = fileResult;
686 jsContext->status = true;
687 napi_get_undefined(env, &jsContext->error);
688 }
689 }
690
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)691 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
692 {
693 MediaLibraryTracer tracer;
694 tracer.Start("GetFileAssetsAsyncCallbackComplete");
695
696 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
697 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
698
699 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
700 jsContext->status = false;
701 napi_get_undefined(env, &jsContext->data);
702
703 if (context->error != ERR_DEFAULT) {
704 context->HandleError(env, jsContext->error);
705 } else {
706 GetNapiFileResult(env, context, jsContext);
707 }
708
709 tracer.Finish();
710 if (context->work != nullptr) {
711 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
712 context->work, *jsContext);
713 }
714 delete context;
715 }
716
JSGetFileAssets(napi_env env,napi_callback_info info)717 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
718 {
719 napi_status status;
720 napi_value result = nullptr;
721 size_t argc = ARGS_TWO;
722 napi_value argv[ARGS_TWO] = {0};
723 napi_value thisVar = nullptr;
724
725 MediaLibraryTracer tracer;
726 tracer.Start("JSGetFileAssets");
727
728 GET_JS_ARGS(env, info, argc, argv, thisVar);
729 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
730 napi_get_undefined(env, &result);
731
732 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
733 asyncContext->mediaTypes.clear();
734 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
735 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
736 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
737 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
738 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
739
740 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
741 GetFileAssetsAsyncCallbackComplete);
742 }
743
744 return result;
745 }
746
GetFileMediaTypeUri(MediaType mediaType,const string & networkId)747 static string GetFileMediaTypeUri(MediaType mediaType, const string &networkId)
748 {
749 string uri = MEDIALIBRARY_DATA_ABILITY_PREFIX + networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
750 switch (mediaType) {
751 case MEDIA_TYPE_AUDIO:
752 return uri + MEDIALIBRARY_TYPE_AUDIO_URI;
753 break;
754 case MEDIA_TYPE_VIDEO:
755 return uri + MEDIALIBRARY_TYPE_VIDEO_URI;
756 break;
757 case MEDIA_TYPE_IMAGE:
758 return uri + MEDIALIBRARY_TYPE_IMAGE_URI;
759 break;
760 case MEDIA_TYPE_ALBUM:
761 return uri + MEDIALIBRARY_TYPE_ALBUM_URI;
762 break;
763 case MEDIA_TYPE_SMARTALBUM:
764 return uri + MEDIALIBRARY_TYPE_SMART_URI;
765 break;
766 case MEDIA_TYPE_FILE:
767 default:
768 return uri + MEDIALIBRARY_TYPE_FILE_URI;
769 break;
770 }
771 }
772
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)773 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
774 {
775 MediaLibraryTracer tracer;
776 tracer.Start("SetAlbumCoverUri");
777 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
778 DataShare::DataSharePredicates predicates;
779 predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
780 predicates.SetWhereArgs({ std::to_string(album->GetAlbumId()) });
781 predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC");
782 vector<string> columns;
783 string queryUri = MEDIALIBRARY_DATA_URI;
784 if (!context->networkId.empty()) {
785 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
786 NAPI_DEBUG_LOG("querycoverUri is = %{public}s", queryUri.c_str());
787 }
788 Uri uri(queryUri);
789 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
790 uri, predicates, columns);
791 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
792 fetchFileResult->SetNetworkId(context->networkId);
793 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
794 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
795 string coverUri = fileAsset->GetUri();
796 album->SetCoverUri(coverUri);
797 NAPI_DEBUG_LOG("coverUri is = %{public}s", album->GetCoverUri().c_str());
798 }
799
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)800 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
801 const string &networkId)
802 {
803 // Get album id index and value
804 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
805 TYPE_INT32)));
806
807 // Get album title index and value
808 albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
809 TYPE_STRING)));
810
811 // Get album asset count index and value
812 albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
813 albumData->SetAlbumUri(GetFileMediaTypeUri(MEDIA_TYPE_ALBUM, networkId) +
814 "/" + to_string(albumData->GetAlbumId()));
815 // Get album relativePath index and value
816 albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
817 resultSet, TYPE_STRING)));
818 albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
819 resultSet, TYPE_INT64)));
820 }
821
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)822 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
823 {
824 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
825 context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
826 context->fetchAlbumResult->SetNetworkId(context->networkId);
827 context->fetchAlbumResult->resultNapiType_ = context->resultNapiType;
828 context->fetchAlbumResult->typeMask_ = context->typeMask;
829 return;
830 }
831
832 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
833 unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
834 if (albumData != nullptr) {
835 SetAlbumData(albumData.get(), resultSet, context->networkId);
836 SetAlbumCoverUri(context, albumData);
837 albumData->SetAlbumTypeMask(context->typeMask);
838 context->albumNativeArray.push_back(move(albumData));
839 } else {
840 context->SaveError(E_NO_MEMORY);
841 }
842 }
843 }
844
GetResultDataExecute(napi_env env,void * data)845 static void GetResultDataExecute(napi_env env, void *data)
846 {
847 MediaLibraryTracer tracer;
848 tracer.Start("GetResultDataExecute");
849
850 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
851 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
852
853 MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
854 context->predicates.SetWhereClause(context->selection);
855 context->predicates.SetWhereArgs(context->selectionArgs);
856 if (!context->order.empty()) {
857 context->predicates.SetOrder(context->order);
858 }
859
860 vector<string> columns;
861 string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
862 if (!context->networkId.empty()) {
863 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
864 MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
865 NAPI_DEBUG_LOG("queryAlbumUri is = %{public}s", queryUri.c_str());
866 }
867 MediaLibraryNapiUtils::UriAddFragmentTypeMask(queryUri, context->typeMask);
868 Uri uri(queryUri);
869 shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns);
870
871 if (resultSet == nullptr) {
872 NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr");
873 context->SaveError(resultSet);
874 return;
875 }
876
877 GetAlbumResult(context, resultSet);
878 }
879
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)880 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
881 unique_ptr<JSAsyncContextOutput> &jsContext)
882 {
883 if (context->albumNativeArray.empty()) {
884 napi_value albumNoArray = nullptr;
885 napi_create_array(env, &albumNoArray);
886 jsContext->status = true;
887 napi_get_undefined(env, &jsContext->error);
888 jsContext->data = albumNoArray;
889 } else {
890 napi_value albumArray = nullptr;
891 napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
892 for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
893 napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
894 napi_set_element(env, albumArray, i, albumNapiObj);
895 }
896 jsContext->status = true;
897 napi_get_undefined(env, &jsContext->error);
898 jsContext->data = albumArray;
899 }
900 }
901
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)902 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
903 unique_ptr<JSAsyncContextOutput> &jsContext)
904 {
905 if (context->fetchAlbumResult->GetCount() < 0) {
906 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
907 "find no data by options");
908 } else {
909 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
910 if (fileResult == nullptr) {
911 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
912 "Failed to create js object for Fetch Album Result");
913 } else {
914 jsContext->data = fileResult;
915 jsContext->status = true;
916 napi_get_undefined(env, &jsContext->error);
917 }
918 }
919 }
920
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)921 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
922 unique_ptr<JSAsyncContextOutput> &jsContext)
923 {
924 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
925 MediaLibAlbumsAsyncResult(env, context, jsContext);
926 } else {
927 UserFileMgrAlbumsAsyncResult(env, context, jsContext);
928 }
929 }
930
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)931 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
932 {
933 MediaLibraryTracer tracer;
934 tracer.Start("AlbumsAsyncCallbackComplete");
935
936 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
937 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
938 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
939 jsContext->status = false;
940 napi_get_undefined(env, &jsContext->error);
941 if (context->error != ERR_DEFAULT) {
942 napi_get_undefined(env, &jsContext->data);
943 context->HandleError(env, jsContext->error);
944 } else {
945 AlbumsAsyncResult(env, context, jsContext);
946 }
947
948 tracer.Finish();
949 if (context->work != nullptr) {
950 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
951 context->work, *jsContext);
952 }
953 delete context;
954 }
955
JSGetAlbums(napi_env env,napi_callback_info info)956 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
957 {
958 napi_status status;
959 napi_value result = nullptr;
960 size_t argc = ARGS_TWO;
961 napi_value argv[ARGS_TWO] = {0};
962 napi_value thisVar = nullptr;
963
964 MediaLibraryTracer tracer;
965 tracer.Start("JSGetAlbums");
966
967 GET_JS_ARGS(env, info, argc, argv, thisVar);
968 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
969 napi_get_undefined(env, &result);
970
971 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
972 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
973 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
974 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
975 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
976
977 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
978 AlbumsAsyncCallbackComplete);
979 }
980
981 return result;
982 }
983
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)984 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
985 {
986 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
987 vector<string> columns;
988 DataShare::DataSharePredicates predicates;
989
990 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
991 predicates.SetWhereArgs({ std::to_string(id) });
992
993 string queryUri = MEDIALIBRARY_DATA_URI;
994 MediaLibraryNapiUtils::UriAddFragmentTypeMask(queryUri, context->typeMask);
995 Uri uri(queryUri);
996
997 auto resultSet = UserFileClient::Query(uri, predicates, columns);
998 CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
999
1000 // Create FetchResult object using the contents of resultSet
1001 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1002 CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1003 context->fetchFileResult->SetNetworkId(networkId);
1004 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1005 context->fetchFileResult->resultNapiType_ = context->resultNapiType;
1006 }
1007 if (context->fetchFileResult->GetCount() < 1) {
1008 NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1009 return;
1010 }
1011 unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1012 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1013 context->fileAsset = std::move(fileAsset);
1014 }
1015
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1016 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1017 {
1018 MediaLibraryTracer tracer;
1019 tracer.Start("JSCreateAssetCompleteCallback");
1020
1021 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1022 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1023
1024 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1025 jsContext->status = false;
1026 napi_value jsFileAsset = nullptr;
1027
1028 if (context->error == ERR_DEFAULT) {
1029 if (context->fileAsset == nullptr) {
1030 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1031 "Obtain file asset failed");
1032 napi_get_undefined(env, &jsContext->data);
1033 } else {
1034 jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1035 if (jsFileAsset == nullptr) {
1036 NAPI_ERR_LOG("Failed to get file asset napi object");
1037 napi_get_undefined(env, &jsContext->data);
1038 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1039 "Failed to create js object for FileAsset");
1040 } else {
1041 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1042 jsContext->data = jsFileAsset;
1043 napi_get_undefined(env, &jsContext->error);
1044 jsContext->status = true;
1045 }
1046 }
1047 } else {
1048 context->HandleError(env, jsContext->error);
1049 napi_get_undefined(env, &jsContext->data);
1050 }
1051
1052 tracer.Finish();
1053 if (context->work != nullptr) {
1054 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1055 context->work, *jsContext);
1056 }
1057
1058 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback OUT");
1059 delete context;
1060 }
1061
CheckTitlePrams(MediaLibraryAsyncContext * context)1062 static bool CheckTitlePrams(MediaLibraryAsyncContext *context)
1063 {
1064 if (context == nullptr) {
1065 NAPI_ERR_LOG("Async context is null");
1066 return false;
1067 }
1068 bool isValid = false;
1069 string title = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1070 if (!isValid) {
1071 NAPI_ERR_LOG("getting title is invalid");
1072 return false;
1073 }
1074 if (title.empty()) {
1075 return false;
1076 }
1077 return true;
1078 }
1079
GetFirstDirName(const string & relativePath)1080 static string GetFirstDirName(const string &relativePath)
1081 {
1082 string firstDirName = "";
1083 if (!relativePath.empty()) {
1084 string::size_type pos = relativePath.find_first_of('/');
1085 if (pos == relativePath.length()) {
1086 return relativePath;
1087 }
1088 firstDirName = relativePath.substr(0, pos + 1);
1089 NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
1090 }
1091 return firstDirName;
1092 }
1093
IsDirectory(const string & dirName)1094 static bool IsDirectory(const string &dirName)
1095 {
1096 struct stat statInfo {};
1097 if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == SUCCESS) {
1098 if (statInfo.st_mode & S_IFDIR) {
1099 return true;
1100 }
1101 }
1102
1103 return false;
1104 }
1105
CheckTypeOfType(const std::string & firstDirName,int32_t fileMediaType)1106 static bool CheckTypeOfType(const std::string &firstDirName, int32_t fileMediaType)
1107 {
1108 // "CDSA/"
1109 if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
1110 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1111 return true;
1112 } else {
1113 return false;
1114 }
1115 }
1116 // "Movies/"
1117 if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
1118 if (fileMediaType == MEDIA_TYPE_VIDEO) {
1119 return true;
1120 } else {
1121 return false;
1122 }
1123 }
1124 if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_2].c_str())) {
1125 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1126 return true;
1127 } else {
1128 NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
1129 return false;
1130 }
1131 }
1132 if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_3].c_str())) {
1133 if (fileMediaType == MEDIA_TYPE_AUDIO) {
1134 return true;
1135 } else {
1136 return false;
1137 }
1138 }
1139 return true;
1140 }
CheckRelativePathPrams(MediaLibraryAsyncContext * context)1141 static bool CheckRelativePathPrams(MediaLibraryAsyncContext *context)
1142 {
1143 if (context == nullptr) {
1144 NAPI_ERR_LOG("Async context is null");
1145 return false;
1146 }
1147 bool isValid = false;
1148 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1149 if (!isValid) {
1150 NAPI_DEBUG_LOG("getting relativePath is invalid");
1151 return false;
1152 }
1153 isValid = false;
1154 int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
1155 if (!isValid) {
1156 NAPI_DEBUG_LOG("getting fileMediaType is invalid");
1157 return false;
1158 }
1159 if (relativePath.empty()) {
1160 NAPI_DEBUG_LOG("CheckRelativePathPrams relativePath is empty");
1161 return false;
1162 }
1163
1164 if (IsDirectory(relativePath)) {
1165 NAPI_DEBUG_LOG("CheckRelativePathPrams relativePath exist return true");
1166 return true;
1167 }
1168
1169 string firstDirName = GetFirstDirName(relativePath);
1170 if (!firstDirName.empty() && IsDirectory(firstDirName)) {
1171 NAPI_DEBUG_LOG("CheckRelativePathPrams firstDirName exist return true");
1172 return true;
1173 }
1174
1175 if (!firstDirName.empty()) {
1176 NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1177 for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
1178 NAPI_DEBUG_LOG("directoryEnumValues%{public}d = %{public}s", i, directoryEnumValues[i].c_str());
1179 if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
1180 return CheckTypeOfType(firstDirName, fileMediaType);
1181 }
1182 }
1183 NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
1184 }
1185 NAPI_DEBUG_LOG("CheckRelativePathPrams return false");
1186 return false;
1187 }
1188
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1189 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
1190 MediaLibraryAsyncContext &asyncContext)
1191 {
1192 const int32_t refCount = 1;
1193 napi_value result = nullptr;
1194 auto context = &asyncContext;
1195 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1196 int32_t fileMediaType = 0;
1197 size_t res = 0;
1198 char relativePathBuffer[PATH_MAX];
1199 char titleBuffer[PATH_MAX];
1200 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1201
1202 for (size_t i = PARAM0; i < argc; i++) {
1203 napi_valuetype valueType = napi_undefined;
1204 napi_typeof(env, argv[i], &valueType);
1205 if (i == PARAM0 && valueType == napi_number) {
1206 napi_get_value_int32(env, argv[i], &fileMediaType);
1207 } else if (i == PARAM1 && valueType == napi_string) {
1208 napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
1209 NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
1210 } else if (i == PARAM2 && valueType == napi_string) {
1211 napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
1212 NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
1213 } else if (i == PARAM3 && valueType == napi_function) {
1214 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1215 } else {
1216 NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
1217 return result;
1218 }
1219 }
1220
1221 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
1222 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
1223 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
1224 NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
1225 // Return true napi_value if params are successfully obtained
1226 napi_get_boolean(env, true, &result);
1227 return result;
1228 }
1229
JSCreateAssetExecute(napi_env env,void * data)1230 static void JSCreateAssetExecute(napi_env env, void *data)
1231 {
1232 MediaLibraryTracer tracer;
1233 tracer.Start("JSCreateAssetExecute");
1234
1235 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1236 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1237
1238 if (!CheckTitlePrams(context)) {
1239 context->error = JS_E_DISPLAYNAME;
1240 return;
1241 }
1242 if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathPrams(context))) {
1243 context->error = JS_E_RELATIVEPATH;
1244 return;
1245 }
1246 string uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1247 MediaLibraryNapiUtils::UriAddFragmentTypeMask(uri, context->typeMask);
1248 Uri createFileUri(uri);
1249 int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
1250 if (index < 0) {
1251 context->SaveError(index);
1252 } else {
1253 getFileAssetById(index, "", context);
1254 }
1255 }
1256
JSCreateAsset(napi_env env,napi_callback_info info)1257 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
1258 {
1259 napi_status status;
1260 napi_value result = nullptr;
1261 size_t argc = ARGS_FOUR;
1262 napi_value argv[ARGS_FOUR] = {0};
1263 napi_value thisVar = nullptr;
1264
1265 MediaLibraryTracer tracer;
1266 tracer.Start("JSCreateAsset");
1267
1268 GET_JS_ARGS(env, info, argc, argv, thisVar);
1269 NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
1270 napi_get_undefined(env, &result);
1271
1272 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1273 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1274 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
1275 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1276 result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
1277 ASSERT_NULLPTR_CHECK(env, result);
1278
1279 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
1280 JSCreateAssetCompleteCallback);
1281 }
1282
1283 return result;
1284 }
1285
JSDeleteAssetExecute(napi_env env,void * data)1286 static void JSDeleteAssetExecute(napi_env env, void *data)
1287 {
1288 MediaLibraryTracer tracer;
1289 tracer.Start("JSDeleteAssetExecute");
1290
1291 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1292 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1293
1294 string mediaType;
1295 string deleteId;
1296 bool isValid = false;
1297 string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
1298 if (!isValid) {
1299 context->error = ERR_INVALID_OUTPUT;
1300 return;
1301 }
1302 size_t index = notifyUri.rfind('/');
1303 if (index != string::npos) {
1304 deleteId = notifyUri.substr(index + 1);
1305 notifyUri = notifyUri.substr(0, index);
1306 size_t indexType = notifyUri.rfind('/');
1307 if (indexType != string::npos) {
1308 mediaType = notifyUri.substr(indexType + 1);
1309 }
1310 }
1311 notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
1312 NAPI_DEBUG_LOG("JSDeleteAssetExcute notifyUri = %{public}s", notifyUri.c_str());
1313 string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET + "/" + deleteId;
1314 MediaLibraryNapiUtils::UriAddFragmentTypeMask(deleteUri, context->typeMask);
1315 Uri deleteAssetUri(deleteUri);
1316 int retVal = UserFileClient::Delete(deleteAssetUri, {});
1317 if (retVal < 0) {
1318 context->SaveError(retVal);
1319 } else {
1320 context->retVal = retVal;
1321 Uri deleteNotify(notifyUri);
1322 UserFileClient::NotifyChange(deleteNotify);
1323 }
1324 }
1325
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)1326 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
1327 {
1328 MediaLibraryTracer tracer;
1329 tracer.Start("JSDeleteAssetCompleteCallback");
1330
1331 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1332 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1333 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1334 jsContext->status = false;
1335
1336 if (context->error == ERR_DEFAULT) {
1337 NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
1338 napi_create_int32(env, context->retVal, &jsContext->data);
1339 napi_get_undefined(env, &jsContext->error);
1340 jsContext->status = true;
1341 } else {
1342 context->HandleError(env, jsContext->error);
1343 napi_get_undefined(env, &jsContext->data);
1344 }
1345
1346 tracer.Finish();
1347 if (context->work != nullptr) {
1348 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1349 context->work, *jsContext);
1350 }
1351
1352 delete context;
1353 }
1354
JSTrashAssetExecute(napi_env env,void * data)1355 static void JSTrashAssetExecute(napi_env env, void *data)
1356 {
1357 MediaLibraryTracer tracer;
1358 tracer.Start("JSTrashAssetExecute");
1359
1360 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1361 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1362
1363 string uri = context->uri;
1364 if (uri.empty()) {
1365 context->error = ERR_INVALID_OUTPUT;
1366 return;
1367 }
1368 MediaLibraryNapiUtils::UriRemoveAllFragment(uri);
1369 string trashId = MediaLibraryDataManagerUtils::GetIdFromUri(uri);
1370
1371 DataShareValuesBucket valuesBucket;
1372 valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, TRASH_ALBUM_ID_VALUES);
1373 valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, stoi(trashId));
1374 string trashUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/" +
1375 MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM;
1376 MediaLibraryNapiUtils::UriAddFragmentTypeMask(trashUri, context->typeMask);
1377 Uri trashAssetUri(trashUri);
1378 int retVal = UserFileClient::Insert(trashAssetUri, valuesBucket);
1379 context->SaveError(retVal);
1380 }
1381
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)1382 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
1383 {
1384 MediaLibraryTracer tracer;
1385 tracer.Start("JSTrashAssetCompleteCallback");
1386
1387 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1388 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1389 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1390 CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1391 jsContext->status = false;
1392 napi_get_undefined(env, &jsContext->data);
1393 if (context->error == ERR_DEFAULT) {
1394 jsContext->status = true;
1395 Media::MediaType mediaType = MediaLibraryNapiUtils::GetMediaTypeFromUri(context->uri);
1396 string notifyUri = MediaLibraryNapiUtils::GetMediaTypeUri(mediaType);
1397 Uri modifyNotify(notifyUri);
1398 UserFileClient::NotifyChange(modifyNotify);
1399 } else {
1400 context->HandleError(env, jsContext->error);
1401 }
1402 if (context->work != nullptr) {
1403 tracer.Finish();
1404 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1405 context->work, *jsContext);
1406 }
1407
1408 delete context;
1409 }
1410
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1411 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
1412 MediaLibraryAsyncContext &asyncContext)
1413 {
1414 const int32_t refCount = 1;
1415 napi_value result = nullptr;
1416 auto context = &asyncContext;
1417 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1418 size_t res = 0;
1419 char buffer[PATH_MAX];
1420
1421 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1422
1423 for (size_t i = PARAM0; i < argc; i++) {
1424 napi_valuetype valueType = napi_undefined;
1425 napi_typeof(env, argv[i], &valueType);
1426
1427 if (i == PARAM0 && valueType == napi_string) {
1428 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
1429 } else if (i == PARAM1 && valueType == napi_function) {
1430 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1431 break;
1432 } else {
1433 NAPI_ASSERT(env, false, "type mismatch");
1434 }
1435 }
1436
1437 context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
1438
1439 // Return true napi_value if params are successfully obtained
1440 napi_get_boolean(env, true, &result);
1441 return result;
1442 }
1443
JSDeleteAsset(napi_env env,napi_callback_info info)1444 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
1445 {
1446 napi_status status;
1447 napi_value result = nullptr;
1448 size_t argc = ARGS_TWO;
1449 napi_value argv[ARGS_TWO] = {0};
1450 napi_value thisVar = nullptr;
1451
1452 MediaLibraryTracer tracer;
1453 tracer.Start("JSDeleteAsset");
1454
1455 GET_JS_ARGS(env, info, argc, argv, thisVar);
1456 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1457 napi_get_undefined(env, &result);
1458
1459 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1460 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
1461 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1462 result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
1463 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1464
1465 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
1466 JSDeleteAssetCompleteCallback);
1467 }
1468
1469 return result;
1470 }
1471
OnChange(const MediaChangeListener & listener,const napi_ref cbRef)1472 void ChangeListenerNapi::OnChange(const MediaChangeListener &listener, const napi_ref cbRef)
1473 {
1474 uv_loop_s *loop = nullptr;
1475 napi_get_uv_event_loop(env_, &loop);
1476 if (loop == nullptr) {
1477 return;
1478 }
1479
1480 uv_work_t *work = new (std::nothrow) uv_work_t;
1481 if (work == nullptr) {
1482 return;
1483 }
1484
1485 UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef);
1486 if (msg == nullptr) {
1487 delete work;
1488 return;
1489 }
1490 work->data = reinterpret_cast<void *>(msg);
1491
1492 int ret = uv_queue_work(loop, work, [](uv_work_t *w) {}, [](uv_work_t *w, int s) {
1493 // js thread
1494 if (w == nullptr) {
1495 return;
1496 }
1497
1498 UvChangeMsg *msg = reinterpret_cast<UvChangeMsg *>(w->data);
1499 do {
1500 if (msg == nullptr) {
1501 NAPI_ERR_LOG("UvChangeMsg is null");
1502 break;
1503 }
1504 napi_env env = msg->env_;
1505 napi_value result[ARGS_TWO] = { nullptr };
1506 napi_get_undefined(env, &result[PARAM0]);
1507 napi_get_undefined(env, &result[PARAM1]);
1508 napi_value jsCallback = nullptr;
1509 napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
1510 if (status != napi_ok) {
1511 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
1512 break;
1513 }
1514 napi_value retVal = nullptr;
1515 napi_call_function(env, nullptr, jsCallback, ARGS_TWO, result, &retVal);
1516 if (status != napi_ok) {
1517 NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
1518 break;
1519 }
1520 } while (0);
1521 delete msg;
1522 delete w;
1523 });
1524 if (ret != 0) {
1525 NAPI_ERR_LOG("Failed to execute libuv work queue, ret: %{public}d", ret);
1526 delete msg;
1527 delete work;
1528 }
1529 }
1530
GetListenerType(const std::string & str) const1531 int32_t MediaLibraryNapi::GetListenerType(const std::string &str) const
1532 {
1533 auto iter = ListenerTypeMaps.find(str);
1534 if (iter == ListenerTypeMaps.end()) {
1535 NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
1536 return INVALID_LISTENER;
1537 }
1538
1539 return iter->second;
1540 }
1541
RegisterChange(napi_env env,const std::string & type,ChangeListenerNapi & listObj)1542 void MediaLibraryNapi::RegisterChange(napi_env env, const std::string &type, ChangeListenerNapi &listObj)
1543 {
1544 NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
1545
1546 int32_t typeEnum = GetListenerType(type);
1547 switch (typeEnum) {
1548 case AUDIO_LISTENER:
1549 listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
1550 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
1551 break;
1552 case VIDEO_LISTENER:
1553 listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
1554 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
1555 break;
1556 case IMAGE_LISTENER:
1557 listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
1558 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
1559 break;
1560 case FILE_LISTENER:
1561 listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
1562 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
1563 break;
1564 case SMARTALBUM_LISTENER:
1565 listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
1566 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
1567 listObj.smartAlbumDataObserver_);
1568 break;
1569 case DEVICE_LISTENER:
1570 listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
1571 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
1572 break;
1573 case REMOTEFILE_LISTENER:
1574 listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
1575 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
1576 break;
1577 case ALBUM_LISTENER:
1578 listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
1579 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
1580 break;
1581 default:
1582 NAPI_ERR_LOG("Invalid Media Type!");
1583 }
1584 }
1585
JSOnCallback(napi_env env,napi_callback_info info)1586 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
1587 {
1588 napi_value undefinedResult = nullptr;
1589 size_t argc = ARGS_TWO;
1590 napi_value argv[ARGS_TWO] = {nullptr};
1591 napi_value thisVar = nullptr;
1592 size_t res = 0;
1593 char buffer[ARG_BUF_SIZE];
1594 string type;
1595 const int32_t refCount = 1;
1596 MediaLibraryNapi *obj = nullptr;
1597 napi_status status;
1598
1599 MediaLibraryTracer tracer;
1600 tracer.Start("JSOnCallback");
1601
1602 napi_get_undefined(env, &undefinedResult);
1603 GET_JS_ARGS(env, info, argc, argv, thisVar);
1604 NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
1605 if (thisVar == nullptr || argv[PARAM0] == nullptr || argv[PARAM1] == nullptr) {
1606 NAPI_ERR_LOG("Failed to retrieve details about the callback");
1607 return undefinedResult;
1608 }
1609
1610 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
1611 if (status == napi_ok && obj != nullptr) {
1612 napi_valuetype valueType = napi_undefined;
1613 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
1614 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
1615 return undefinedResult;
1616 }
1617
1618 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
1619 NAPI_ERR_LOG("Failed to get value string utf8 for type");
1620 return undefinedResult;
1621 }
1622 type = string(buffer);
1623
1624 napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
1625
1626 tracer.Start("RegisterChange");
1627 obj->RegisterChange(env, type, *g_listObj);
1628 tracer.Finish();
1629 }
1630
1631 return undefinedResult;
1632 }
1633
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)1634 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
1635 {
1636 NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
1637
1638 MediaType mediaType;
1639 int32_t typeEnum = GetListenerType(type);
1640
1641 switch (typeEnum) {
1642 case AUDIO_LISTENER:
1643 CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
1644 mediaType = MEDIA_TYPE_AUDIO;
1645 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
1646 listObj.audioDataObserver_ = nullptr;
1647 break;
1648 case VIDEO_LISTENER:
1649 CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
1650 mediaType = MEDIA_TYPE_VIDEO;
1651 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
1652 listObj.videoDataObserver_ = nullptr;
1653 break;
1654 case IMAGE_LISTENER:
1655 CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
1656 mediaType = MEDIA_TYPE_IMAGE;
1657 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
1658 listObj.imageDataObserver_ = nullptr;
1659 break;
1660 case FILE_LISTENER:
1661 CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
1662 mediaType = MEDIA_TYPE_FILE;
1663 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
1664 listObj.fileDataObserver_ = nullptr;
1665 break;
1666 case SMARTALBUM_LISTENER:
1667 CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
1668 mediaType = MEDIA_TYPE_SMARTALBUM;
1669 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
1670 listObj.smartAlbumDataObserver_);
1671 listObj.smartAlbumDataObserver_ = nullptr;
1672 break;
1673 case DEVICE_LISTENER:
1674 CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
1675 mediaType = MEDIA_TYPE_DEVICE;
1676 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
1677 listObj.deviceDataObserver_ = nullptr;
1678 break;
1679 case REMOTEFILE_LISTENER:
1680 CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
1681 mediaType = MEDIA_TYPE_REMOTEFILE;
1682 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
1683 listObj.remoteFileDataObserver_ = nullptr;
1684 break;
1685 case ALBUM_LISTENER:
1686 CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
1687 mediaType = MEDIA_TYPE_ALBUM;
1688 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
1689 listObj.albumDataObserver_ = nullptr;
1690 break;
1691 default:
1692 NAPI_ERR_LOG("Invalid Media Type");
1693 return;
1694 }
1695
1696 if (listObj.cbOffRef_ != nullptr) {
1697 MediaChangeListener listener;
1698 listener.mediaType = mediaType;
1699 listObj.OnChange(listener, listObj.cbOffRef_);
1700 }
1701 }
1702
JSOffCallback(napi_env env,napi_callback_info info)1703 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
1704 {
1705 napi_value undefinedResult = nullptr;
1706 size_t argc = ARGS_TWO;
1707 napi_value argv[ARGS_TWO] = {nullptr};
1708 napi_value thisVar = nullptr;
1709 size_t res = 0;
1710 char buffer[ARG_BUF_SIZE];
1711 const int32_t refCount = 1;
1712 string type;
1713 MediaLibraryNapi *obj = nullptr;
1714 napi_status status;
1715
1716 MediaLibraryTracer tracer;
1717 tracer.Start("JSOffCallback");
1718
1719 napi_get_undefined(env, &undefinedResult);
1720 GET_JS_ARGS(env, info, argc, argv, thisVar);
1721 NAPI_ASSERT(env, ARGS_ONE <= argc && argc<= ARGS_TWO, "requires one or two parameters");
1722 if (thisVar == nullptr || argv[PARAM0] == nullptr) {
1723 NAPI_ERR_LOG("Failed to retrieve details about the callback");
1724 return undefinedResult;
1725 }
1726
1727 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
1728 if (status == napi_ok && obj != nullptr) {
1729 napi_valuetype valueType = napi_undefined;
1730 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
1731 return undefinedResult;
1732 }
1733
1734 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
1735 NAPI_ERR_LOG("Failed to get value string utf8 for type");
1736 return undefinedResult;
1737 }
1738 type = string(buffer);
1739
1740 if (argc == ARGS_TWO) {
1741 if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
1742 g_listObj == nullptr) {
1743 return undefinedResult;
1744 }
1745
1746 napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
1747 }
1748
1749 tracer.Start("UnregisterChange");
1750 obj->UnregisterChange(env, type, *g_listObj);
1751 tracer.Finish();
1752 }
1753
1754 return undefinedResult;
1755 }
1756
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)1757 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
1758 MediaLibraryAsyncContext *context)
1759 {
1760 MediaLibraryTracer tracer;
1761 tracer.Start("JSReleaseCompleteCallback");
1762
1763 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1764
1765 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1766 jsContext->status = false;
1767 if (context->objectInfo != nullptr) {
1768 context->objectInfo->~MediaLibraryNapi();
1769 napi_create_int32(env, SUCCESS, &jsContext->data);
1770 jsContext->status = true;
1771 napi_get_undefined(env, &jsContext->error);
1772 } else {
1773 NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
1774 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1775 "UserFileClient is invalid");
1776 napi_get_undefined(env, &jsContext->data);
1777 }
1778
1779 tracer.Finish();
1780 if (context->work != nullptr) {
1781 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1782 context->work, *jsContext);
1783 }
1784
1785 delete context;
1786 }
1787
JSRelease(napi_env env,napi_callback_info info)1788 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
1789 {
1790 napi_status status;
1791 napi_value result = nullptr;
1792 size_t argc = ARGS_ONE;
1793 napi_value argv[ARGS_ONE] = {0};
1794 napi_value thisVar = nullptr;
1795 napi_value resource = nullptr;
1796 int32_t refCount = 1;
1797
1798 MediaLibraryTracer tracer;
1799 tracer.Start("JSRelease");
1800
1801 GET_JS_ARGS(env, info, argc, argv, thisVar);
1802 NAPI_ERR_LOG("NAPI_ASSERT begin %{public}zu", argc);
1803 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
1804 NAPI_ERR_LOG("NAPI_ASSERT end");
1805 napi_get_undefined(env, &result);
1806
1807 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1808 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
1809 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1810 if (argc == PARAM1) {
1811 napi_valuetype valueType = napi_undefined;
1812 napi_typeof(env, argv[PARAM0], &valueType);
1813 if (valueType == napi_function) {
1814 napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
1815 }
1816 }
1817 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1818
1819 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1820 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRelease", asyncContext);
1821
1822 status = napi_create_async_work(
1823 env, nullptr, resource, [](napi_env env, void* data) {},
1824 reinterpret_cast<CompleteCallback>(JSReleaseCompleteCallback),
1825 static_cast<void*>(asyncContext.get()), &asyncContext->work);
1826 if (status != napi_ok) {
1827 napi_get_undefined(env, &result);
1828 } else {
1829 napi_queue_async_work(env, asyncContext->work);
1830 asyncContext.release();
1831 }
1832 }
1833
1834 return result;
1835 }
1836
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)1837 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
1838 {
1839 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1840 if (smartAlbum->GetAlbumCapacity() == 0) {
1841 return;
1842 }
1843 DataShare::DataSharePredicates predicates;
1844 string trashPrefix;
1845 if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
1846 trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
1847 } else {
1848 trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
1849 }
1850 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
1851 context->selectionArgs.emplace_back("0");
1852 context->selectionArgs.emplace_back(std::to_string(smartAlbum->GetAlbumId()));
1853 predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC");
1854 predicates.SetWhereClause(context->selection);
1855 predicates.SetWhereArgs(context->selectionArgs);
1856 std::vector<std::string> columns;
1857 Uri uri(MEDIALIBRARY_DATA_URI + "/"
1858 + MEDIA_ALBUMOPRN_QUERYALBUM + "/"
1859 + ASSETMAP_VIEW_NAME);
1860
1861 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns);
1862 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1863 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1864 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
1865 string coverUri = fileAsset->GetUri();
1866 smartAlbum->SetCoverUri(coverUri);
1867 NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
1868 }
1869
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)1870 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1871 MediaLibraryAsyncContext *context)
1872 {
1873 CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
1874 smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
1875 smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
1876 TYPE_STRING)));
1877 smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_CAPACITY,
1878 resultSet, TYPE_INT32)));
1879 smartAlbumData->SetAlbumUri(GetFileMediaTypeUri(MEDIA_TYPE_SMARTALBUM, context->networkId) +
1880 "/" + to_string(smartAlbumData->GetAlbumId()));
1881 smartAlbumData->SetTypeMask(context->typeMask);
1882 }
1883
GetAllSmartAlbumResultDataExecute(napi_env env,void * data)1884 static void GetAllSmartAlbumResultDataExecute(napi_env env, void *data)
1885 {
1886 MediaLibraryTracer tracer;
1887 tracer.Start("GetResultDataExecute");
1888
1889 auto context = static_cast<MediaLibraryAsyncContext *>(data);
1890 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1891 NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
1892
1893 if (context->privateAlbumType == TYPE_TRASH) {
1894 context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
1895 NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
1896 }
1897 if (context->privateAlbumType == TYPE_FAVORITE) {
1898 context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
1899 NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
1900 }
1901
1902 vector<string> columns;
1903 string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
1904 if (!context->networkId.empty()) {
1905 uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
1906 "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
1907 }
1908 MediaLibraryNapiUtils::UriAddFragmentTypeMask(uriStr, context->typeMask);
1909 Uri uri(uriStr);
1910 auto resultSet = UserFileClient::Query(uri, context->predicates, columns);
1911 if (resultSet == nullptr) {
1912 NAPI_ERR_LOG("resultSet == nullptr");
1913 return;
1914 }
1915
1916 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1917 context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
1918 context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
1919 context->fetchSmartAlbumResult->resultNapiType_ = context->resultNapiType;
1920 context->fetchSmartAlbumResult->typeMask_ = context->typeMask;
1921 return;
1922 }
1923 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1924 unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
1925 SetSmartAlbumData(albumData.get(), resultSet, context);
1926 SetSmartAlbumCoverUri(context, albumData);
1927
1928 context->privateSmartAlbumNativeArray.push_back(move(albumData));
1929 }
1930 }
1931
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1932 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1933 unique_ptr<JSAsyncContextOutput> &jsContext)
1934 {
1935 if (context->smartAlbumData != nullptr) {
1936 NAPI_ERR_LOG("context->smartAlbumData != nullptr");
1937 jsContext->status = true;
1938 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
1939 napi_get_undefined(env, &jsContext->error);
1940 jsContext->data = albumNapiObj;
1941 } else if (!context->privateSmartAlbumNativeArray.empty()) {
1942 NAPI_ERR_LOG("context->privateSmartAlbumNativeArray.empty()");
1943 jsContext->status = true;
1944 napi_value albumArray = nullptr;
1945 napi_create_array(env, &albumArray);
1946 for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
1947 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
1948 context->privateSmartAlbumNativeArray[i]);
1949 napi_set_element(env, albumArray, i, albumNapiObj);
1950 }
1951 napi_get_undefined(env, &jsContext->error);
1952 jsContext->data = albumArray;
1953 } else {
1954 NAPI_ERR_LOG("No fetch file result found!");
1955 napi_get_undefined(env, &jsContext->data);
1956 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1957 "Failed to obtain Fetch File Result");
1958 }
1959 }
1960
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1961 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1962 unique_ptr<JSAsyncContextOutput> &jsContext)
1963 {
1964 if (context->fetchSmartAlbumResult->GetCount() < 0) {
1965 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1966 "find no data by options");
1967 } else {
1968 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
1969 if (fileResult == nullptr) {
1970 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1971 "Failed to create js object for Fetch SmartAlbum Result");
1972 } else {
1973 jsContext->data = fileResult;
1974 jsContext->status = true;
1975 napi_get_undefined(env, &jsContext->error);
1976 }
1977 }
1978 }
1979
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1980 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1981 unique_ptr<JSAsyncContextOutput> &jsContext)
1982 {
1983 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1984 MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
1985 } else {
1986 UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
1987 }
1988 }
1989
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)1990 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
1991 {
1992 MediaLibraryTracer tracer;
1993 tracer.Start("GetPrivateAlbumCallbackComplete");
1994
1995 auto context = static_cast<MediaLibraryAsyncContext *>(data);
1996 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1997 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1998 jsContext->status = false;
1999 napi_get_undefined(env, &jsContext->error);
2000 if (context->error != ERR_DEFAULT) {
2001 napi_get_undefined(env, &jsContext->data);
2002 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2003 "Query for get fileAssets failed");
2004 } else {
2005 SmartAlbumsAsyncResult(env, context, jsContext);
2006 }
2007
2008 tracer.Finish();
2009 if (context->work != nullptr) {
2010 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2011 context->work, *jsContext);
2012 }
2013 delete context;
2014 }
2015
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)2016 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
2017 {
2018 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2019 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2020 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2021 jsContext->status = false;
2022 napi_get_undefined(env, &jsContext->error);
2023 if (context->error != ERR_DEFAULT) {
2024 napi_get_undefined(env, &jsContext->data);
2025 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2026 "Query for get smartAlbums failed");
2027 } else {
2028 if (!context->smartAlbumNativeArray.empty()) {
2029 jsContext->status = true;
2030 napi_value albumArray = nullptr;
2031 napi_create_array(env, &albumArray);
2032 for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
2033 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
2034 context->smartAlbumNativeArray[i]);
2035 napi_set_element(env, albumArray, i, albumNapiObj);
2036 }
2037 napi_get_undefined(env, &jsContext->error);
2038 jsContext->data = albumArray;
2039 } else {
2040 NAPI_ERR_LOG("No SmartAlbums result found!");
2041 napi_get_undefined(env, &jsContext->data);
2042 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2043 "Failed to obtain SmartAlbums Result");
2044 }
2045 }
2046 if (context->work != nullptr) {
2047 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2048 context->work, *jsContext);
2049 }
2050 delete context;
2051 }
2052
JSGetSmartAlbums(napi_env env,napi_callback_info info)2053 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
2054 {
2055 napi_status status;
2056 napi_value result = nullptr;
2057 size_t argc = ARGS_TWO;
2058 napi_value argv[ARGS_TWO] = {0};
2059 napi_value thisVar = nullptr;
2060
2061 GET_JS_ARGS(env, info, argc, argv, thisVar);
2062 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2063 napi_get_undefined(env, &result);
2064 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2065 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
2066 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2067 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2068 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
2069 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2070
2071 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
2072 GetAllSmartAlbumResultDataExecute, SmartAlbumsAsyncCallbackComplete);
2073 }
2074
2075 return result;
2076 }
2077
JSGetPrivateAlbum(napi_env env,napi_callback_info info)2078 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
2079 {
2080 napi_status status;
2081 napi_value result = nullptr;
2082 size_t argc = ARGS_TWO;
2083 napi_value argv[ARGS_TWO] = {0};
2084 napi_value thisVar = nullptr;
2085 const int32_t refCount = 1;
2086
2087 GET_JS_ARGS(env, info, argc, argv, thisVar);
2088 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2089 napi_get_undefined(env, &result);
2090 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2091 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2092 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2093 for (size_t i = PARAM0; i < argc; i++) {
2094 napi_valuetype valueType = napi_undefined;
2095 napi_typeof(env, argv[i], &valueType);
2096 if (i == PARAM0 && valueType == napi_number) {
2097 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
2098 } else if (i == PARAM1 && valueType == napi_function) {
2099 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
2100 break;
2101 } else {
2102 NAPI_ASSERT(env, false, "type mismatch");
2103 }
2104 }
2105 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
2106 GetAllSmartAlbumResultDataExecute, GetPrivateAlbumCallbackComplete);
2107 }
2108 return result;
2109 }
2110
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2111 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
2112 MediaLibraryAsyncContext &asyncContext)
2113 {
2114 const int32_t refCount = 1;
2115 napi_value result = nullptr;
2116 auto context = &asyncContext;
2117 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2118 size_t res = 0;
2119 char buffer[PATH_MAX];
2120 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2121 for (size_t i = PARAM0; i < argc; i++) {
2122 napi_valuetype valueType = napi_undefined;
2123 napi_typeof(env, argv[i], &valueType);
2124 if (i == PARAM0 && valueType == napi_string) {
2125 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2126 } else if (i == PARAM1 && valueType == napi_function) {
2127 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2128 break;
2129 } else {
2130 NAPI_ASSERT(env, false, "type mismatch");
2131 }
2132 }
2133 context->valuesBucket.Put(SMARTALBUM_DB_NAME, string(buffer));
2134 napi_get_boolean(env, true, &result);
2135 return result;
2136 }
2137
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2138 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
2139 MediaLibraryAsyncContext *context)
2140 {
2141 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2142 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2143 jsContext->status = false;
2144 if (context->error == ERR_DEFAULT) {
2145 if (context->smartAlbumNativeArray.empty()) {
2146 NAPI_ERR_LOG("No albums found");
2147 napi_get_undefined(env, &jsContext->data);
2148 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2149 "No albums found");
2150 } else {
2151 jsContext->status = true;
2152 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumNativeArray[0]);
2153 jsContext->data = albumNapiObj;
2154 napi_get_undefined(env, &jsContext->error);
2155 }
2156 } else {
2157 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2158 "File asset creation failed");
2159 napi_get_undefined(env, &jsContext->data);
2160 }
2161 if (context->work != nullptr) {
2162 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2163 context->work, *jsContext);
2164 }
2165 delete context;
2166 }
2167
JSCreateSmartAlbum(napi_env env,napi_callback_info info)2168 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
2169 {
2170 napi_status status;
2171 napi_value result = nullptr;
2172 size_t argc = ARGS_TWO;
2173 napi_value argv[ARGS_TWO] = {0};
2174 napi_value thisVar = nullptr;
2175 napi_value resource = nullptr;
2176
2177 GET_JS_ARGS(env, info, argc, argv, thisVar);
2178 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2179 napi_get_undefined(env, &result);
2180 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2181 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2182 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2183 result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
2184 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2185 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2186 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
2187 status = napi_create_async_work(
2188 env, nullptr, resource, [](napi_env env, void *data) {
2189 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2190 string abilityUri = MEDIALIBRARY_DATA_URI;
2191 Uri CreateSmartAlbumUri(abilityUri + "/" + MEDIA_SMARTALBUMOPRN + "/" +
2192 MEDIA_SMARTALBUMOPRN_CREATEALBUM);
2193 int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
2194 if (retVal > 0) {
2195 context->selection = SMARTALBUM_DB_ID + " = ?";
2196 context->selectionArgs = {std::to_string(retVal)};
2197 context->retVal = retVal;
2198 } else {
2199 context->error = retVal;
2200 }
2201 },
2202 reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
2203 static_cast<void*>(asyncContext.get()), &asyncContext->work);
2204 if (status != napi_ok) {
2205 napi_get_undefined(env, &result);
2206 } else {
2207 napi_queue_async_work(env, asyncContext->work);
2208 asyncContext.release();
2209 }
2210 }
2211 return result;
2212 }
2213
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2214 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
2215 MediaLibraryAsyncContext &asyncContext)
2216 {
2217 const int32_t refCount = 1;
2218 napi_value result = nullptr;
2219 auto context = &asyncContext;
2220 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2221 size_t res = 0;
2222 char buffer[PATH_MAX];
2223 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2224 for (size_t i = PARAM0; i < argc; i++) {
2225 napi_valuetype valueType = napi_undefined;
2226 napi_typeof(env, argv[i], &valueType);
2227 if (i == PARAM0 && valueType == napi_string) {
2228 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2229 } else if (i == PARAM1 && valueType == napi_function) {
2230 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2231 break;
2232 } else {
2233 NAPI_ASSERT(env, false, "type mismatch");
2234 }
2235 }
2236 std::string coverUri = string(buffer);
2237 std::string strRow;
2238 string::size_type pos = coverUri.find_last_of('/');
2239 strRow = coverUri.substr(pos + 1);
2240 context->valuesBucket.Put(SMARTALBUM_DB_ID, std::stoi(strRow));
2241 napi_get_boolean(env, true, &result);
2242 return result;
2243 }
2244
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2245 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
2246 MediaLibraryAsyncContext *context)
2247 {
2248 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2249 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2250 jsContext->status = false;
2251 if (context->error == ERR_DEFAULT) {
2252 napi_create_int32(env, context->retVal, &jsContext->data);
2253 napi_get_undefined(env, &jsContext->error);
2254 jsContext->status = true;
2255 } else {
2256 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2257 "UserFileClient is invalid");
2258 napi_get_undefined(env, &jsContext->data);
2259 }
2260 if (context->work != nullptr) {
2261 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2262 context->work, *jsContext);
2263 }
2264 delete context;
2265 }
2266
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)2267 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
2268 {
2269 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2270 bool isValid = false;
2271 int32_t smartAlbumId = context->valuesBucket.Get(SMARTALBUM_DB_ID, isValid);
2272 if (!isValid) {
2273 context->error = ERR_INVALID_OUTPUT;
2274 return;
2275 }
2276 string abilityUri = MEDIALIBRARY_DATA_URI;
2277 Uri DeleteSmartAlbumUri(abilityUri + "/" + MEDIA_SMARTALBUMOPRN + "/" +
2278 MEDIA_SMARTALBUMOPRN_DELETEALBUM + '/' + to_string(smartAlbumId));
2279 DataSharePredicates predicates;
2280 int retVal = UserFileClient::Delete(DeleteSmartAlbumUri, predicates);
2281 NAPI_DEBUG_LOG("JSDeleteSmartAlbumCompleteCallback retVal = %{public}d", retVal);
2282 if (retVal < 0) {
2283 context->error = retVal;
2284 } else {
2285 context->retVal = retVal;
2286 }
2287 }
2288
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)2289 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
2290 {
2291 napi_status status;
2292 napi_value result = nullptr;
2293 size_t argc = ARGS_TWO;
2294 napi_value argv[ARGS_TWO] = {0};
2295 napi_value thisVar = nullptr;
2296 napi_value resource = nullptr;
2297
2298 GET_JS_ARGS(env, info, argc, argv, thisVar);
2299 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2300 napi_get_undefined(env, &result);
2301 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2302 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2303 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2304 result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
2305 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2306 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2307 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
2308 status = napi_create_async_work(
2309 env, nullptr, resource, [](napi_env env, void* data) {
2310 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2311 JSDeleteSmartAlbumExecute(context);
2312 },
2313 reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
2314 static_cast<void*>(asyncContext.get()), &asyncContext->work);
2315 if (status != napi_ok) {
2316 napi_get_undefined(env, &result);
2317 } else {
2318 napi_queue_async_work(env, asyncContext->work);
2319 asyncContext.release();
2320 }
2321 }
2322 return result;
2323 }
2324
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)2325 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
2326 {
2327 napi_value value;
2328 napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
2329 if (status != napi_ok) {
2330 NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
2331 return status;
2332 }
2333 status = napi_set_named_property(env, result, fieldStr, value);
2334 if (status != napi_ok) {
2335 NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
2336 }
2337 return status;
2338 }
2339
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2340 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2341 {
2342 napi_value value;
2343 napi_status status = napi_create_int32(env, intValue, &value);
2344 if (status != napi_ok) {
2345 NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2346 return status;
2347 }
2348 status = napi_set_named_property(env, result, fieldStr, value);
2349 if (status != napi_ok) {
2350 NAPI_ERR_LOG("Set int32 named property error! field: %{public}s", fieldStr);
2351 }
2352 return status;
2353 }
2354
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)2355 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
2356 {
2357 napi_value value = nullptr;
2358 napi_status status = napi_get_boolean(env, boolvalue, &value);
2359 if (status != napi_ok) {
2360 NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
2361 return status;
2362 }
2363 status = napi_set_named_property(env, result, fieldStr, value);
2364 if (status != napi_ok) {
2365 NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
2366 }
2367 return status;
2368 }
2369
PeerInfoToJsArray(const napi_env & env,const std::vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)2370 static void PeerInfoToJsArray(const napi_env &env, const std::vector<unique_ptr<PeerInfo>> &vecPeerInfo,
2371 const int32_t idx, napi_value &arrayResult)
2372 {
2373 if (idx >= (int32_t) vecPeerInfo.size()) {
2374 return;
2375 }
2376 auto info = vecPeerInfo[idx].get();
2377 if (info == nullptr) {
2378 return;
2379 }
2380 napi_value result = nullptr;
2381 napi_create_object(env, &result);
2382 SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
2383 SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
2384 SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
2385 SetValueBool(env, "isOnline", info->isOnline, result);
2386
2387 napi_status status = napi_set_element(env, arrayResult, idx, result);
2388 if (status != napi_ok) {
2389 NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
2390 }
2391 }
2392
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2393 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
2394 MediaLibraryAsyncContext *context)
2395 {
2396 napi_value jsPeerInfoArray = nullptr;
2397
2398 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2399
2400 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2401 jsContext->status = false;
2402 napi_get_undefined(env, &jsContext->data);
2403
2404 vector<std::string> columns;
2405 DataShare::DataSharePredicates predicates;
2406 std::string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
2407 predicates.SetWhereClause(strQueryCondition);
2408 predicates.SetWhereArgs(context->selectionArgs);
2409
2410 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE);
2411 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
2412 uri, predicates, columns);
2413
2414 if (resultSet == nullptr) {
2415 NAPI_ERR_LOG("JSGetActivePeers resultSet is null");
2416 delete context;
2417 return;
2418 }
2419
2420 vector<unique_ptr<PeerInfo>> peerInfoArray;
2421 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2422 unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
2423 if (peerInfo != nullptr) {
2424 peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
2425 TYPE_STRING));
2426 peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
2427 TYPE_STRING));
2428 peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
2429 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
2430 peerInfo->isOnline = true;
2431 peerInfoArray.push_back(move(peerInfo));
2432 }
2433 }
2434
2435 if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
2436 for (size_t i = 0; i < peerInfoArray.size(); ++i) {
2437 PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
2438 }
2439
2440 jsContext->data = jsPeerInfoArray;
2441 napi_get_undefined(env, &jsContext->error);
2442 jsContext->status = true;
2443 } else {
2444 NAPI_DEBUG_LOG("No peer info found!");
2445 napi_get_undefined(env, &jsContext->data);
2446 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2447 "Failed to obtain peer info array from DB");
2448 }
2449
2450 if (context->work != nullptr) {
2451 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2452 context->work, *jsContext);
2453 }
2454
2455 delete context;
2456 }
2457
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2458 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
2459 MediaLibraryAsyncContext *context)
2460 {
2461 napi_value jsPeerInfoArray = nullptr;
2462
2463 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2464
2465 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2466 jsContext->status = false;
2467 napi_get_undefined(env, &jsContext->data);
2468
2469 vector<string> columns;
2470 DataShare::DataSharePredicates predicates;
2471 predicates.SetWhereClause(context->selection);
2472 predicates.SetWhereArgs(context->selectionArgs);
2473
2474 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE);
2475 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
2476 uri, predicates, columns);
2477
2478 if (resultSet == nullptr) {
2479 NAPI_ERR_LOG("JSGetAllPeers resultSet is null");
2480 delete context;
2481 return;
2482 }
2483
2484 vector<unique_ptr<PeerInfo>> peerInfoArray;
2485 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2486 unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
2487 if (peerInfo != nullptr) {
2488 peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
2489 TYPE_STRING));
2490 peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
2491 TYPE_STRING));
2492 peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
2493 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
2494 peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
2495 TYPE_INT32)) == 0);
2496 peerInfoArray.push_back(move(peerInfo));
2497 }
2498 }
2499
2500 if (!peerInfoArray.empty() && (napi_create_array(env, &jsPeerInfoArray) == napi_ok)) {
2501 for (size_t i = 0; i < peerInfoArray.size(); ++i) {
2502 PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
2503 }
2504
2505 jsContext->data = jsPeerInfoArray;
2506 napi_get_undefined(env, &jsContext->error);
2507 jsContext->status = true;
2508 } else {
2509 NAPI_DEBUG_LOG("No peer info found!");
2510 napi_get_undefined(env, &jsContext->data);
2511 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2512 "Failed to obtain peer info array from DB");
2513 }
2514
2515 if (context->work != nullptr) {
2516 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2517 context->work, *jsContext);
2518 }
2519 delete context;
2520 }
2521
JSGetActivePeers(napi_env env,napi_callback_info info)2522 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
2523 {
2524 napi_status status;
2525 napi_value result = nullptr;
2526 const int32_t refCount = 1;
2527 napi_value resource = nullptr;
2528 size_t argc = ARGS_ONE;
2529 napi_value argv[ARGS_ONE] = {0};
2530 napi_value thisVar = nullptr;
2531
2532 MediaLibraryTracer tracer;
2533 tracer.Start("JSGetActivePeers");
2534
2535 GET_JS_ARGS(env, info, argc, argv, thisVar);
2536 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
2537 napi_get_undefined(env, &result);
2538
2539 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2540 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2541 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2542 if (argc == ARGS_ONE) {
2543 GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
2544 }
2545
2546 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2547 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetActivePeers", asyncContext);
2548 status = napi_create_async_work(
2549 env, nullptr, resource, [](napi_env env, void* data) {},
2550 reinterpret_cast<CompleteCallback>(JSGetActivePeersCompleteCallback),
2551 static_cast<void*>(asyncContext.get()), &asyncContext->work);
2552 if (status != napi_ok) {
2553 napi_get_undefined(env, &result);
2554 } else {
2555 napi_queue_async_work(env, asyncContext->work);
2556 asyncContext.release();
2557 }
2558 }
2559
2560 return result;
2561 }
2562
JSGetAllPeers(napi_env env,napi_callback_info info)2563 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
2564 {
2565 napi_status status;
2566 napi_value result = nullptr;
2567 const int32_t refCount = 1;
2568 napi_value resource = nullptr;
2569 size_t argc = ARGS_ONE;
2570 napi_value argv[ARGS_ONE] = {0};
2571 napi_value thisVar = nullptr;
2572
2573 MediaLibraryTracer tracer;
2574 tracer.Start("JSGetAllPeers");
2575
2576 GET_JS_ARGS(env, info, argc, argv, thisVar);
2577 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
2578 napi_get_undefined(env, &result);
2579
2580 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2581 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2582 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2583 if (argc == ARGS_ONE) {
2584 GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
2585 }
2586
2587 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2588 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetAllPeers", asyncContext);
2589 status = napi_create_async_work(
2590 env, nullptr, resource, [](napi_env env, void* data) {},
2591 reinterpret_cast<CompleteCallback>(JSGetAllPeersCompleteCallback),
2592 static_cast<void*>(asyncContext.get()), &asyncContext->work);
2593 if (status != napi_ok) {
2594 napi_get_undefined(env, &result);
2595 } else {
2596 napi_queue_async_work(env, asyncContext->work);
2597 asyncContext.release();
2598 }
2599 }
2600
2601 return result;
2602 }
2603
CloseAsset(MediaLibraryAsyncContext * context,string uri)2604 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
2605 {
2606 string abilityUri = MEDIALIBRARY_DATA_URI;
2607 Uri closeAssetUri(abilityUri + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CLOSEASSET);
2608 context->valuesBucket.Clear();
2609 context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
2610 int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
2611 NAPI_DEBUG_LOG("File close asset %{public}d", ret);
2612 if (ret != E_SUCCESS) {
2613 context->error = ret;
2614 NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
2615 }
2616 return ret;
2617 }
2618
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)2619 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
2620 {
2621 string realPath;
2622 if (!PathToRealPath(context->storeMediaSrc, realPath)) {
2623 NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
2624 context->error = JS_ERR_NO_SUCH_FILE;
2625 return;
2626 }
2627 context->error = JS_E_RELATIVEPATH;
2628 int32_t srcFd = open(realPath.c_str(), O_RDWR);
2629 if (srcFd == -1) {
2630 NAPI_ERR_LOG("src path open fail, %{public}d", errno);
2631 return;
2632 }
2633 struct stat statSrc;
2634 if (fstat(srcFd, &statSrc) == -1) {
2635 close(srcFd);
2636 NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
2637 return;
2638 }
2639 Uri createFileUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET);
2640 int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
2641 if (index < 0) {
2642 close(srcFd);
2643 NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
2644 return;
2645 }
2646 getFileAssetById(index, "", context);
2647 Uri openFileUri(context->fileAsset->GetUri());
2648 int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE);
2649 if (destFd < 0) {
2650 context->error = destFd;
2651 NAPI_DEBUG_LOG("File open asset failed");
2652 close(srcFd);
2653 return;
2654 }
2655 if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
2656 close(srcFd);
2657 close(destFd);
2658 CloseAsset(context, context->fileAsset->GetUri());
2659 NAPI_ERR_LOG("copy file fail %{public}d ", errno);
2660 return;
2661 }
2662 close(srcFd);
2663 close(destFd);
2664 CloseAsset(context, context->fileAsset->GetUri());
2665 context->error = ERR_DEFAULT;
2666 }
2667
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2668 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
2669 MediaLibraryAsyncContext *context)
2670 {
2671 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2672 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2673 CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
2674 jsContext->status = false;
2675 napi_get_undefined(env, &jsContext->data);
2676 if (context->error != ERR_DEFAULT) {
2677 NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
2678 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2679 "storeMediaAsset fail");
2680 } else {
2681 napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
2682 jsContext->status = true;
2683 napi_get_undefined(env, &jsContext->error);
2684 }
2685
2686 if (context->work != nullptr) {
2687 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2688 context->work, *jsContext);
2689 }
2690 delete context;
2691 }
2692
ConvertMediaType(const string & mimeType)2693 static int ConvertMediaType(const string &mimeType)
2694 {
2695 string res;
2696 // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
2697 size_t slash = mimeType.find('/');
2698 if (slash != string::npos) {
2699 res = mimeType.substr(0, slash);
2700 if (res.empty()) {
2701 return MediaType::MEDIA_TYPE_FILE;
2702 }
2703 }
2704 if (res == "image") {
2705 return MediaType::MEDIA_TYPE_IMAGE;
2706 } else if (res == "video") {
2707 return MediaType::MEDIA_TYPE_VIDEO;
2708 } else if (res == "audio") {
2709 return MediaType::MEDIA_TYPE_AUDIO;
2710 }
2711 return MediaType::MEDIA_TYPE_FILE;
2712 }
2713
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)2714 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
2715 {
2716 napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
2717 if (value == nullptr) {
2718 NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
2719 return false;
2720 }
2721 unique_ptr<char[]> tmp;
2722 bool succ;
2723 tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
2724 if (!succ) {
2725 NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
2726 return false;
2727 }
2728 res = string(tmp.get());
2729 return true;
2730 }
2731
GetDefaultDirectory(int mediaType)2732 static string GetDefaultDirectory(int mediaType)
2733 {
2734 string relativePath;
2735 if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
2736 relativePath = "Pictures/";
2737 } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
2738 relativePath = "Videos/";
2739 } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
2740 relativePath = "Audios/";
2741 } else {
2742 relativePath = "Documents/";
2743 }
2744 return relativePath;
2745 }
2746
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)2747 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
2748 MediaLibraryAsyncContext &asyncContext)
2749 {
2750 auto context = &asyncContext;
2751 if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
2752 NAPI_ERR_LOG("param get fail");
2753 return nullptr;
2754 }
2755 string fileName = MediaFileUtils::GetFilename(context->storeMediaSrc);
2756 if (fileName.empty() || (fileName.at(0) == '.')) {
2757 NAPI_ERR_LOG("src file name is not proper");
2758 context->error = JS_E_RELATIVEPATH;
2759 return nullptr;
2760 };
2761 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
2762 string mimeType;
2763 if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
2764 NAPI_ERR_LOG("param get fail");
2765 return nullptr;
2766 }
2767 auto mediaType = ConvertMediaType(mimeType);
2768 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
2769 string relativePath;
2770 if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
2771 NAPI_DEBUG_LOG("optional relativePath param empty");
2772 relativePath = GetDefaultDirectory(mediaType);
2773 }
2774 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
2775 NAPI_DEBUG_LOG("src:%{public}s mime:%{public}s relp:%{private}s filename:%{private}s",
2776 context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
2777 napi_value result = nullptr;
2778 napi_get_undefined(env, &result);
2779 return result;
2780 }
2781
JSStoreMediaAsset(napi_env env,napi_callback_info info)2782 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
2783 {
2784 size_t argc = ARGS_TWO;
2785 napi_value argv[ARGS_TWO] = {0};
2786 napi_value thisVar = nullptr;
2787 GET_JS_ARGS(env, info, argc, argv, thisVar);
2788 napi_value result = nullptr;
2789 napi_get_undefined(env, &result);
2790 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2791 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
2792 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2793 if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
2794 napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
2795 CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
2796 if (argc == ARGS_TWO) {
2797 const int32_t refCount = 1;
2798 GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
2799 }
2800 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2801 napi_value resource = nullptr;
2802 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
2803 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
2804 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2805 JSGetStoreMediaAssetExecute(context);
2806 },
2807 reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
2808 static_cast<void*>(asyncContext.get()), &asyncContext->work);
2809 if (status != napi_ok) {
2810 napi_get_undefined(env, &result);
2811 } else {
2812 napi_queue_async_work(env, asyncContext->work);
2813 asyncContext.release();
2814 }
2815 }
2816 return result;
2817 }
2818
CreateAsyncCallbackInfo(napi_env env)2819 static Ability *CreateAsyncCallbackInfo(napi_env env)
2820 {
2821 if (env == nullptr) {
2822 NAPI_ERR_LOG("env == nullptr.");
2823 return nullptr;
2824 }
2825 napi_status ret;
2826 napi_value global = 0;
2827 const napi_extended_error_info *errorInfo = nullptr;
2828 ret = napi_get_global(env, &global);
2829 if (ret != napi_ok) {
2830 napi_get_last_error_info(env, &errorInfo);
2831 NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
2832 }
2833 napi_value abilityObj = 0;
2834 ret = napi_get_named_property(env, global, "ability", &abilityObj);
2835 if (ret != napi_ok) {
2836 napi_get_last_error_info(env, &errorInfo);
2837 NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
2838 }
2839 Ability *ability = nullptr;
2840 ret = napi_get_value_external(env, abilityObj, (void **)&ability);
2841 if (ret != napi_ok) {
2842 napi_get_last_error_info(env, &errorInfo);
2843 NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
2844 }
2845 return ability;
2846 }
2847
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)2848 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
2849 {
2850 uint32_t arraySize = 0;
2851 if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
2852 NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
2853 return nullptr;
2854 }
2855 string uri = "";
2856 for (uint32_t i = 0; i < arraySize; i++) {
2857 napi_value jsValue = nullptr;
2858 if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
2859 NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
2860 return nullptr;
2861 }
2862 unique_ptr<char[]> inputStr;
2863 bool succ;
2864 tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
2865 if (!succ) {
2866 NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
2867 return nullptr;
2868 }
2869 uri += string(inputStr.get());
2870 uri += ",";
2871 }
2872 context.uri = uri.substr(0, uri.length() - 1);
2873 NAPI_DEBUG_LOG("GetImagePreviewArgs res %{public}s", context.uri.c_str());
2874 napi_value res;
2875 napi_get_undefined(env, &res);
2876 return res;
2877 }
2878
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)2879 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
2880 {
2881 context.imagePreviewIndex = 0;
2882 napi_valuetype valueType = napi_undefined;
2883 napi_typeof(env, param, &valueType);
2884 if (valueType != napi_number) {
2885 NAPI_ERR_LOG("not napi value");
2886 return nullptr;
2887 }
2888 if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
2889 NAPI_ERR_LOG("get property value fail");
2890 }
2891 NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
2892 napi_value res;
2893 napi_get_undefined(env, &res);
2894 return res;
2895 }
2896
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)2897 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
2898 {
2899 if (context->ability_ == nullptr) {
2900 NAPI_ERR_LOG("ability_ is not exist");
2901 context->error = ERR_INVALID_OUTPUT;
2902 return;
2903 }
2904 Want want;
2905 string networkId = "";
2906 string bundleName = "com.ohos.photos";
2907 string abilityName = "com.ohos.photos.MainAbility";
2908 want.SetElementName(networkId, bundleName, abilityName);
2909 want.SetUri(context->uri);
2910 want.SetAction("ohos.want.action.viewData");
2911 want.SetParam("index", context->imagePreviewIndex);
2912 context->error = context->ability_->StartAbility(want);
2913 }
2914
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)2915 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
2916 MediaLibraryAsyncContext *context)
2917 {
2918 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2919 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2920 CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
2921 jsContext->status = true;
2922 napi_get_undefined(env, &jsContext->data);
2923 if (context->error != 0) {
2924 jsContext->status = false;
2925 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2926 "startImagePreview currently fail");
2927 }
2928 if (context->work != nullptr) {
2929 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2930 context->work, *jsContext);
2931 }
2932 delete context;
2933 }
2934
JSStartImagePreview(napi_env env,napi_callback_info info)2935 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
2936 {
2937 size_t argc = ARGS_THREE;
2938 napi_value argv[ARGS_THREE] = {0};
2939 napi_value thisVar = nullptr;
2940 GET_JS_ARGS(env, info, argc, argv, thisVar);
2941 napi_value result = nullptr;
2942 napi_get_undefined(env, &result);
2943 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2944 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
2945 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
2946 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2947 napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
2948 CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
2949 GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
2950 asyncContext->ability_ = CreateAsyncCallbackInfo(env);
2951 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
2952 const int32_t refCount = 1;
2953 if (argc == ARGS_THREE) {
2954 GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
2955 } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
2956 GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
2957 }
2958 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2959 napi_value resource = nullptr;
2960 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
2961 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
2962 auto context = static_cast<MediaLibraryAsyncContext *>(data);
2963 JSStartImagePreviewExecute(context);
2964 },
2965 reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
2966 static_cast<void*>(asyncContext.get()), &asyncContext->work);
2967 if (status != napi_ok) {
2968 napi_get_undefined(env, &result);
2969 } else {
2970 napi_queue_async_work(env, asyncContext->work);
2971 asyncContext.release();
2972 }
2973 }
2974 return result;
2975 }
2976
ParseArgsCreateAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)2977 static napi_value ParseArgsCreateAsset(napi_env env, napi_callback_info info,
2978 unique_ptr<MediaLibraryAsyncContext> &context)
2979 {
2980 constexpr size_t minArgs = ARGS_ONE;
2981 constexpr size_t maxArgs = ARGS_THREE;
2982 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
2983 napi_ok, "Failed to get object info");
2984
2985 /* Set mediaTypes to get typeMask */
2986 vector<uint32_t> mediaTypes;
2987 mediaTypes.push_back(MEDIA_TYPE_IMAGE);
2988 mediaTypes.push_back(MEDIA_TYPE_VIDEO);
2989 MediaLibraryNapiUtils::GenTypeMaskFromArray(mediaTypes, context->typeMask);
2990
2991 /* Parse the first argument into displayName */
2992 string displayName;
2993 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
2994 napi_ok, "Failed to get displayName");
2995 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
2996
2997 /* Parse the second argument into albumUri if exists */
2998 string albumUri;
2999 if ((context->argc >= ARGS_TWO) &&
3000 (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok)) {
3001 context->valuesBucket.Put(MEDIA_DATA_DB_URI, albumUri);
3002 }
3003
3004 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
3005 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
3006 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
3007 vector<uint32_t> types = { mediaType };
3008 MediaLibraryNapiUtils::GenTypeMaskFromArray(types, context->typeMask);
3009 }
3010
3011 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
3012
3013 napi_value result = nullptr;
3014 NAPI_CALL(env, napi_get_boolean(env, true, &result));
3015 return result;
3016 }
3017
AddDefaultFetchColumn(unique_ptr<MediaLibraryAsyncContext> & asyncContext)3018 void AddDefaultFetchColumn(unique_ptr<MediaLibraryAsyncContext> &asyncContext)
3019 {
3020 if (asyncContext->fetchColumn.size() == 0) {
3021 return;
3022 }
3023 asyncContext->fetchColumn.push_back(MEDIA_DATA_DB_ID);
3024 asyncContext->fetchColumn.push_back(MEDIA_DATA_DB_NAME);
3025 asyncContext->fetchColumn.push_back(MEDIA_DATA_DB_MEDIA_TYPE);
3026 }
3027
UserFileMgrGetFileAssets(napi_env env,napi_callback_info info,vector<uint32_t> & mediaTypes)3028 napi_value UserFileMgrGetFileAssets(napi_env env, napi_callback_info info, vector<uint32_t> &mediaTypes)
3029 {
3030 napi_value ret = nullptr;
3031 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3032 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3033
3034 // Parse the first argument into typeMask
3035 asyncContext->mediaTypes = mediaTypes;
3036 MediaLibraryNapiUtils::GenTypeMaskFromArray(mediaTypes, asyncContext->typeMask);
3037
3038 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAssetFetchOptCallback(env, info, asyncContext), asyncContext,
3039 JS_ERR_PARAMETER_INVALID);
3040 AddDefaultFetchColumn(asyncContext);
3041 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3042
3043 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UFMJSGetTypeAssets", GetFileAssetsExecute,
3044 GetFileAssetsAsyncCallbackComplete);
3045 }
3046
UserFileMgrGetPhotoAssets(napi_env env,napi_callback_info info)3047 napi_value MediaLibraryNapi::UserFileMgrGetPhotoAssets(napi_env env, napi_callback_info info)
3048 {
3049 vector<uint32_t> mediaTypes;
3050 mediaTypes.push_back(MEDIA_TYPE_IMAGE);
3051 mediaTypes.push_back(MEDIA_TYPE_VIDEO);
3052 return UserFileMgrGetFileAssets(env, info, mediaTypes);
3053 }
3054
UserFileMgrGetAudioAssets(napi_env env,napi_callback_info info)3055 napi_value MediaLibraryNapi::UserFileMgrGetAudioAssets(napi_env env, napi_callback_info info)
3056 {
3057 vector<uint32_t> mediaTypes;
3058 mediaTypes.push_back(MEDIA_TYPE_AUDIO);
3059 return UserFileMgrGetFileAssets(env, info, mediaTypes);
3060 }
3061
UserFileMgrGetAlbums(napi_env env,napi_callback_info info)3062 napi_value MediaLibraryNapi::UserFileMgrGetAlbums(napi_env env, napi_callback_info info)
3063 {
3064 napi_value ret = nullptr;
3065 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3066 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3067 // Parse the first argument into typeMask
3068 asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE);
3069 asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO);
3070 MediaLibraryNapiUtils::GenTypeMaskFromArray(asyncContext->mediaTypes, asyncContext->typeMask);
3071 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext), asyncContext,
3072 JS_ERR_PARAMETER_INVALID);
3073 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3074
3075 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetAlbums", GetResultDataExecute,
3076 AlbumsAsyncCallbackComplete);
3077 }
3078
UserFileMgrCreateAsset(napi_env env,napi_callback_info info)3079 napi_value MediaLibraryNapi::UserFileMgrCreateAsset(napi_env env, napi_callback_info info)
3080 {
3081 napi_value ret = nullptr;
3082 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3083 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3084 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3085 NAPI_ASSERT(env, ParseArgsCreateAsset(env, info, asyncContext), "Failed to parse js args");
3086
3087 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAsset", JSCreateAssetExecute,
3088 JSCreateAssetCompleteCallback);
3089 }
3090
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)3091 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
3092 {
3093 napi_value ret = nullptr;
3094 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3095 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3096 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3097 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->uri),
3098 asyncContext, JS_ERR_PARAMETER_INVALID);
3099 MediaLibraryNapiUtils::GenTypeMaskFromArray({ MediaLibraryNapiUtils::GetMediaTypeFromUri(asyncContext->uri) },
3100 asyncContext->typeMask);
3101
3102 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
3103 JSTrashAssetCompleteCallback);
3104 }
3105
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)3106 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
3107 {
3108 napi_value ret = nullptr;
3109 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3110 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3111
3112 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext,
3113 asyncContext->privateAlbumType), asyncContext, JS_ERR_PARAMETER_INVALID);
3114 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3115 // PrivateAlbum only support image and video so far
3116 asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE);
3117 asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO);
3118 MediaLibraryNapiUtils::GenTypeMaskFromArray(asyncContext->mediaTypes, asyncContext->typeMask);
3119
3120 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
3121 GetAllSmartAlbumResultDataExecute, GetPrivateAlbumCallbackComplete);
3122 }
3123
CreateMediaTypeEnum(napi_env env)3124 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
3125 {
3126 return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
3127 }
3128
CreateMediaTypeUserFileEnum(napi_env env)3129 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
3130 {
3131 const int32_t startIdx = 1;
3132 return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
3133 }
3134
CreateDirectoryTypeEnum(napi_env env)3135 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
3136 {
3137 return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
3138 }
3139
CreateVirtualAlbumTypeEnum(napi_env env)3140 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
3141 {
3142 return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
3143 }
3144
CreatePrivateAlbumTypeEnum(napi_env env)3145 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
3146 {
3147 return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
3148 }
3149
CreateFileKeyEnum(napi_env env)3150 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
3151 {
3152 return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
3153 }
3154
UserFileMgrCreateFileKeyEnum(napi_env env)3155 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
3156 {
3157 return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
3158 }
3159
CreateAudioKeyEnum(napi_env env)3160 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
3161 {
3162 return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
3163 }
3164
CreateImageVideoKeyEnum(napi_env env)3165 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
3166 {
3167 return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
3168 }
3169
CreateAlbumKeyEnum(napi_env env)3170 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
3171 {
3172 return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
3173 }
3174 } // namespace Media
3175 } // namespace OHOS
3176