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