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