1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "SendablePhotoAccessHelper"
17 
18 #include "sendable_photo_access_helper_napi.h"
19 
20 #include <fcntl.h>
21 #include <functional>
22 #include <sys/sendfile.h>
23 
24 #include "ability_context.h"
25 #include "context.h"
26 #include "directory_ex.h"
27 #include "file_ex.h"
28 #include "hitrace_meter.h"
29 #include "location_column.h"
30 #include "media_device_column.h"
31 #include "media_directory_type_column.h"
32 #include "media_file_asset_columns.h"
33 #include "media_change_request_napi.h"
34 #include "media_column.h"
35 #include "media_app_uri_permission_column.h"
36 #include "media_file_uri.h"
37 #include "media_file_utils.h"
38 #include "media_smart_album_column.h"
39 #include "media_smart_map_column.h"
40 #include "medialibrary_client_errno.h"
41 #include "medialibrary_data_manager.h"
42 #include "medialibrary_db_const.h"
43 #include "medialibrary_errno.h"
44 #include "medialibrary_napi_log.h"
45 #include "medialibrary_napi_utils.h"
46 #include "medialibrary_tracer.h"
47 #include "napi_base_context.h"
48 #include "photo_album_column.h"
49 #include "photo_album_napi.h"
50 #include "result_set_utils.h"
51 #include "safe_map.h"
52 #include "search_column.h"
53 #include "sendable_medialibrary_napi_utils.h"
54 #include "sendable_photo_album_napi.h"
55 #include "smart_album_napi.h"
56 #include "story_album_column.h"
57 #include "string_ex.h"
58 #include "string_wrapper.h"
59 #include "userfile_client.h"
60 #include "form_map.h"
61 #include "userfile_manager_types.h"
62 
63 using namespace std;
64 using namespace OHOS::AppExecFwk;
65 using namespace OHOS::NativeRdb;
66 using namespace OHOS::DataShare;
67 
68 namespace OHOS {
69 namespace Media {
70 using ChangeType = AAFwk::ChangeInfo::ChangeType;
71 const string DATE_FUNCTION = "DATE(";
72 
73 mutex SendablePhotoAccessHelper::sUserFileClientMutex_;
74 mutex SendablePhotoAccessHelper::sOnOffMutex_;
75 
76 const std::string SUBTYPE = "subType";
77 const std::string PAH_SUBTYPE = "subtype";
78 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
79 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
80     { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
81     { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
82     { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
83 
84 };
85 
86 const std::string TITLE = "title";
87 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
88     { TITLE, MediaColumn::MEDIA_TITLE }
89 };
90 
91 using CompleteCallback = napi_async_complete_callback;
92 using Context = SendablePhotoAccessHelperAsyncContext* ;
93 
94 thread_local napi_ref SendablePhotoAccessHelper::photoAccessHelperConstructor_ = nullptr;
95 thread_local napi_ref SendablePhotoAccessHelper::sMediaTypeEnumRef_ = nullptr;
96 thread_local napi_ref SendablePhotoAccessHelper::sPhotoSubType_ = nullptr;
97 thread_local napi_ref SendablePhotoAccessHelper::sPositionTypeEnumRef_ = nullptr;
98 thread_local napi_ref SendablePhotoAccessHelper::sAlbumType_ = nullptr;
99 thread_local napi_ref SendablePhotoAccessHelper::sAlbumSubType_ = nullptr;
100 thread_local napi_ref SendablePhotoAccessHelper::sMovingPhotoEffectModeEnumRef_ = nullptr;
101 
SendablePhotoAccessHelper()102 SendablePhotoAccessHelper::SendablePhotoAccessHelper()
103     : env_(nullptr) {}
104 
105 SendablePhotoAccessHelper::~SendablePhotoAccessHelper() = default;
106 
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)107 void SendablePhotoAccessHelper::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
108 {
109     SendablePhotoAccessHelper *sendablePhotoAccessHelper = reinterpret_cast<SendablePhotoAccessHelper*>(nativeObject);
110     if (sendablePhotoAccessHelper != nullptr) {
111         delete sendablePhotoAccessHelper;
112         sendablePhotoAccessHelper = nullptr;
113     }
114 }
115 
Init(napi_env env,napi_value exports)116 napi_value SendablePhotoAccessHelper::Init(napi_env env, napi_value exports)
117 {
118     napi_value ctorObj;
119 
120     napi_property_descriptor props[] = {
121         DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
122         DECLARE_NAPI_FUNCTION("getBurstAssets", PhotoAccessGetBurstAssets),
123         DECLARE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
124         DECLARE_NAPI_FUNCTION("release", JSRelease),
125         DECLARE_NAPI_FUNCTION("getAlbums", PhotoAccessGetPhotoAlbums),
126         DECLARE_NAPI_FUNCTION("getHiddenAlbums", PahGetHiddenAlbums),
127         DECLARE_NAPI_FUNCTION("getSharedPhotoAssets", PhotoAccessGetSharedPhotoAssets),
128     };
129     napi_define_sendable_class(env, SENDABLE_PHOTOACCESSHELPER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
130                                MediaLibraryNapiConstructor, nullptr, sizeof(props) / sizeof(props[0]),
131                                props, nullptr, &ctorObj);
132     NAPI_CALL(env, napi_create_reference(env, ctorObj, NAPI_INIT_REF_COUNT, &photoAccessHelperConstructor_));
133     NAPI_CALL(env, napi_set_named_property(env, exports, SENDABLE_PHOTOACCESSHELPER_NAPI_CLASS_NAME.c_str(), ctorObj));
134 
135     const vector<napi_property_descriptor> staticProps = {
136         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
137         DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
138         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
139         DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
140         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
141         DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
142         DECLARE_NAPI_PROPERTY("MovingPhotoEffectMode", CreateMovingPhotoEffectModeEnum(env)),
143     };
144     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
145     return exports;
146 }
147 
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)148 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
149 {
150     isAsync = false;
151     size_t argc = ARGS_TWO;
152     napi_value argv[ARGS_TWO] = {0};
153     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
154     if (status != napi_ok) {
155         NAPI_ERR_LOG("Error while obtaining js environment information");
156         return status;
157     }
158 
159     if (argc == ARGS_ONE) {
160         return napi_ok;
161     } else if (argc == ARGS_TWO) {
162         napi_valuetype valueType = napi_undefined;
163         status = napi_typeof(env, argv[ARGS_ONE], &valueType);
164         if (status != napi_ok) {
165             NAPI_ERR_LOG("Error while obtaining js environment information");
166             return status;
167         }
168         if (valueType == napi_boolean) {
169             isAsync = true;
170         }
171         status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
172         return status;
173     } else {
174         NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
175         return napi_invalid_arg;
176     }
177 }
178 
179 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)180 napi_value SendablePhotoAccessHelper::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
181 {
182     napi_status status;
183     napi_value result = nullptr;
184     napi_value thisVar = nullptr;
185     MediaLibraryTracer tracer;
186 
187     tracer.Start("MediaLibraryNapiConstructor");
188 
189     NAPI_CALL(env, napi_get_undefined(env, &result));
190     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
191     if (status != napi_ok || thisVar == nullptr) {
192         NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
193         return result;
194     }
195 
196     unique_ptr<SendablePhotoAccessHelper> obj = make_unique<SendablePhotoAccessHelper>();
197     if (obj == nullptr) {
198         return result;
199     }
200     obj->env_ = env;
201 
202     bool isAsync = false;
203     NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
204     if (!isAsync) {
205         unique_lock<mutex> helperLock(sUserFileClientMutex_);
206         if (!UserFileClient::IsValid()) {
207             UserFileClient::Init(env, info);
208             if (!UserFileClient::IsValid()) {
209                 NAPI_ERR_LOG("UserFileClient creation failed");
210                 helperLock.unlock();
211                 return result;
212             }
213         }
214         helperLock.unlock();
215     }
216 
217     status = napi_wrap_sendable(env, thisVar, reinterpret_cast<void *>(obj.get()),
218         SendablePhotoAccessHelper::MediaLibraryNapiDestructor, nullptr);
219     if (status == napi_ok) {
220         obj.release();
221         return thisVar;
222     } else {
223         NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
224     }
225 
226     return result;
227 }
228 
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid)229 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid)
230 {
231     napi_value propertyNames;
232     uint32_t propertyLength;
233     napi_valuetype valueType = napi_undefined;
234     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
235     if (valueType != napi_object) {
236         return false;
237     }
238 
239     NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
240     NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
241     if (propertyLength == 0) {
242         return false;
243     }
244     if (checkIsValid && (!UserFileClient::IsValid())) {
245         NAPI_ERR_LOG("UserFileClient is not valid");
246         return false;
247     }
248     return true;
249 }
250 
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)251 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
252     bool isAsync = false)
253 {
254     constexpr size_t argContext = 1;
255     size_t argc = argContext;
256     napi_value argv[ARGS_TWO] = {0};
257 
258     napi_value thisVar = nullptr;
259     napi_value ctor = nullptr;
260     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
261     NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
262 
263     if (isAsync) {
264         argc = ARGS_TWO;
265         NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
266         argv[ARGS_ONE] = argv[argContext];
267     }
268 
269     napi_value result = nullptr;
270     NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
271     if (!CheckWhetherInitSuccess(env, result, !isAsync)) {
272         NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
273         NAPI_CALL(env, napi_get_undefined(env, &result));
274     }
275     return result;
276 }
277 
GetPhotoAccessHelper(napi_env env,napi_callback_info info)278 napi_value SendablePhotoAccessHelper::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
279 {
280     MediaLibraryTracer tracer;
281     tracer.Start("GetPhotoAccessHelper");
282     if (photoAccessHelperConstructor_ == nullptr) {
283         napi_value exports = nullptr;
284         napi_create_object(env, &exports);
285         SendablePhotoAccessHelper::Init(env, exports);
286     }
287 
288     return CreateNewInstance(env, info, photoAccessHelperConstructor_);
289 }
290 
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)291 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
292     const string &name, int32_t enumValue)
293 {
294     napi_value enumNapiValue;
295     napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
296     if (status == napi_ok) {
297         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
298     }
299     return status;
300 }
301 
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)302 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
303 {
304     napi_value result = nullptr;
305     NAPI_CALL(env, napi_create_object(env, &result));
306     for (size_t i = 0; i < properties.size(); i++) {
307         NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], i + offset));
308     }
309     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
310     return result;
311 }
312 
GetNapiFileResult(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)313 static void GetNapiFileResult(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
314     unique_ptr<SendableJSAsyncContextOutput> &jsContext)
315 {
316     // Create FetchResult object using the contents of resultSet
317     if (context->fetchFileResult == nullptr) {
318         NAPI_ERR_LOG("No fetch file result found!");
319         SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
320             "Failed to obtain Fetch File Result");
321         return;
322     }
323     napi_value fileResult = SendableFetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
324     if (fileResult == nullptr) {
325         SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
326             "Failed to create js object for Fetch File Result");
327     } else {
328         jsContext->data = fileResult;
329         jsContext->status = true;
330         napi_get_undefined(env, &jsContext->error);
331     }
332 }
333 
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)334 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
335 {
336     MediaLibraryTracer tracer;
337     tracer.Start("GetFileAssetsAsyncCallbackComplete");
338 
339     SendablePhotoAccessHelperAsyncContext *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
340     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
341 
342     unique_ptr<SendableJSAsyncContextOutput> jsContext = make_unique<SendableJSAsyncContextOutput>();
343     jsContext->status = false;
344     napi_get_undefined(env, &jsContext->data);
345 
346     if (context->error != ERR_DEFAULT) {
347         context->HandleError(env, jsContext->error);
348     } else {
349         GetNapiFileResult(env, context, jsContext);
350     }
351 
352     tracer.Finish();
353     if (context->work != nullptr) {
354         SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
355             context->work, *jsContext);
356     }
357     delete context;
358 }
359 
360 #ifdef MEDIALIBRARY_COMPATIBILITY
SetCompatAlbumName(AlbumAsset * albumData)361 static void SetCompatAlbumName(AlbumAsset *albumData)
362 {
363     string albumName;
364     switch (albumData->GetAlbumSubType()) {
365         case PhotoAlbumSubType::CAMERA:
366             albumName = CAMERA_ALBUM_NAME;
367             break;
368         case PhotoAlbumSubType::SCREENSHOT:
369             albumName = SCREEN_SHOT_ALBUM_NAME;
370             break;
371         default:
372             NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
373     }
374     albumData->SetAlbumName(albumName);
375 }
376 #else
SetAlbumCoverUri(SendablePhotoAccessHelperAsyncContext * context,unique_ptr<AlbumAsset> & album)377 static void SetAlbumCoverUri(SendablePhotoAccessHelperAsyncContext *context, unique_ptr<AlbumAsset> &album)
378 {
379     MediaLibraryTracer tracer;
380     tracer.Start("SetAlbumCoverUri");
381     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
382     DataShare::DataSharePredicates predicates;
383     predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
384     predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
385     predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
386     vector<string> columns;
387     string queryUri = MEDIALIBRARY_DATA_URI;
388     if (!context->networkId.empty()) {
389         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
390         NAPI_DEBUG_LOG("querycoverUri is = %{private}s", queryUri.c_str());
391     }
392     Uri uri(queryUri);
393     int errCode = 0;
394     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
395         uri, predicates, columns, errCode);
396     if (resultSet == nullptr) {
397         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
398         return;
399     }
400     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
401     fetchFileResult->SetNetworkId(context->networkId);
402     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
403     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
404     string coverUri = fileAsset->GetUri();
405     album->SetCoverUri(coverUri);
406     NAPI_DEBUG_LOG("coverUri is = %{private}s", album->GetCoverUri().c_str());
407 }
408 #endif
409 
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)410 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
411     const string &networkId)
412 {
413 #ifdef MEDIALIBRARY_COMPATIBILITY
414     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
415         TYPE_INT32)));
416     albumData->SetAlbumType(static_cast<PhotoAlbumType>(
417         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
418     albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
419         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
420     SetCompatAlbumName(albumData);
421 #else
422     // Get album id index and value
423     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
424         TYPE_INT32)));
425 
426     // Get album title index and value
427     albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
428         TYPE_STRING)));
429 #endif
430 
431     // Get album asset count index and value
432     albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
433     MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
434         MEDIA_API_VERSION_DEFAULT);
435     albumData->SetAlbumUri(fileUri.ToString());
436     // Get album relativePath index and value
437     albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
438         resultSet, TYPE_STRING)));
439     albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
440         resultSet, TYPE_INT64)));
441 }
442 
443 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)444 static void ReplaceAlbumName(const string &arg, string &argInstead)
445 {
446     if (arg == CAMERA_ALBUM_NAME) {
447         argInstead = to_string(PhotoAlbumSubType::CAMERA);
448     } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
449         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
450     } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
451         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
452     } else {
453         argInstead = arg;
454     }
455 }
456 
DoReplaceRelativePath(const string & arg,string & argInstead)457 static bool DoReplaceRelativePath(const string &arg, string &argInstead)
458 {
459     if (arg == CAMERA_PATH) {
460         argInstead = to_string(PhotoAlbumSubType::CAMERA);
461     } else if (arg == SCREEN_SHOT_PATH) {
462         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
463     } else if (arg == SCREEN_RECORD_PATH) {
464         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
465     } else if (arg.empty()) {
466         argInstead = arg;
467         return false;
468     } else {
469         argInstead = arg;
470     }
471     return true;
472 }
473 
ReplaceRelativePath(string & selection,size_t pos,const string & keyInstead,const string & arg,string & argInstead)474 static inline void ReplaceRelativePath(string &selection, size_t pos, const string &keyInstead, const string &arg,
475     string &argInstead)
476 {
477     bool shouldReplace = DoReplaceRelativePath(arg, argInstead);
478     if (shouldReplace) {
479         selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), keyInstead);
480     }
481 }
482 
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead,const int32_t mode)483 void SendablePhotoAccessHelper::ReplaceSelection(string &selection, vector<string> &selectionArgs,
484     const string &key, const string &keyInstead, const int32_t mode)
485 {
486     for (size_t pos = 0; pos != string::npos;) {
487         pos = selection.find(key, pos);
488         if (pos == string::npos) {
489             break;
490         }
491 
492         size_t argPos = selection.find('?', pos);
493         if (argPos == string::npos) {
494             break;
495         }
496         size_t argIndex = 0;
497         for (size_t i = 0; i < argPos; i++) {
498             if (selection[i] == '?') {
499                 argIndex++;
500             }
501         }
502         if (argIndex > selectionArgs.size() - 1) {
503             NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
504                 selection.c_str());
505             break;
506         }
507         const string &arg = selectionArgs[argIndex];
508         string argInstead = arg;
509         if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
510             if (mode == SendableReplaceSelectionMode::SENDABLE_ADD_DOCS_TO_RELATIVE_PATH) {
511                 argInstead = MediaFileUtils::AddDocsToRelativePath(arg);
512             } else {
513                 ReplaceRelativePath(selection, pos, keyInstead, arg, argInstead);
514             }
515         } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
516             ReplaceAlbumName(arg, argInstead);
517             selection.replace(pos, key.length(), keyInstead);
518         } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
519             selection.replace(pos, key.length(), keyInstead);
520         }
521         selectionArgs[argIndex] = argInstead;
522         argPos = selection.find('?', pos);
523         if (argPos == string::npos) {
524             break;
525         }
526         pos = argPos + 1;
527     }
528 }
529 #endif
530 
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],SendablePhotoAccessHelperAsyncContext & asyncContext)531 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
532                                    SendablePhotoAccessHelperAsyncContext &asyncContext)
533 {
534     const int32_t refCount = 1;
535     napi_value result = nullptr;
536     auto context = &asyncContext;
537     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
538     int32_t fileMediaType = 0;
539     size_t res = 0;
540     char relativePathBuffer[PATH_MAX];
541     char titleBuffer[PATH_MAX];
542     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
543 
544     for (size_t i = PARAM0; i < argc; i++) {
545         napi_valuetype valueType = napi_undefined;
546         napi_typeof(env, argv[i], &valueType);
547         if (i == PARAM0 && valueType == napi_number) {
548             napi_get_value_int32(env, argv[i], &fileMediaType);
549         } else if (i == PARAM1 && valueType == napi_string) {
550             napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
551             NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
552         } else if (i == PARAM2 && valueType == napi_string) {
553             napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
554             NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
555         } else if (i == PARAM3 && valueType == napi_function) {
556             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
557         } else {
558             NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
559             return result;
560     }
561     }
562 
563     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
564     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
565     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
566 
567     context->assetType = TYPE_DEFAULT;
568     if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
569         context->assetType = TYPE_PHOTO;
570     } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
571         context->assetType = TYPE_AUDIO;
572     }
573 
574     NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
575     // Return true napi_value if params are successfully obtained
576     napi_get_boolean(env, true, &result);
577     return result;
578 }
579 
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],SendablePhotoAccessHelperAsyncContext & asyncContext)580 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
581                                    SendablePhotoAccessHelperAsyncContext &asyncContext)
582 {
583     const int32_t refCount = 1;
584     napi_value result = nullptr;
585     auto context = &asyncContext;
586     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
587     size_t res = 0;
588     char buffer[PATH_MAX];
589 
590     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
591 
592     for (size_t i = PARAM0; i < argc; i++) {
593         napi_valuetype valueType = napi_undefined;
594         napi_typeof(env, argv[i], &valueType);
595 
596         if (i == PARAM0 && valueType == napi_string) {
597             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
598         } else if (i == PARAM1 && valueType == napi_function) {
599             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
600             break;
601         } else {
602             NAPI_ASSERT(env, false, "type mismatch");
603         }
604     }
605 
606     context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
607 
608     // Return true napi_value if params are successfully obtained
609     napi_get_boolean(env, true, &result);
610     return result;
611 }
612 
JSReleaseCompleteCallback(napi_env env,napi_status status,SendablePhotoAccessHelperAsyncContext * context)613 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
614                                       SendablePhotoAccessHelperAsyncContext *context)
615 {
616     MediaLibraryTracer tracer;
617     tracer.Start("JSReleaseCompleteCallback");
618 
619     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
620 
621     unique_ptr<SendableJSAsyncContextOutput> jsContext = make_unique<SendableJSAsyncContextOutput>();
622     jsContext->status = false;
623     if (context->objectInfo != nullptr) {
624         napi_create_int32(env, E_SUCCESS, &jsContext->data);
625         jsContext->status = true;
626         napi_get_undefined(env, &jsContext->error);
627     } else {
628         NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
629         SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
630             "UserFileClient is invalid");
631         napi_get_undefined(env, &jsContext->data);
632     }
633 
634     tracer.Finish();
635     if (context->work != nullptr) {
636         SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
637             context->work, *jsContext);
638     }
639 
640     delete context;
641 }
642 
JSRelease(napi_env env,napi_callback_info info)643 napi_value SendablePhotoAccessHelper::JSRelease(napi_env env, napi_callback_info info)
644 {
645     napi_status status;
646     napi_value result = nullptr;
647     size_t argc = ARGS_ONE;
648     napi_value argv[ARGS_ONE] = {0};
649     napi_value thisVar = nullptr;
650     napi_value resource = nullptr;
651     int32_t refCount = 1;
652 
653     MediaLibraryTracer tracer;
654     tracer.Start("JSRelease");
655 
656     GET_JS_ARGS(env, info, argc, argv, thisVar);
657     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
658     napi_get_undefined(env, &result);
659 
660     unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
661         make_unique<SendablePhotoAccessHelperAsyncContext>();
662     status = napi_unwrap_sendable(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
663     NAPI_ASSERT(env, status == napi_ok && asyncContext->objectInfo != nullptr, "Failed to get object info");
664 
665     if (argc == PARAM1) {
666         napi_valuetype valueType = napi_undefined;
667         napi_typeof(env, argv[PARAM0], &valueType);
668         if (valueType == napi_function) {
669             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
670         }
671     }
672     CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
673 
674     NAPI_CALL(env, napi_remove_wrap_sendable(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
675     NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
676     NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRelease", asyncContext);
677 
678     status = napi_create_async_work(
679         env, nullptr, resource, [](napi_env env, void *data) {},
680         reinterpret_cast<CompleteCallback>(JSReleaseCompleteCallback),
681         static_cast<void *>(asyncContext.get()), &asyncContext->work);
682     if (status != napi_ok) {
683         napi_get_undefined(env, &result);
684     } else {
685         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
686         asyncContext.release();
687     }
688 
689     return result;
690 }
691 
AddDefaultPhotoAlbumColumns(napi_env env,vector<string> & fetchColumn)692 static napi_value AddDefaultPhotoAlbumColumns(napi_env env, vector<string> &fetchColumn)
693 {
694     auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
695     for (const auto &column : fetchColumn) {
696         if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
697             validFetchColumns.insert(column);
698         } else if (column.compare(MEDIA_DATA_DB_URI) == 0) {
699             // uri is default property of album
700             continue;
701         } else {
702             NAPI_ERR_LOG("unknown columns:%{public}s", column.c_str());
703             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
704             return nullptr;
705         }
706     }
707     fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
708 
709     napi_value result = nullptr;
710     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
711     return result;
712 }
713 
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],SendablePhotoAccessHelperAsyncContext & asyncContext)714 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
715                                         SendablePhotoAccessHelperAsyncContext &asyncContext)
716 {
717     const int32_t refCount = 1;
718     napi_value result = nullptr;
719     auto context = &asyncContext;
720     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
721     size_t res = 0;
722     char buffer[PATH_MAX];
723     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
724     for (size_t i = 0; i < argc; i++) {
725         napi_valuetype valueType = napi_undefined;
726         napi_typeof(env, argv[i], &valueType);
727         if (i == 0 && valueType == napi_number) {
728             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
729         } else if (i == PARAM1 && valueType == napi_string) {
730             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
731         } else if (i == PARAM2 && valueType == napi_function) {
732             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
733             break;
734         } else {
735             NAPI_ASSERT(env, false, "type mismatch");
736         }
737     }
738     if (context->parentSmartAlbumId < 0) {
739         NAPI_ASSERT(env, false, "type mismatch");
740     }
741     string smartName = string(buffer);
742     if (smartName.empty()) {
743         NAPI_ASSERT(env, false, "type mismatch");
744     }
745     context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
746     napi_get_boolean(env, true, &result);
747     return result;
748 }
749 
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,bool needExtraOption=false)750 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
751     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context, bool needExtraOption = false)
752 {
753     constexpr size_t minArgs = ARGS_ONE;
754     constexpr size_t maxArgs = ARGS_TWO;
755     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
756         JS_ERR_PARAMETER_INVALID);
757 
758     /* Parse the first argument */
759     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
760         JS_INNER_FAIL);
761     auto &predicates = context->predicates;
762     switch (context->assetType) {
763         case TYPE_AUDIO: {
764             CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
765                 AudioColumn::IsAudioColumn, TYPE_AUDIO));
766             break;
767         }
768         case TYPE_PHOTO: {
769             if (needExtraOption) {
770                 bool isAddDefaultColumn =
771                     std::find(context->fetchColumn.begin(), context->fetchColumn.end(), MEDIA_DATA_DB_URI) !=
772                         context->fetchColumn.end();
773                 if (isAddDefaultColumn) {
774                     CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
775                         PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
776                 } else {
777                     std::set<std::string> fetchColumns;
778                     CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddAssetColumns(env, context->fetchColumn,
779                         PhotoColumn::IsPhotoColumn, fetchColumns));
780                 }
781             } else {
782                 CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
783                     PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
784             }
785             break;
786         }
787         default: {
788             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
789             return nullptr;
790         }
791     }
792     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
793     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
794     if (context->assetType == TYPE_PHOTO) {
795         predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
796         predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
797         predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
798             to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
799     }
800 
801     napi_value result = nullptr;
802     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
803     return result;
804 }
805 
PhotoAccessGetAssetsExecute(napi_env env,void * data)806 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
807 {
808     MediaLibraryTracer tracer;
809     tracer.Start("PhotoAccessGetAssetsExecute");
810 
811     auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
812     string queryUri;
813     switch (context->assetType) {
814         case TYPE_PHOTO: {
815             if (context->uri == URI_ALL_DUPLICATE_ASSETS) {
816                 queryUri = PAH_ALL_DUPLICATE_ASSETS;
817             } else if (context->uri == URI_CAN_DEL_DUPLICATE_ASSETS) {
818                 queryUri = PAH_CAN_DEL_DUPLICATE_ASSETS;
819             } else {
820                 queryUri = PAH_QUERY_PHOTO;
821             }
822             SendableMediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
823             break;
824         }
825         default: {
826             context->SaveError(-EINVAL);
827             return;
828         }
829     }
830 
831     Uri uri(queryUri);
832     int errCode = 0;
833     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
834         context->predicates, context->fetchColumn, errCode);
835     if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
836         Uri queryWithUri(context->uri);
837         resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
838     }
839     if (resultSet == nullptr) {
840         context->SaveError(errCode);
841         return;
842     }
843     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
844     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
845 }
846 
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)847 napi_value SendablePhotoAccessHelper::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
848 {
849     unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
850         make_unique<SendablePhotoAccessHelperAsyncContext>();
851     asyncContext->assetType = TYPE_PHOTO;
852     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
853 
854     return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
855         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
856 }
857 
GetPhotoAlbumQueryResult(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)858 static void GetPhotoAlbumQueryResult(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
859     unique_ptr<SendableJSAsyncContextOutput> &jsContext)
860 {
861     napi_value fileResult = SendableFetchFileResultNapi::CreateFetchFileResult(env,
862         move(context->fetchPhotoAlbumResult));
863     if (fileResult == nullptr) {
864         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
865         SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
866             "Failed to create js object for Fetch Album Result");
867         return;
868     }
869     jsContext->data = fileResult;
870     jsContext->status = true;
871     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
872 }
873 
JSGetPhotoAlbumsExecute(napi_env env,void * data)874 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
875 {
876     MediaLibraryTracer tracer;
877     tracer.Start("JSGetPhotoAlbumsExecute");
878 
879     auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
880     string queryUri;
881     if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
882         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
883             UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
884     } else if (context->isAnalysisAlbum) {
885         queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
886             PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
887     } else {
888         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
889             UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
890     }
891     Uri uri(queryUri);
892     int errCode = 0;
893     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
894     if (resultSet == nullptr) {
895         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
896         if (errCode == E_PERMISSION_DENIED) {
897             if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
898                 context->error = OHOS_PERMISSION_DENIED_CODE;
899             } else {
900                 context->SaveError(E_HAS_DB_ERROR);
901             }
902         } else {
903             context->SaveError(E_HAS_DB_ERROR);
904         }
905         return;
906     }
907 
908     context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
909     context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
910     context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
911     context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
912         PhotoAlbumSubType::GEOGRAPHY_LOCATION);
913 }
914 
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)915 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
916 {
917     MediaLibraryTracer tracer;
918     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
919 
920     auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
921     unique_ptr<SendableJSAsyncContextOutput> jsContext = make_unique<SendableJSAsyncContextOutput>();
922     jsContext->status = false;
923     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
924     if (context->error != ERR_DEFAULT  || context->fetchPhotoAlbumResult == nullptr) {
925         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
926         context->HandleError(env, jsContext->error);
927     } else {
928         GetPhotoAlbumQueryResult(env, context, jsContext);
929     }
930 
931     tracer.Finish();
932     if (context->work != nullptr) {
933         SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
934             context->work, *jsContext);
935     }
936     delete context;
937 }
938 
CreateMediaTypeUserFileEnum(napi_env env)939 napi_value SendablePhotoAccessHelper::CreateMediaTypeUserFileEnum(napi_env env)
940 {
941     const int32_t startIdx = 1;
942     return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
943 }
944 
CreateAlbumTypeEnum(napi_env env)945 napi_value SendablePhotoAccessHelper::CreateAlbumTypeEnum(napi_env env)
946 {
947     napi_value result = nullptr;
948     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
949 
950     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
951     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
952     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SMART", PhotoAlbumType::SMART), JS_INNER_FAIL);
953     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE", PhotoAlbumType::SOURCE), JS_INNER_FAIL);
954 
955     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
956     return result;
957 }
958 
CreateAlbumSubTypeEnum(napi_env env)959 napi_value SendablePhotoAccessHelper::CreateAlbumSubTypeEnum(napi_env env)
960 {
961     napi_value result = nullptr;
962     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
963 
964     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
965         JS_INNER_FAIL);
966     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE_GENERIC", PhotoAlbumSubType::SOURCE_GENERIC),
967         JS_INNER_FAIL);
968     for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
969         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
970             PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
971     }
972     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "CLASSIFY", PhotoAlbumSubType::CLASSIFY),
973         JS_INNER_FAIL);
974     for (size_t i = 0; i < analysisAlbumSubType.size(); i++) {
975         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, analysisAlbumSubType[i],
976             PhotoAlbumSubType::GEOGRAPHY_LOCATION + i), JS_INNER_FAIL);
977     }
978     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
979 
980     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
981     return result;
982 }
983 
CreateMovingPhotoEffectModeEnum(napi_env env)984 napi_value SendablePhotoAccessHelper::CreateMovingPhotoEffectModeEnum(napi_env env)
985 {
986     return CreateNumberEnumProperty(env, movingPhotoEffectModeEnum, sMovingPhotoEffectModeEnumRef_);
987 }
988 
GetAlbumFetchOption(napi_env env,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,bool hasCallback)989 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<SendablePhotoAccessHelperAsyncContext> &context,
990     bool hasCallback)
991 {
992     if (context->argc < (ARGS_ONE + hasCallback)) {
993         NAPI_ERR_LOG("No arguments to parse");
994         return nullptr;
995     }
996 
997     // The index of fetchOption should always be the last arg besides callback
998     napi_value fetchOption = context->argv[context->argc - 1 - hasCallback];
999     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT,
1000         context), JS_INNER_FAIL);
1001     if (!context->uri.empty()) {
1002         if (context->uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != std::string::npos) {
1003             context->isAnalysisAlbum = 1; // 1:is an analysis album
1004         }
1005     }
1006     napi_value result = nullptr;
1007     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1008     return result;
1009 }
1010 
ParseLocationAlbumTypes(unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,const int32_t albumSubType)1011 static bool ParseLocationAlbumTypes(unique_ptr<SendablePhotoAccessHelperAsyncContext> &context,
1012     const int32_t albumSubType)
1013 {
1014     if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
1015         context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
1016         context->fetchColumn.insert(context->fetchColumn.end(),
1017             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
1018             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
1019         SendableMediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
1020         return false;
1021     } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
1022         context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
1023         context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
1024         string onClause = PhotoAlbumColumns::ALBUM_NAME  + " = " + CITY_ID;
1025         context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
1026         context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
1027     }
1028     return true;
1029 }
1030 
ParseAlbumTypes(napi_env env,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1031 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1032 {
1033     if (context->argc < ARGS_TWO) {
1034         NAPI_ERR_LOG("No arguments to parse");
1035         return nullptr;
1036     }
1037 
1038     /* Parse the first argument to photo album type */
1039     int32_t albumType;
1040     CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
1041     if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
1042         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
1043         return nullptr;
1044     }
1045     context->isAnalysisAlbum = (albumType == PhotoAlbumType::SMART) ? 1 : 0;
1046 
1047     /* Parse the second argument to photo album subType */
1048     int32_t albumSubType;
1049     CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
1050     if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
1051         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
1052         return nullptr;
1053     }
1054 
1055     if (!ParseLocationAlbumTypes(context, albumSubType)) {
1056         napi_value result = nullptr;
1057         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1058         return result;
1059     }
1060 
1061     context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
1062     if (albumSubType != ANY) {
1063         context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
1064     }
1065     if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
1066         context->predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
1067     }
1068     if (albumSubType == PhotoAlbumSubType::HIGHLIGHT || albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
1069         context->isHighlightAlbum = albumSubType;
1070         vector<string> onClause = {
1071             ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
1072             HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
1073         };
1074         context->predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
1075         context->predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
1076     }
1077 
1078     napi_value result = nullptr;
1079     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1080     return result;
1081 }
1082 
RestrictAlbumSubtypeOptions(unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1083 static void RestrictAlbumSubtypeOptions(unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1084 {
1085     if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
1086         context->predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
1087             to_string(PhotoAlbumSubType::USER_GENERIC),
1088             to_string(PhotoAlbumSubType::FAVORITE),
1089             to_string(PhotoAlbumSubType::VIDEO),
1090             to_string(PhotoAlbumSubType::IMAGE),
1091         }));
1092     } else {
1093         context->predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
1094     }
1095 }
1096 
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1097 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
1098     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1099 {
1100     constexpr size_t minArgs = ARGS_ZERO;
1101     constexpr size_t maxArgs = ARGS_FOUR;
1102     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1103         JS_ERR_PARAMETER_INVALID);
1104 
1105     bool hasCallback = false;
1106     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
1107         JS_ERR_PARAMETER_INVALID);
1108     if (context->argc == ARGS_THREE) {
1109         napi_valuetype valueType = napi_undefined;
1110         if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
1111             (valueType == napi_undefined || valueType == napi_null)) {
1112             context->argc -= 1;
1113         }
1114     }
1115     switch (context->argc - hasCallback) {
1116         case ARGS_ZERO:
1117             break;
1118         case ARGS_ONE:
1119             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
1120             break;
1121         case ARGS_TWO:
1122             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
1123             break;
1124         case ARGS_THREE:
1125             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
1126             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
1127             break;
1128         default:
1129             return nullptr;
1130     }
1131     RestrictAlbumSubtypeOptions(context);
1132     if (context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
1133         context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
1134         CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
1135         if (!context->isAnalysisAlbum) {
1136             context->fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
1137             context->fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
1138         }
1139         if (context->isHighlightAlbum) {
1140             context->fetchColumn.erase(std::remove(context->fetchColumn.begin(), context->fetchColumn.end(),
1141                 PhotoAlbumColumns::ALBUM_ID), context->fetchColumn.end());
1142             context->fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
1143             PhotoAlbumColumns::ALBUM_ID);
1144         }
1145     }
1146     napi_value result = nullptr;
1147     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1148     return result;
1149 }
1150 
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)1151 napi_value SendablePhotoAccessHelper::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
1152 {
1153     unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1154         make_unique<SendablePhotoAccessHelperAsyncContext>();
1155     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1156     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
1157 
1158     return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums",
1159         JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
1160 }
1161 
CreatePositionTypeEnum(napi_env env)1162 napi_value SendablePhotoAccessHelper::CreatePositionTypeEnum(napi_env env)
1163 {
1164     const int32_t startIdx = 1;
1165     return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
1166 }
1167 
CreatePhotoSubTypeEnum(napi_env env)1168 napi_value SendablePhotoAccessHelper::CreatePhotoSubTypeEnum(napi_env env)
1169 {
1170     return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
1171 }
1172 
ParseHiddenPhotosDisplayMode(napi_env env,const unique_ptr<SendablePhotoAccessHelperAsyncContext> & context,const int32_t fetchMode)1173 napi_value ParseHiddenPhotosDisplayMode(napi_env env,
1174     const unique_ptr<SendablePhotoAccessHelperAsyncContext> &context, const int32_t fetchMode)
1175 {
1176     switch (fetchMode) {
1177         case ASSETS_MODE:
1178             context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::HIDDEN);
1179             break;
1180         case ALBUMS_MODE:
1181             context->predicates.EqualTo(PhotoAlbumColumns::CONTAINS_HIDDEN, to_string(1));
1182             break;
1183         default:
1184             NapiError::ThrowError(
1185                 env, OHOS_INVALID_PARAM_CODE, "Invalid fetch mode: " + to_string(fetchMode));
1186             return nullptr;
1187     }
1188     napi_value result = nullptr;
1189     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1190     return result;
1191 }
1192 
ParseArgsGetHiddenAlbums(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1193 napi_value ParseArgsGetHiddenAlbums(napi_env env, napi_callback_info info,
1194     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1195 {
1196     if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
1197         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1198         return nullptr;
1199     }
1200     napi_value result = nullptr;
1201     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1202     constexpr size_t minArgs = ARGS_ONE;
1203     constexpr size_t maxArgs = ARGS_THREE;
1204     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1205         OHOS_INVALID_PARAM_CODE);
1206     bool hasCallback = false;
1207     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
1208         OHOS_INVALID_PARAM_CODE);
1209     if (context->argc == ARGS_THREE) {
1210         napi_valuetype valueType = napi_undefined;
1211         if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
1212             (valueType == napi_undefined || valueType == napi_null)) {
1213             context->argc -= 1;
1214         }
1215     }
1216     int32_t fetchMode = 0;
1217     switch (context->argc - hasCallback) {
1218         case ARGS_ONE:
1219             CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode),
1220                 OHOS_INVALID_PARAM_CODE);
1221             break;
1222         case ARGS_TWO:
1223             CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode),
1224                 OHOS_INVALID_PARAM_CODE);
1225             CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(
1226                 env, context->argv[PARAM1], ALBUM_FETCH_OPT, context), OHOS_INVALID_PARAM_CODE);
1227             break;
1228         default:
1229             NapiError::ThrowError(
1230                 env, OHOS_INVALID_PARAM_CODE, "Invalid parameter count: " + to_string(context->argc));
1231             return nullptr;
1232     }
1233     CHECK_NULLPTR_RET(ParseHiddenPhotosDisplayMode(env, context, fetchMode));
1234     CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
1235     context->hiddenAlbumFetchMode = fetchMode;
1236     if (fetchMode == HiddenPhotosDisplayMode::ASSETS_MODE) {
1237         return result;
1238     }
1239     context->hiddenOnly = true;
1240     context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COUNT);
1241     context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COVER);
1242     return result;
1243 }
1244 
PahGetHiddenAlbums(napi_env env,napi_callback_info info)1245 napi_value SendablePhotoAccessHelper::PahGetHiddenAlbums(napi_env env, napi_callback_info info)
1246 {
1247     auto asyncContext = make_unique<SendablePhotoAccessHelperAsyncContext>();
1248     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1249     CHECK_NULLPTR_RET(ParseArgsGetHiddenAlbums(env, info, asyncContext));
1250     return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetHiddenAlbums",
1251         JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
1252 }
1253 
1254 template <class AsyncContext>
AsyncContextSetStaticObjectInfo(napi_env env,napi_callback_info info,AsyncContext & asyncContext,const size_t minArgs,const size_t maxArgs)1255 static napi_status AsyncContextSetStaticObjectInfo(napi_env env, napi_callback_info info,
1256     AsyncContext &asyncContext, const size_t minArgs, const size_t maxArgs)
1257 {
1258     NAPI_INFO_LOG("AsyncContextSetStaticObjectInfo start");
1259     napi_value thisVar = nullptr;
1260     asyncContext->argc = maxArgs;
1261     CHECK_STATUS_RET(napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]), &thisVar,
1262         nullptr), "Failed to get cb info");
1263     CHECK_COND_RET(((asyncContext->argc >= minArgs) && (asyncContext->argc <= maxArgs)), napi_invalid_arg,
1264         "Number of args is invalid");
1265     if (minArgs > 0) {
1266         CHECK_COND_RET(asyncContext->argv[ARGS_ZERO] != nullptr, napi_invalid_arg, "Argument list is empty");
1267     }
1268     CHECK_STATUS_RET(SendableMediaLibraryNapiUtils::GetParamCallback(env, asyncContext),
1269         "Failed to get callback param!");
1270     return napi_ok;
1271 }
1272 
CheckDisplayNameParams(SendablePhotoAccessHelperAsyncContext * context)1273 static bool CheckDisplayNameParams(SendablePhotoAccessHelperAsyncContext *context)
1274 {
1275     if (context == nullptr) {
1276         NAPI_ERR_LOG("Async context is null");
1277         return false;
1278     }
1279     if (!context->isCreateByComponent) {
1280         bool isValid = false;
1281         string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1282         if (!isValid) {
1283             NAPI_ERR_LOG("getting displayName is invalid");
1284             return false;
1285         }
1286         if (displayName.empty()) {
1287             return false;
1288         }
1289     }
1290 
1291     return true;
1292 }
1293 
CheckCreateOption(SendablePhotoAccessHelperAsyncContext & context)1294 static napi_status CheckCreateOption(SendablePhotoAccessHelperAsyncContext &context)
1295 {
1296     bool isValid = false;
1297     int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
1298     string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
1299     if (isValid) {
1300         if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
1301             NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
1302             return napi_invalid_arg;
1303         }
1304         if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
1305             NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
1306             return napi_invalid_arg;
1307         } else {
1308             context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
1309         }
1310     }
1311 
1312     return napi_ok;
1313 }
1314 
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,SendablePhotoAccessHelperAsyncContext & context)1315 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg,
1316     SendablePhotoAccessHelperAsyncContext &context)
1317 {
1318     for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
1319         string param = iter.first;
1320         bool present = false;
1321         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
1322         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
1323         if (!present) {
1324             continue;
1325         }
1326         napi_value value;
1327         result = napi_get_named_property(env, arg, param.c_str(), &value);
1328         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
1329         napi_valuetype valueType = napi_undefined;
1330         result = napi_typeof(env, value, &valueType);
1331         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
1332         if (valueType == napi_number) {
1333             int32_t number = 0;
1334             result = napi_get_value_int32(env, value, &number);
1335             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
1336             context.valuesBucket.Put(iter.second, number);
1337         } else if (valueType == napi_boolean) {
1338             bool isTrue = false;
1339             result = napi_get_value_bool(env, value, &isTrue);
1340             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
1341             context.valuesBucket.Put(iter.second, isTrue);
1342         } else if (valueType == napi_string) {
1343             char buffer[ARG_BUF_SIZE];
1344             size_t res = 0;
1345             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
1346             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
1347             context.valuesBucket.Put(iter.second, string(buffer));
1348         } else if (valueType == napi_undefined || valueType == napi_null) {
1349             continue;
1350         } else {
1351             NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
1352             return napi_invalid_arg;
1353         }
1354     }
1355 
1356     return CheckCreateOption(context);
1357 }
1358 
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1359 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
1360     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1361 {
1362     /* Parse the first argument into displayName */
1363     napi_valuetype valueType;
1364     MediaType mediaType;
1365     string displayName;
1366     NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
1367         napi_ok, "Failed to get displayName");
1368     mediaType = MediaFileUtils::GetMediaType(displayName);
1369     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
1370     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
1371 
1372     /* Parse the second argument into albumUri if exists */
1373     string albumUri;
1374     if ((context->argc >= ARGS_TWO)) {
1375         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
1376         if (valueType == napi_string) {
1377             if (SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
1378                 albumUri) == napi_ok) {
1379                 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
1380             }
1381         } else if (valueType == napi_object) {
1382             NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
1383                 "Parse asset create option failed");
1384         }
1385     }
1386 
1387     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
1388     NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok,
1389         "Failed to get callback");
1390 
1391     napi_value result = nullptr;
1392     NAPI_CALL(env, napi_get_boolean(env, true, &result));
1393     return result;
1394 }
1395 
ParseCreateOptions(napi_env env,napi_value arg,SendablePhotoAccessHelperAsyncContext & context)1396 static napi_status ParseCreateOptions(napi_env env, napi_value arg, SendablePhotoAccessHelperAsyncContext &context)
1397 {
1398     for (const auto &iter : CREATE_OPTIONS_PARAM) {
1399         string param = iter.first;
1400         bool present = false;
1401         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
1402         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
1403         if (!present) {
1404             continue;
1405         }
1406         napi_value value;
1407         result = napi_get_named_property(env, arg, param.c_str(), &value);
1408         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
1409         napi_valuetype valueType = napi_undefined;
1410         result = napi_typeof(env, value, &valueType);
1411         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
1412         if (valueType == napi_number) {
1413             int32_t number = 0;
1414             result = napi_get_value_int32(env, value, &number);
1415             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
1416             context.valuesBucket.Put(iter.second, number);
1417         } else if (valueType == napi_boolean) {
1418             bool isTrue = false;
1419             result = napi_get_value_bool(env, value, &isTrue);
1420             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
1421             context.valuesBucket.Put(iter.second, isTrue);
1422         } else if (valueType == napi_string) {
1423             char buffer[ARG_BUF_SIZE];
1424             size_t res = 0;
1425             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
1426             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
1427             context.valuesBucket.Put(iter.second, string(buffer));
1428         } else if (valueType == napi_undefined || valueType == napi_null) {
1429             continue;
1430         } else {
1431             NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
1432                 static_cast<int>(valueType));
1433             return napi_invalid_arg;
1434         }
1435     }
1436 
1437     return napi_ok;
1438 }
1439 
1440 
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1441 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
1442     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1443 {
1444     /* Parse the first argument into displayName */
1445     napi_valuetype valueType;
1446     MediaType mediaType;
1447     int32_t type = 0;
1448     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
1449         "Failed to get type value");
1450     mediaType = static_cast<MediaType>(type);
1451     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
1452 
1453     /* Parse the second argument into albumUri if exists */
1454     string extention;
1455     NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
1456         napi_ok, "Failed to get extention");
1457     context->valuesBucket.Put(ASSET_EXTENTION, extention);
1458 
1459     /* Parse the third argument into albumUri if exists */
1460     if (context->argc >= ARGS_THREE) {
1461         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
1462         if (valueType == napi_object) {
1463             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
1464                 "Parse asset create option failed");
1465         } else if (valueType != napi_function) {
1466             NAPI_ERR_LOG("Napi type is wrong in create options");
1467             return nullptr;
1468         }
1469     }
1470 
1471     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
1472 
1473     napi_value result = nullptr;
1474     NAPI_CALL(env, napi_get_boolean(env, true, &result));
1475     return result;
1476 }
1477 
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,SendablePhotoAccessHelperAsyncContext * context)1478 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1479                                            SendablePhotoAccessHelperAsyncContext *context)
1480 {
1481     bool isValid = false;
1482     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1483     if (!isValid) {
1484         NAPI_ERR_LOG("getting title is invalid");
1485         return;
1486     }
1487     auto fileAsset = make_unique<FileAsset>();
1488     fileAsset->SetId(id);
1489     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1490     fileAsset->SetUri(uri);
1491     fileAsset->SetMediaType(mediaType);
1492     fileAsset->SetDisplayName(displayName);
1493     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1494     fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1495     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1496     context->fileAsset = move(fileAsset);
1497 }
1498 
GetCreateUri(SendablePhotoAccessHelperAsyncContext * context,string & uri)1499 static void GetCreateUri(SendablePhotoAccessHelperAsyncContext *context, string &uri)
1500 {
1501     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1502         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1503         switch (context->assetType) {
1504             case TYPE_PHOTO:
1505                 uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1506                     ((context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO) :
1507                     ((context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT : PAH_CREATE_PHOTO);
1508                 break;
1509             case TYPE_AUDIO:
1510                 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
1511                 break;
1512             default:
1513                 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
1514                 return;
1515         }
1516         SendableMediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1517     } else {
1518 #ifdef MEDIALIBRARY_COMPATIBILITY
1519         bool isValid = false;
1520         string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1521         if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
1522             MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1523             uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1524             SendableMediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1525             return;
1526         }
1527         switch (context->assetType) {
1528             case TYPE_PHOTO:
1529                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1530                 break;
1531             case TYPE_AUDIO:
1532                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1533                 break;
1534             case TYPE_DEFAULT:
1535                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1536                 break;
1537             default:
1538                 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
1539                 return;
1540         }
1541         SendableMediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
1542 #else
1543         uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
1544 #endif
1545     }
1546 }
1547 
PhotoAccessCreateAssetExecute(napi_env env,void * data)1548 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
1549 {
1550     MediaLibraryTracer tracer;
1551     tracer.Start("JSCreateAssetExecute");
1552 
1553     auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
1554     if (!CheckDisplayNameParams(context)) {
1555         context->error = JS_E_DISPLAYNAME;
1556         return;
1557     }
1558 
1559     string uri;
1560     GetCreateUri(context, uri);
1561     Uri createFileUri(uri);
1562     string outUri;
1563     int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
1564     if (index < 0) {
1565         context->SaveError(index);
1566         NAPI_ERR_LOG("InsertExt fail, index: %{public}d.", index);
1567     } else {
1568         if (context->isCreateByComponent) {
1569             context->uri = outUri;
1570         } else {
1571             PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
1572         }
1573     }
1574 }
1575 
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1576 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
1577     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1578 {
1579     constexpr size_t minArgs = ARGS_ONE;
1580     constexpr size_t maxArgs = ARGS_FOUR;
1581     NAPI_ASSERT(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
1582         napi_ok, "Failed to get object info");
1583 
1584     napi_valuetype valueType;
1585     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
1586     if (valueType == napi_string) {
1587         context->isCreateByComponent = false;
1588         if (!SendableMediaLibraryNapiUtils::IsSystemApp()) {
1589             NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1590             return nullptr;
1591         }
1592         return ParseArgsCreatePhotoAssetSystem(env, info, context);
1593     } else if (valueType == napi_number) {
1594         context->isCreateByComponent = true;
1595         return ParseArgsCreatePhotoAssetComponent(env, info, context);
1596     } else {
1597         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
1598         return nullptr;
1599     }
1600 }
1601 
JSCreateUriInCallback(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)1602 static void JSCreateUriInCallback(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
1603     unique_ptr<SendableJSAsyncContextOutput> &jsContext)
1604 {
1605     napi_value jsObject = nullptr;
1606     if (context->uri.empty()) {
1607         SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1608             "Obtain file asset uri failed");
1609         napi_get_undefined(env, &jsContext->data);
1610     } else {
1611         napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1612         if (status != napi_ok || jsObject == nullptr) {
1613             NAPI_ERR_LOG("Failed to get file asset uri napi object");
1614             napi_get_undefined(env, &jsContext->data);
1615             SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1616                 "System inner fail");
1617         } else {
1618             jsContext->data = jsObject;
1619             napi_get_undefined(env, &jsContext->error);
1620             jsContext->status = true;
1621         }
1622     }
1623 }
1624 
JSCreateAssetInCallback(napi_env env,SendablePhotoAccessHelperAsyncContext * context,unique_ptr<SendableJSAsyncContextOutput> & jsContext)1625 static void JSCreateAssetInCallback(napi_env env, SendablePhotoAccessHelperAsyncContext *context,
1626     unique_ptr<SendableJSAsyncContextOutput> &jsContext)
1627 {
1628     napi_value jsFileAsset = nullptr;
1629     if (context->fileAsset == nullptr) {
1630         SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1631             "Obtain file asset failed");
1632         napi_get_undefined(env, &jsContext->data);
1633     } else {
1634         jsFileAsset = SendableFileAssetNapi::CreateFileAsset(env, context->fileAsset);
1635         if (jsFileAsset == nullptr) {
1636             NAPI_ERR_LOG("Failed to get file asset napi object");
1637             napi_get_undefined(env, &jsContext->data);
1638             SendableMediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1639                 "System inner fail");
1640         } else {
1641             NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1642             jsContext->data = jsFileAsset;
1643             napi_get_undefined(env, &jsContext->error);
1644             jsContext->status = true;
1645         }
1646     }
1647 }
1648 
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1649 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1650 {
1651     MediaLibraryTracer tracer;
1652     tracer.Start("JSCreateAssetCompleteCallback");
1653 
1654     auto *context = static_cast<SendablePhotoAccessHelperAsyncContext*>(data);
1655     auto jsContext = make_unique<SendableJSAsyncContextOutput>();
1656     jsContext->status = false;
1657 
1658     if (context->error == ERR_DEFAULT) {
1659         if (context->isCreateByComponent) {
1660             JSCreateUriInCallback(env, context, jsContext);
1661         } else {
1662             JSCreateAssetInCallback(env, context, jsContext);
1663         }
1664     } else {
1665         context->HandleError(env, jsContext->error);
1666         napi_get_undefined(env, &jsContext->data);
1667     }
1668 
1669     tracer.Finish();
1670     if (context->work != nullptr) {
1671         SendableMediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1672             context->work, *jsContext);
1673     }
1674     delete context;
1675 }
1676 
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)1677 napi_value SendablePhotoAccessHelper::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
1678 {
1679     MediaLibraryTracer tracer;
1680     tracer.Start("PhotoAccessHelperCreatePhotoAsset");
1681 
1682     NAPI_INFO_LOG("enter");
1683 
1684     unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1685         make_unique<SendablePhotoAccessHelperAsyncContext>();
1686     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1687     asyncContext->assetType = TYPE_PHOTO;
1688     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
1689 
1690     return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
1691         PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
1692 }
1693 
ParseArgsGetBurstAssets(napi_env env,napi_callback_info info,unique_ptr<SendablePhotoAccessHelperAsyncContext> & context)1694 static napi_value ParseArgsGetBurstAssets(napi_env env, napi_callback_info info,
1695     unique_ptr<SendablePhotoAccessHelperAsyncContext> &context)
1696 {
1697     constexpr size_t minArgs = ARGS_ONE;
1698     constexpr size_t maxArgs = ARGS_TWO;
1699     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1700         OHOS_INVALID_PARAM_CODE);
1701 
1702     /* Parse the first argument */
1703     std::string burstKey;
1704     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], burstKey),
1705         OHOS_INVALID_PARAM_CODE);
1706     if (burstKey.empty()) {
1707         NAPI_ERR_LOG("The input burstkey cannot be empty");
1708         return nullptr;
1709     }
1710     /* Parse the second argument */
1711     CHECK_ARGS(env, SendableMediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ASSET_FETCH_OPT,
1712         context), JS_INNER_FAIL);
1713 
1714     auto &predicates = context->predicates;
1715     if (context->assetType != TYPE_PHOTO) {
1716         return nullptr;
1717     }
1718     CHECK_NULLPTR_RET(SendableMediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
1719         PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
1720     predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_KEY, burstKey);
1721     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
1722     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
1723     predicates.OrderByAsc(MediaColumn::MEDIA_NAME);
1724 
1725     napi_value result = nullptr;
1726     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1727     return result;
1728 }
1729 
PhotoAccessGetBurstAssets(napi_env env,napi_callback_info info)1730 napi_value SendablePhotoAccessHelper::PhotoAccessGetBurstAssets(napi_env env, napi_callback_info info)
1731 {
1732     NAPI_INFO_LOG("PhotoAccessHelper::PhotoAccessGetBurstAssets start");
1733     unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1734         make_unique<SendablePhotoAccessHelperAsyncContext>();
1735     asyncContext->assetType = TYPE_PHOTO;
1736     CHECK_NULLPTR_RET(ParseArgsGetBurstAssets(env, info, asyncContext));
1737 
1738     return SendableMediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
1739         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
1740 }
1741 
PhotoAccessGetSharedPhotoAssets(napi_env env,napi_callback_info info)1742 napi_value SendablePhotoAccessHelper::PhotoAccessGetSharedPhotoAssets(napi_env env, napi_callback_info info)
1743 {
1744     MediaLibraryTracer tracer;
1745     tracer.Start("PhotoAccessGetSharedPhotoAssets");
1746     unique_ptr<SendablePhotoAccessHelperAsyncContext> asyncContext =
1747         make_unique<SendablePhotoAccessHelperAsyncContext>();
1748     asyncContext->assetType = TYPE_PHOTO;
1749     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext, true));
1750 
1751     SendablePhotoAccessHelperAsyncContext* context =
1752         static_cast<SendablePhotoAccessHelperAsyncContext*>((asyncContext.get()));
1753     string queryUri = PAH_QUERY_PHOTO;
1754     SendableMediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1755 
1756     Uri uri(queryUri);
1757     shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
1758         context->predicates, context->fetchColumn);
1759     CHECK_NULLPTR_RET(resultSet);
1760 
1761     napi_value jsFileArray = 0;
1762     napi_create_array(env, &jsFileArray);
1763 
1764     int count = 0;
1765     int err = resultSet->GoToFirstRow();
1766     if (err != napi_ok) {
1767         NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
1768         return jsFileArray;
1769     }
1770     do {
1771         napi_value item = SendableMediaLibraryNapiUtils::GetNextRowObject(env, resultSet);
1772         napi_set_element(env, jsFileArray, count++, item);
1773     } while (!resultSet->GoToNextRow());
1774     resultSet->Close();
1775     return jsFileArray;
1776 }
1777 } // namespace Media
1778 } // namespace OHOS