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