• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-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 "MediaLibraryNapi"
17 #define ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE "ability.want.params.uiExtensionTargetType"
18 
19 #include "media_library_napi.h"
20 
21 #include <fcntl.h>
22 #include <sys/sendfile.h>
23 #include <functional>
24 
25 #include "access_token.h"
26 #include "accesstoken_kit.h"
27 #include "ability_context.h"
28 #include "confirm_callback.h"
29 #include "context.h"
30 #include "directory_ex.h"
31 #include "file_ex.h"
32 #include "hitrace_meter.h"
33 #include "ipc_skeleton.h"
34 #include "location_column.h"
35 #include "media_device_column.h"
36 #include "media_directory_type_column.h"
37 #include "media_file_asset_columns.h"
38 #include "media_change_request_napi.h"
39 #include "media_column.h"
40 #include "media_app_uri_permission_column.h"
41 #include "media_app_uri_sensitive_column.h"
42 #include "media_file_uri.h"
43 #include "media_file_utils.h"
44 #include "media_smart_album_column.h"
45 #include "media_smart_map_column.h"
46 #include "medialibrary_client_errno.h"
47 #include "medialibrary_data_manager.h"
48 #include "medialibrary_db_const.h"
49 #include "medialibrary_errno.h"
50 #include "medialibrary_napi_log.h"
51 #include "medialibrary_peer_info.h"
52 #include "medialibrary_tracer.h"
53 #include "modal_ui_callback.h"
54 #include "modal_ui_extension_config.h"
55 #include "napi_base_context.h"
56 #include "napi_common_want.h"
57 #include "photo_album_column.h"
58 #include "photo_album_napi.h"
59 #include "result_set_utils.h"
60 #include "safe_map.h"
61 #include "search_column.h"
62 #include "short_term_callback.h"
63 #include "smart_album_napi.h"
64 #include "story_album_column.h"
65 #include "string_ex.h"
66 #include "string_wrapper.h"
67 #include "userfile_client.h"
68 #include "uv.h"
69 #include "form_map.h"
70 #include "ui_content.h"
71 #include "ui_extension_context.h"
72 #include "want.h"
73 #include "js_native_api.h"
74 #include "js_native_api_types.h"
75 #include "delete_callback.h"
76 #include "window.h"
77 #include "permission_utils.h"
78 
79 using namespace std;
80 using namespace OHOS::AppExecFwk;
81 using namespace OHOS::NativeRdb;
82 using namespace OHOS::DataShare;
83 using namespace OHOS::Security::AccessToken;
84 
85 namespace OHOS {
86 namespace Media {
87 using ChangeType = AAFwk::ChangeInfo::ChangeType;
88 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
89 const int32_t NUM_2 = 2;
90 const int32_t NUM_3 = 3;
91 const string DATE_FUNCTION = "DATE(";
92 const int32_t FORMID_MAX_LEN = 19;
93 const int32_t SLEEP_TIME = 100;
94 const int64_t MAX_INT64 = 9223372036854775807;
95 const int32_t MAX_QUERY_LIMIT = 15;
96 constexpr uint32_t CONFIRM_BOX_ARRAY_MAX_LENGTH = 100;
97 
98 mutex MediaLibraryNapi::sUserFileClientMutex_;
99 mutex MediaLibraryNapi::sOnOffMutex_;
100 string ChangeListenerNapi::trashAlbumUri_;
101 static SafeMap<int32_t, std::shared_ptr<ThumbnailBatchGenerateObserver>> thumbnailGenerateObserverMap;
102 static SafeMap<int32_t, std::shared_ptr<ThumbnailGenerateHandler>> thumbnailGenerateHandlerMap;
103 static std::atomic<int32_t> requestIdCounter_ = 0;
104 static std::atomic<int32_t> requestIdCallback_ = 0;
105 static map<string, ListenerType> ListenerTypeMaps = {
106     {"audioChange", AUDIO_LISTENER},
107     {"videoChange", VIDEO_LISTENER},
108     {"imageChange", IMAGE_LISTENER},
109     {"fileChange", FILE_LISTENER},
110     {"albumChange", ALBUM_LISTENER},
111     {"deviceChange", DEVICE_LISTENER},
112     {"remoteFileChange", REMOTEFILE_LISTENER}
113 };
114 
115 const std::string SUBTYPE = "subType";
116 const std::string PAH_SUBTYPE = "subtype";
117 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
118 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
119     { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
120     { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
121     { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
122 
123 };
124 
125 const std::string TITLE = "title";
126 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
127     { TITLE, MediaColumn::MEDIA_TITLE }
128 };
129 
130 const std::string EXTENSION = "fileNameExtension";
131 const std::string PHOTO_TYPE = "photoType";
132 const std::string PHOTO_SUB_TYPE = "subtype";
133 const std::string SHORT_TERM_TAG = "shortTerm";
134 const std::string SHORT_TERM_TITLE = "title";
135 const std::string SHORT_TERM_EXTENSION = "extension";
136 const std::string SHORT_TERM_PHOTO_TYPE = "photoType";
137 const std::string SHORT_TERM_PHOTO_SUB_TYPE = "photoSubType";
138 const std::string CONFIRM_BOX_PACKAGE_NAME = "com.ohos.photos";
139 const std::string CONFIRM_BOX_EXT_ABILITY_NAME = "SaveUIExtensionAbility";
140 const std::string CONFIRM_BOX_EXTENSION_TYPE = "ability.want.params.uiExtensionType";
141 const std::string CONFIRM_BOX_REQUEST_TYPE = "sysDialog/common";
142 const std::string CONFIRM_BOX_SRC_FILE_URIS = "ability.params.stream";
143 const std::string CONFIRM_BOX_TITLE_ARRAY = "titleArray";
144 const std::string CONFIRM_BOX_EXTENSION_ARRAY = "extensionArray";
145 const std::string CONFIRM_BOX_PHOTO_TYPE_ARRAY = "photoTypeArray";
146 const std::string CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY = "photoSubTypeArray";
147 const std::string CONFIRM_BOX_BUNDLE_NAME = "bundleName";
148 const std::string CONFIRM_BOX_APP_NAME = "appName";
149 const std::string CONFIRM_BOX_APP_ID = "appId";
150 
151 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
152 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
153 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
154 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
155 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
156 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
157 thread_local napi_ref MediaLibraryNapi::sDeliveryModeEnumRef_ = nullptr;
158 thread_local napi_ref MediaLibraryNapi::sSourceModeEnumRef_ = nullptr;
159 thread_local napi_ref MediaLibraryNapi::sResourceTypeEnumRef_ = nullptr;
160 thread_local napi_ref MediaLibraryNapi::sPositionTypeEnumRef_ = nullptr;
161 thread_local napi_ref MediaLibraryNapi::sPhotoSubType_ = nullptr;
162 thread_local napi_ref MediaLibraryNapi::sPhotoPermissionType_ = nullptr;
163 thread_local napi_ref MediaLibraryNapi::sHideSensitiveType_ = nullptr;
164 thread_local napi_ref MediaLibraryNapi::sDynamicRangeType_ = nullptr;
165 thread_local napi_ref MediaLibraryNapi::sHiddenPhotosDisplayModeEnumRef_ = nullptr;
166 thread_local napi_ref MediaLibraryNapi::sAuthorizationModeEnumRef_ = nullptr;
167 using CompleteCallback = napi_async_complete_callback;
168 using Context = MediaLibraryAsyncContext* ;
169 
170 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
171 thread_local napi_ref MediaLibraryNapi::photoAccessHelperConstructor_ = nullptr;
172 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
173 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
174 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
175 thread_local napi_ref MediaLibraryNapi::sPhotoKeysEnumRef_ = nullptr;
176 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
177 thread_local napi_ref MediaLibraryNapi::sAlbumType_ = nullptr;
178 thread_local napi_ref MediaLibraryNapi::sAlbumSubType_ = nullptr;
179 thread_local napi_ref MediaLibraryNapi::sNotifyType_ = nullptr;
180 thread_local napi_ref MediaLibraryNapi::sDefaultChangeUriRef_ = nullptr;
181 thread_local napi_ref MediaLibraryNapi::sRequestPhotoTypeEnumRef_ = nullptr;
182 thread_local napi_ref MediaLibraryNapi::sAnalysisType_ = nullptr;
183 thread_local napi_ref MediaLibraryNapi::sHighlightAlbumInfoType_ = nullptr;
184 thread_local napi_ref MediaLibraryNapi::sHighlightUserActionType_ = nullptr;
185 thread_local napi_ref MediaLibraryNapi::sMovingPhotoEffectModeEnumRef_ = nullptr;
186 thread_local napi_ref MediaLibraryNapi::sImageFileTypeEnumEnumRef_ = nullptr;
187 thread_local napi_ref MediaLibraryNapi::sCloudEnhancementTaskStageEnumRef_ = nullptr;
188 thread_local napi_ref MediaLibraryNapi::sCloudEnhancementStateEnumRef_ = nullptr;
189 thread_local napi_ref MediaLibraryNapi::sVideoEnhancementTypeEnumRef_ = nullptr;
190 
191 constexpr int32_t DEFAULT_REFCOUNT = 1;
192 constexpr int32_t DEFAULT_ALBUM_COUNT = 1;
MediaLibraryNapi()193 MediaLibraryNapi::MediaLibraryNapi()
194     : env_(nullptr) {}
195 
196 MediaLibraryNapi::~MediaLibraryNapi() = default;
197 
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)198 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
199 {
200     MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
201     if (mediaLibrary != nullptr) {
202         delete mediaLibrary;
203         mediaLibrary = nullptr;
204     }
205 }
206 
Init(napi_env env,napi_value exports)207 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
208 {
209     napi_property_descriptor media_library_properties[] = {
210         DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
211         DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
212         DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
213         DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
214         DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
215         DECLARE_NAPI_FUNCTION("on", JSOnCallback),
216         DECLARE_NAPI_FUNCTION("off", JSOffCallback),
217         DECLARE_NAPI_FUNCTION("release", JSRelease),
218         DECLARE_NAPI_FUNCTION("getSmartAlbum", JSGetSmartAlbums),
219         DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
220         DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
221         DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
222         DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
223         DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
224         DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
225         DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
226     };
227     napi_property_descriptor static_prop[] = {
228         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
229         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibraryAsync", GetMediaLibraryNewInstanceAsync),
230         DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
231         DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
232         DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
233         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
234     };
235     napi_value ctorObj;
236     napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
237         MediaLibraryNapiConstructor, nullptr,
238         sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
239         media_library_properties, &ctorObj);
240     if (status == napi_ok) {
241         int32_t refCount = 1;
242         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
243             status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
244             if (status == napi_ok && napi_define_properties(env, exports,
245                 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
246                 return exports;
247             }
248         }
249     }
250     return nullptr;
251 }
252 
UserFileMgrInit(napi_env env,napi_value exports)253 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
254 {
255     NapiClassInfo info = {
256         USERFILE_MGR_NAPI_CLASS_NAME,
257         &userFileMgrConstructor_,
258         MediaLibraryNapiConstructor,
259         {
260             DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
261             DECLARE_NAPI_FUNCTION("getAudioAssets", JSGetAudioAssets),
262             DECLARE_NAPI_FUNCTION("getPhotoAlbums", JSGetPhotoAlbums),
263             DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreatePhotoAsset),
264             DECLARE_NAPI_FUNCTION("createAudioAsset", UserFileMgrCreateAudioAsset),
265             DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
266             DECLARE_NAPI_FUNCTION("on", UserFileMgrOnCallback),
267             DECLARE_NAPI_FUNCTION("off", UserFileMgrOffCallback),
268             DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
269             DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
270             DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
271             DECLARE_NAPI_FUNCTION("release", JSRelease),
272             DECLARE_NAPI_FUNCTION("createAlbum", CreatePhotoAlbum),
273             DECLARE_NAPI_FUNCTION("deleteAlbums", DeletePhotoAlbums),
274             DECLARE_NAPI_FUNCTION("getAlbums", GetPhotoAlbums),
275             DECLARE_NAPI_FUNCTION("getPhotoIndex", JSGetPhotoIndex),
276             DECLARE_NAPI_FUNCTION("setHidden", SetHidden),
277         }
278     };
279     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
280 
281     const vector<napi_property_descriptor> staticProps = {
282         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
283         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgrAsync", GetUserFileMgrAsync),
284         DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
285         DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
286         DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
287         DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
288         DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
289         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
290         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
291         DECLARE_NAPI_PROPERTY("AlbumSubType", CreateAlbumSubTypeEnum(env)),
292         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
293         DECLARE_NAPI_PROPERTY("PhotoSubType", CreatePhotoSubTypeEnum(env)),
294         DECLARE_NAPI_PROPERTY("PhotoPermissionType", CreatePhotoPermissionTypeEnum(env)),
295         DECLARE_NAPI_PROPERTY("HideSensitiveType", CreateHideSensitiveTypeEnum(env)),
296         DECLARE_NAPI_PROPERTY("DynamicRangeType", CreateDynamicRangeTypeEnum(env)),
297         DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
298         DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env)),
299         DECLARE_NAPI_PROPERTY("HiddenPhotosDisplayMode", CreateHiddenPhotosDisplayModeEnum(env)),
300         DECLARE_NAPI_PROPERTY("RequestPhotoType", CreateRequestPhotoTypeEnum(env))
301     };
302     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
303     return exports;
304 }
305 
PhotoAccessHelperInit(napi_env env,napi_value exports)306 napi_value MediaLibraryNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
307 {
308     NapiClassInfo info = { PHOTOACCESSHELPER_NAPI_CLASS_NAME, &photoAccessHelperConstructor_,
309         MediaLibraryNapiConstructor,
310         {
311             DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
312             DECLARE_NAPI_FUNCTION("getBurstAssets", PhotoAccessGetBurstAssets),
313             DECLARE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
314             DECLARE_NAPI_FUNCTION("registerChange", PhotoAccessHelperOnCallback),
315             DECLARE_NAPI_FUNCTION("unRegisterChange", PhotoAccessHelperOffCallback),
316             DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperTrashAsset),
317             DECLARE_NAPI_FUNCTION("release", JSRelease),
318             DECLARE_NAPI_FUNCTION("createAlbum", PhotoAccessCreatePhotoAlbum),
319             DECLARE_NAPI_FUNCTION("deleteAlbums", PhotoAccessDeletePhotoAlbums),
320             DECLARE_NAPI_FUNCTION("getAlbums", PhotoAccessGetPhotoAlbums),
321             DECLARE_NAPI_FUNCTION("getPhotoIndex", PhotoAccessGetPhotoIndex),
322             DECLARE_NAPI_FUNCTION("getIndexConstructProgress", PhotoAccessGetIndexConstructProgress),
323             DECLARE_NAPI_FUNCTION("setHidden", SetHidden),
324             DECLARE_NAPI_FUNCTION("getHiddenAlbums", PahGetHiddenAlbums),
325             DECLARE_NAPI_FUNCTION("applyChanges", JSApplyChanges),
326             DECLARE_NAPI_FUNCTION("saveFormInfo", PhotoAccessSaveFormInfo),
327             DECLARE_NAPI_FUNCTION("removeFormInfo", PhotoAccessRemoveFormInfo),
328             DECLARE_NAPI_FUNCTION("getAssetsSync", PhotoAccessGetPhotoAssetsSync),
329             DECLARE_NAPI_FUNCTION("getAlbumsSync", PhotoAccessGetPhotoAlbumsSync),
330             DECLARE_NAPI_FUNCTION("getFileAssetsInfo", PhotoAccessGetFileAssetsInfo),
331             DECLARE_NAPI_FUNCTION("startCreateThumbnailTask", PhotoAccessStartCreateThumbnailTask),
332             DECLARE_NAPI_FUNCTION("stopCreateThumbnailTask", PhotoAccessStopCreateThumbnailTask),
333             DECLARE_NAPI_FUNCTION("createAssetsForApp", PhotoAccessHelperAgentCreateAssets),
334             DECLARE_NAPI_FUNCTION("createAssetsHasPermission", CreateAssetsHasPermission),
335             DECLARE_NAPI_FUNCTION("grantPhotoUriPermission", PhotoAccessGrantPhotoUriPermission),
336             DECLARE_NAPI_FUNCTION("grantPhotoUrisPermission", PhotoAccessGrantPhotoUrisPermission),
337             DECLARE_NAPI_FUNCTION("cancelPhotoUriPermission", PhotoAccessCancelPhotoUriPermission),
338             DECLARE_NAPI_FUNCTION("createAssetsForAppWithMode", PhotoAccessHelperAgentCreateAssetsWithMode),
339         }
340     };
341     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
342 
343     const vector<napi_property_descriptor> staticProps = {
344         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
345         DECLARE_NAPI_STATIC_FUNCTION("startPhotoPicker", StartPhotoPicker),
346         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelperAsync", GetPhotoAccessHelperAsync),
347         DECLARE_NAPI_STATIC_FUNCTION("createDeleteRequest", CreateDeleteRequest),
348         DECLARE_NAPI_STATIC_FUNCTION("showAssetsCreationDialog", ShowAssetsCreationDialog),
349         DECLARE_NAPI_STATIC_FUNCTION("checkShortTermPermission", CheckShortTermPermission),
350         DECLARE_NAPI_STATIC_FUNCTION("createAssetWithShortTermPermission", CreateAssetWithShortTermPermission),
351         DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
352         DECLARE_NAPI_PROPERTY("AlbumKeys", CreateAlbumKeyEnum(env)),
353         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
354         DECLARE_NAPI_PROPERTY("PhotoKeys", CreatePhotoKeysEnum(env)),
355         DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
356         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
357         DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
358         DECLARE_NAPI_PROPERTY("PhotoPermissionType", CreatePhotoPermissionTypeEnum(env)),
359         DECLARE_NAPI_PROPERTY("HideSensitiveType", CreateHideSensitiveTypeEnum(env)),
360         DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
361         DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env)),
362         DECLARE_NAPI_PROPERTY("HiddenPhotosDisplayMode", CreateHiddenPhotosDisplayModeEnum(env)),
363         DECLARE_NAPI_PROPERTY("RequestPhotoType", CreateRequestPhotoTypeEnum(env)),
364         DECLARE_NAPI_PROPERTY("AnalysisType", CreateAnalysisTypeEnum(env)),
365         DECLARE_NAPI_PROPERTY("DeliveryMode", CreateDeliveryModeEnum(env)),
366         DECLARE_NAPI_PROPERTY("SourceMode", CreateSourceModeEnum(env)),
367         DECLARE_NAPI_PROPERTY("ResourceType", CreateResourceTypeEnum(env)),
368         DECLARE_NAPI_PROPERTY("HighlightAlbumInfoType", CreateHighlightAlbumInfoTypeEnum(env)),
369         DECLARE_NAPI_PROPERTY("HighlightUserActionType", CreateHighlightUserActionTypeEnum(env)),
370         DECLARE_NAPI_PROPERTY("MovingPhotoEffectMode", CreateMovingPhotoEffectModeEnum(env)),
371         DECLARE_NAPI_PROPERTY("ImageFileType", CreateImageFileTypeEnum(env)),
372         DECLARE_NAPI_PROPERTY("AuthorizationMode", CreateAuthorizationModeEnum(env)),
373         DECLARE_NAPI_PROPERTY("CloudEnhancementTaskStage", CreateCloudEnhancementTaskStageEnum(env)),
374         DECLARE_NAPI_PROPERTY("CloudEnhancementState", CreateCloudEnhancementStateEnum(env)),
375         DECLARE_NAPI_PROPERTY("VideoEnhancementType", CreateVideoEnhancementTypeEnum(env)),
376     };
377     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
378     return exports;
379 }
380 
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)381 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
382 {
383     isAsync = false;
384     size_t argc = ARGS_TWO;
385     napi_value argv[ARGS_TWO] = {0};
386     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
387     if (status != napi_ok) {
388         NAPI_ERR_LOG("Error while obtaining js environment information");
389         return status;
390     }
391 
392     if (argc == ARGS_ONE) {
393         return napi_ok;
394     } else if (argc == ARGS_TWO) {
395         napi_valuetype valueType = napi_undefined;
396         status = napi_typeof(env, argv[ARGS_ONE], &valueType);
397         if (status != napi_ok) {
398             NAPI_ERR_LOG("Error while obtaining js environment information");
399             return status;
400         }
401         if (valueType == napi_boolean) {
402             isAsync = true;
403         }
404         status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
405         return status;
406     } else {
407         NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
408         return napi_invalid_arg;
409     }
410 }
411 
412 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)413 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
414 {
415     napi_status status;
416     napi_value result = nullptr;
417     napi_value thisVar = nullptr;
418     MediaLibraryTracer tracer;
419 
420     tracer.Start("MediaLibraryNapiConstructor");
421 
422     NAPI_CALL(env, napi_get_undefined(env, &result));
423     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
424     if (status != napi_ok || thisVar == nullptr) {
425         NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
426         return result;
427     }
428 
429     unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
430     if (obj == nullptr) {
431         return result;
432     }
433     obj->env_ = env;
434     // Initialize the ChangeListener object
435     if (g_listObj == nullptr) {
436         g_listObj = make_unique<ChangeListenerNapi>(env);
437     }
438 
439     bool isAsync = false;
440     NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
441     if (!isAsync) {
442         unique_lock<mutex> helperLock(sUserFileClientMutex_);
443         if (!UserFileClient::IsValid()) {
444             UserFileClient::Init(env, info);
445             if (!UserFileClient::IsValid()) {
446                 NAPI_ERR_LOG("UserFileClient creation failed");
447                 helperLock.unlock();
448                 return result;
449             }
450         }
451         helperLock.unlock();
452     }
453 
454     status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
455                        MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
456     if (status == napi_ok) {
457         obj.release();
458         return thisVar;
459     } else {
460         NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
461     }
462 
463     return result;
464 }
465 
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid)466 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid)
467 {
468     napi_value propertyNames;
469     uint32_t propertyLength;
470     napi_valuetype valueType = napi_undefined;
471     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
472     if (valueType != napi_object) {
473         return false;
474     }
475 
476     NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
477     NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
478     if (propertyLength == 0) {
479         return false;
480     }
481     if (checkIsValid && (!UserFileClient::IsValid())) {
482         NAPI_ERR_LOG("UserFileClient is not valid");
483         return false;
484     }
485     return true;
486 }
487 
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)488 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
489     bool isAsync = false)
490 {
491     constexpr size_t ARG_CONTEXT = 1;
492     size_t argc = ARG_CONTEXT;
493     napi_value argv[ARGS_TWO] = {0};
494 
495     napi_value thisVar = nullptr;
496     napi_value ctor = nullptr;
497     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
498     NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
499 
500     if (isAsync) {
501         argc = ARGS_TWO;
502         NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
503         argv[ARGS_ONE] = argv[ARG_CONTEXT];
504     }
505 
506     napi_value result = nullptr;
507     NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
508     if (!CheckWhetherInitSuccess(env, result, !isAsync)) {
509         NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
510         NAPI_CALL(env, napi_get_undefined(env, &result));
511     }
512     return result;
513 }
514 
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)515 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
516 {
517     MediaLibraryTracer tracer;
518     tracer.Start("getMediaLibrary");
519 
520     napi_value result = nullptr;
521     napi_value ctor;
522     size_t argc = ARGS_ONE;
523     napi_value argv[ARGS_ONE] = {0};
524     napi_value thisVar = nullptr;
525     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
526     napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
527     if (status == napi_ok) {
528         status = napi_new_instance(env, ctor, argc, argv, &result);
529         if (status == napi_ok) {
530             if (CheckWhetherInitSuccess(env, result, true)) {
531                 return result;
532             } else {
533                 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
534             }
535         } else {
536             NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
537         }
538     } else {
539         NAPI_ERR_LOG("status = %{public}d", status);
540     }
541 
542     napi_get_undefined(env, &result);
543     return result;
544 }
545 
GetMediaLibraryAsyncExecute(napi_env env,void * data)546 static void GetMediaLibraryAsyncExecute(napi_env env, void *data)
547 {
548     MediaLibraryTracer tracer;
549     tracer.Start("GetMediaLibraryAsyncExecute");
550 
551     MediaLibraryInitContext *asyncContext = static_cast<MediaLibraryInitContext *>(data);
552     if (asyncContext == nullptr) {
553         NAPI_ERR_LOG("Async context is null");
554         return;
555     }
556 
557     asyncContext->error = ERR_DEFAULT;
558     unique_lock<mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
559     if (!UserFileClient::IsValid()) {
560         UserFileClient::Init(asyncContext->token_, true);
561         if (!UserFileClient::IsValid()) {
562             NAPI_ERR_LOG("UserFileClient creation failed");
563             asyncContext->error = ERR_INVALID_OUTPUT;
564             helperLock.unlock();
565             return;
566         }
567     }
568     helperLock.unlock();
569 }
570 
GetMediaLibraryAsyncComplete(napi_env env,napi_status status,void * data)571 static void GetMediaLibraryAsyncComplete(napi_env env, napi_status status, void *data)
572 {
573     MediaLibraryInitContext *context = static_cast<MediaLibraryInitContext *>(data);
574     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
575     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
576     jsContext->status = false;
577 
578     napi_value result = nullptr;
579     if (napi_get_reference_value(env, context->resultRef_, &result) != napi_ok) {
580         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
581             "Get result from context ref failed");
582     }
583     napi_valuetype valueType;
584     if (napi_typeof(env, result, &valueType) != napi_ok || valueType != napi_object) {
585         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
586             "Get result type failed " + to_string((int) valueType));
587     }
588 
589     if (context->error == ERR_DEFAULT) {
590         jsContext->data = result;
591         jsContext->status = true;
592         napi_get_undefined(env, &jsContext->error);
593     } else {
594         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
595             "Failed to get MediaLibrary");
596         napi_get_undefined(env, &jsContext->data);
597     }
598 
599     if (context->work != nullptr) {
600         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
601             context->work, *jsContext);
602     }
603     napi_delete_reference(env, context->resultRef_);
604     delete context;
605 }
606 
GetMediaLibraryNewInstanceAsync(napi_env env,napi_callback_info info)607 napi_value MediaLibraryNapi::GetMediaLibraryNewInstanceAsync(napi_env env, napi_callback_info info)
608 {
609     MediaLibraryTracer tracer;
610     tracer.Start("getMediaLibraryAsync");
611 
612     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
613     if (asyncContext == nullptr) {
614         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
615         return nullptr;
616     }
617     asyncContext->argc = ARGS_TWO;
618     napi_value thisVar = nullptr;
619     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
620         &thisVar, nullptr));
621 
622     napi_value result = CreateNewInstance(env, info, sConstructor_, true);
623     napi_valuetype valueType;
624     NAPI_CALL(env, napi_typeof(env, result, &valueType));
625     if (valueType == napi_undefined) {
626         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
627         return nullptr;
628     }
629     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
630     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
631 
632     bool isStage = false;
633     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
634     if (isStage) {
635         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
636     } else {
637         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
638     }
639 
640     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
641         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
642 }
643 
GetUserFileMgr(napi_env env,napi_callback_info info)644 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
645 {
646     MediaLibraryTracer tracer;
647     tracer.Start("getUserFileManager");
648 
649     if (!MediaLibraryNapiUtils::IsSystemApp()) {
650         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
651         return nullptr;
652     }
653 
654     return CreateNewInstance(env, info, userFileMgrConstructor_);
655 }
656 
GetUserFileMgrAsync(napi_env env,napi_callback_info info)657 napi_value MediaLibraryNapi::GetUserFileMgrAsync(napi_env env, napi_callback_info info)
658 {
659     MediaLibraryTracer tracer;
660     tracer.Start("getUserFileManagerAsync");
661 
662     if (!MediaLibraryNapiUtils::IsSystemApp()) {
663         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
664         return nullptr;
665     }
666 
667     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
668     if (asyncContext == nullptr) {
669         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
670         return nullptr;
671     }
672     asyncContext->argc = ARGS_TWO;
673     napi_value thisVar = nullptr;
674     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
675         &thisVar, nullptr));
676 
677     napi_value result = CreateNewInstance(env, info, userFileMgrConstructor_, true);
678     napi_valuetype valueType;
679     NAPI_CALL(env, napi_typeof(env, result, &valueType));
680     if (valueType == napi_undefined) {
681         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
682         return nullptr;
683     }
684     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
685     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
686 
687     bool isStage = false;
688     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
689     if (isStage) {
690         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
691     } else {
692         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
693     }
694 
695     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
696         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
697 }
698 
GetPhotoAccessHelper(napi_env env,napi_callback_info info)699 napi_value MediaLibraryNapi::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
700 {
701     MediaLibraryTracer tracer;
702     tracer.Start("GetPhotoAccessHelper");
703 
704     return CreateNewInstance(env, info, photoAccessHelperConstructor_);
705 }
706 
GetPhotoAccessHelperAsync(napi_env env,napi_callback_info info)707 napi_value MediaLibraryNapi::GetPhotoAccessHelperAsync(napi_env env, napi_callback_info info)
708 {
709     MediaLibraryTracer tracer;
710     tracer.Start("GetPhotoAccessHelperAsync");
711 
712     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
713     if (asyncContext == nullptr) {
714         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
715         return nullptr;
716     }
717     asyncContext->argc = ARGS_TWO;
718     napi_value thisVar = nullptr;
719     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
720         &thisVar, nullptr));
721 
722     napi_value result = CreateNewInstance(env, info, photoAccessHelperConstructor_, true);
723     napi_valuetype valueType;
724     NAPI_CALL(env, napi_typeof(env, result, &valueType));
725     if (valueType == napi_undefined) {
726         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
727         return nullptr;
728     }
729     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
730     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
731 
732     bool isStage = false;
733     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
734     if (isStage) {
735         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
736     } else {
737         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
738     }
739 
740     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAccessHelperAsync",
741         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
742 }
743 
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)744 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
745     const string &name, int32_t enumValue)
746 {
747     napi_value enumNapiValue;
748     napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
749     if (status == napi_ok) {
750         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
751     }
752     return status;
753 }
754 
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)755 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
756 {
757     napi_value result = nullptr;
758     NAPI_CALL(env, napi_create_object(env, &result));
759     for (size_t i = 0; i < properties.size(); i++) {
760         NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], static_cast<int32_t>(i) + offset));
761     }
762     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
763     return result;
764 }
765 
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)766 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
767     const string &name, string enumValue)
768 {
769     napi_value enumNapiValue;
770     napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
771     if (status == napi_ok) {
772         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
773     }
774     return status;
775 }
776 
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)777 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
778 {
779     napi_value result = nullptr;
780     NAPI_CALL(env, napi_create_object(env, &result));
781     for (unsigned int i = 0; i < properties.size(); i++) {
782         NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
783     }
784     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
785     return result;
786 }
787 
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)788 static void DealWithCommonParam(napi_env env, napi_value arg,
789     const MediaLibraryAsyncContext &context, bool &err, bool &present)
790 {
791     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
792     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
793 
794     string propertyName = "selections";
795     string tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
796     if (!tmp.empty()) {
797         asyncContext->selection = tmp;
798     }
799 
800     propertyName = "order";
801     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
802     if (!tmp.empty()) {
803         asyncContext->order = tmp;
804     }
805 
806     propertyName = "uri";
807     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
808     if (!tmp.empty()) {
809         asyncContext->uri = tmp;
810     }
811 
812     propertyName = "networkId";
813     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
814     if (!tmp.empty()) {
815         asyncContext->networkId = tmp;
816     }
817 
818     propertyName = "extendArgs";
819     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
820     if (!tmp.empty()) {
821         asyncContext->extendArgs = tmp;
822     }
823 }
824 
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)825 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
826 {
827     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
828     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
829     napi_value property = nullptr;
830     napi_value stringItem = nullptr;
831     bool present = false;
832     DealWithCommonParam(env, arg, context, err, present);
833     napi_has_named_property(env, arg, "selectionArgs", &present);
834     if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
835         uint32_t len = 0;
836         napi_get_array_length(env, property, &len);
837         char buffer[PATH_MAX];
838         for (size_t i = 0; i < len; i++) {
839             napi_get_element(env, property, i, &stringItem);
840             size_t res = 0;
841             napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
842             asyncContext->selectionArgs.push_back(string(buffer));
843             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
844         }
845     } else {
846         NAPI_ERR_LOG("Could not get the string argument!");
847         err = true;
848     }
849 }
850 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)851 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
852     MediaLibraryAsyncContext &asyncContext)
853 {
854     bool err = false;
855     const int32_t refCount = 1;
856     auto context = &asyncContext;
857 
858     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
859     for (size_t i = PARAM0; i < argc; i++) {
860         napi_valuetype valueType = napi_undefined;
861         napi_typeof(env, argv[i], &valueType);
862 
863         if (i == PARAM0 && valueType == napi_object) {
864             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
865         } else if (i == PARAM0 && valueType == napi_function) {
866             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
867             break;
868         } else if (i == PARAM1 && valueType == napi_function) {
869             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
870             break;
871         } else {
872             NAPI_ASSERT(env, false, "type mismatch");
873         }
874         if (err) {
875             NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
876             NAPI_ASSERT(env, false, "type mismatch");
877         }
878     }
879 
880     // Return true napi_value if params are successfully obtained
881     napi_value result;
882     napi_get_boolean(env, true, &result);
883     return result;
884 }
885 
GetPublicDirectoryExecute(napi_env env,void * data)886 static void GetPublicDirectoryExecute(napi_env env, void *data)
887 {
888     MediaLibraryTracer tracer;
889     tracer.Start("GetPublicDirectoryExecute");
890 
891     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
892     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
893 
894     vector<string> selectionArgs;
895     vector<string> columns;
896     DataSharePredicates predicates;
897     selectionArgs.push_back(to_string(context->dirType));
898     predicates.SetWhereClause(DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
899     predicates.SetWhereArgs(selectionArgs);
900     string queryUri = MEDIALIBRARY_DIRECTORY_URI;
901     Uri uri(queryUri);
902     int errCode = 0;
903     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
904     if (resultSet != nullptr) {
905         auto count = 0;
906         auto ret = resultSet->GetRowCount(count);
907         if (ret != NativeRdb::E_OK) {
908             NAPI_ERR_LOG("get rdbstore failed");
909             context->error = JS_INNER_FAIL;
910             return;
911         }
912         if (count == 0) {
913             NAPI_ERR_LOG("Query for get publicDirectory form db failed");
914             context->error = JS_INNER_FAIL;
915             return;
916         }
917         NAPI_INFO_LOG("Query for get publicDirectory count = %{private}d", count);
918         if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
919             context->directoryRelativePath = get<string>(
920                 ResultSetUtils::GetValFromColumn(DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
921         }
922         if (context->dirType == DirType::DIR_DOCUMENTS) {
923             context->directoryRelativePath = DOC_DIR_VALUES;
924         } else if (context->dirType == DirType::DIR_DOWNLOAD) {
925             context->directoryRelativePath = DOWNLOAD_DIR_VALUES;
926         }
927         return;
928     } else {
929         context->SaveError(errCode);
930         NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
931     }
932 }
933 
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)934 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
935 {
936     MediaLibraryTracer tracer;
937     tracer.Start("GetPublicDirectoryCallbackComplete");
938 
939     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
940     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
941     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
942     jsContext->status = false;
943     if (context->error == ERR_DEFAULT) {
944         napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
945         jsContext->status = true;
946         napi_get_undefined(env, &jsContext->error);
947     } else {
948         context->HandleError(env, jsContext->error);
949         napi_get_undefined(env, &jsContext->data);
950     }
951 
952     tracer.Finish();
953     if (context->work != nullptr) {
954         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
955                                                    context->work, *jsContext);
956     }
957 
958     delete context;
959 }
960 
JSGetPublicDirectory(napi_env env,napi_callback_info info)961 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
962 {
963     napi_status status;
964     napi_value result = nullptr;
965     size_t argc = ARGS_TWO;
966     napi_value argv[ARGS_TWO] = {0};
967     napi_value thisVar = nullptr;
968     const int32_t refCount = 1;
969 
970     MediaLibraryTracer tracer;
971     tracer.Start("JSGetPublicDirectory");
972 
973     GET_JS_ARGS(env, info, argc, argv, thisVar);
974     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
975     napi_get_undefined(env, &result);
976 
977     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
978     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
979     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
980         for (size_t i = PARAM0; i < argc; i++) {
981             napi_valuetype valueType = napi_undefined;
982             napi_typeof(env, argv[i], &valueType);
983 
984             if (i == PARAM0 && valueType == napi_number) {
985                 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
986             } else if (i == PARAM1 && valueType == napi_function) {
987                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
988                 break;
989             } else {
990                 NAPI_ASSERT(env, false, "type mismatch");
991             }
992         }
993         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
994             GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
995     }
996 
997     return result;
998 }
999 
1000 #ifdef MEDIALIBRARY_COMPATIBILITY
GetVirtualIdFromApi10Uri(const string & uri)1001 static string GetVirtualIdFromApi10Uri(const string &uri)
1002 {
1003     string fileId = MediaFileUtils::GetIdFromUri(uri);
1004     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1005         return fileId;
1006     }
1007     int32_t id;
1008     if (!StrToInt(fileId, id)) {
1009         NAPI_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1010         return fileId;
1011     }
1012     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
1013         return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE));
1014     } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
1015         return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO));
1016     } else {
1017         return fileId;
1018     }
1019 }
1020 #endif
1021 
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)1022 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
1023 {
1024     if (!context->uri.empty()) {
1025         NAPI_ERR_LOG("context->uri is = %{private}s", context->uri.c_str());
1026         context->networkId = MediaFileUtils::GetNetworkIdFromUri(context->uri);
1027 #ifdef MEDIALIBRARY_COMPATIBILITY
1028         string fileId = GetVirtualIdFromApi10Uri(context->uri);
1029 #else
1030         string fileId = MediaFileUtils::::GetIdFromUri(context->uri);
1031 #endif
1032         if (!fileId.empty()) {
1033             string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
1034 #ifdef MEDIALIBRARY_COMPATIBILITY
1035             context->selection = idPrefix;
1036             context->selectionArgs.clear();
1037             context->selectionArgs.emplace_back(fileId);
1038 #else
1039             MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
1040             context->selectionArgs.emplace_back(fileId);
1041 #endif
1042         }
1043     }
1044 
1045 #ifdef MEDIALIBRARY_COMPATIBILITY
1046     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, MediaColumn::ASSETS_QUERY_FILTER);
1047     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs, MEDIA_DATA_DB_RELATIVE_PATH,
1048         MEDIA_DATA_DB_RELATIVE_PATH, ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH);
1049 #else
1050     string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
1051     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
1052     context->selectionArgs.emplace_back("0");
1053 #endif
1054     string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
1055     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
1056     context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
1057 }
1058 
LogMedialibraryAPI(const string & saveUri)1059 static void LogMedialibraryAPI(const string& saveUri)
1060 {
1061     string logMedialibraryAPI = MEDIALIBRARY_DATA_URI + "/" + MISC_OPERATION + "/" + "log_medialibrary_api";
1062     Uri logUri(logMedialibraryAPI);
1063     DataShare::DataShareValuesBucket valuesBucket;
1064     string result;
1065     valuesBucket.Put("saveUri", saveUri);
1066     UserFileClient::InsertExt(logUri, valuesBucket, result);
1067 }
1068 
GetFileAssetsExecute(napi_env env,void * data)1069 static void GetFileAssetsExecute(napi_env env, void *data)
1070 {
1071     MediaLibraryTracer tracer;
1072     tracer.Start("GetFileAssetsExecute");
1073 
1074     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1075     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1076 
1077     GetFileAssetUpdateSelections(context);
1078     context->fetchColumn = FILE_ASSET_COLUMNS;
1079     if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
1080         string group(" GROUP BY (");
1081         group += context->extendArgs + " )";
1082         context->selection += group;
1083         context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
1084     }
1085     MediaLibraryNapiUtils::FixSpecialDateType(context->selection);
1086     context->predicates.SetWhereClause(context->selection);
1087     context->predicates.SetWhereArgs(context->selectionArgs);
1088     context->predicates.SetOrder(context->order);
1089 
1090     LogMedialibraryAPI("");
1091 
1092     string queryUri = MEDIALIBRARY_DATA_URI;
1093     if (!context->networkId.empty()) {
1094         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1095     }
1096     Uri uri(queryUri);
1097     int errCode = 0;
1098     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
1099         context->predicates, context->fetchColumn, errCode);
1100     if (resultSet != nullptr) {
1101         // Create FetchResult object using the contents of resultSet
1102         context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1103         context->fetchFileResult->SetNetworkId(context->networkId);
1104         return;
1105     } else {
1106         context->SaveError(errCode);
1107         NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
1108     }
1109 }
1110 
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1111 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
1112     unique_ptr<JSAsyncContextOutput> &jsContext)
1113 {
1114     // Create FetchResult object using the contents of resultSet
1115     if (context->fetchFileResult == nullptr) {
1116         NAPI_ERR_LOG("No fetch file result found!");
1117         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1118             "Failed to obtain Fetch File Result");
1119         return;
1120     }
1121     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
1122     if (fileResult == nullptr) {
1123         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1124             "Failed to create js object for Fetch File Result");
1125     } else {
1126         jsContext->data = fileResult;
1127         jsContext->status = true;
1128         napi_get_undefined(env, &jsContext->error);
1129     }
1130 }
1131 
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1132 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1133 {
1134     MediaLibraryTracer tracer;
1135     tracer.Start("GetFileAssetsAsyncCallbackComplete");
1136 
1137     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1138     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1139 
1140     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1141     jsContext->status = false;
1142     napi_get_undefined(env, &jsContext->data);
1143 
1144     if (context->error != ERR_DEFAULT) {
1145         context->HandleError(env, jsContext->error);
1146     } else {
1147         GetNapiFileResult(env, context, jsContext);
1148     }
1149 
1150     tracer.Finish();
1151     if (context->work != nullptr) {
1152         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1153                                                    context->work, *jsContext);
1154     }
1155     delete context;
1156 }
1157 
JSGetFileAssets(napi_env env,napi_callback_info info)1158 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
1159 {
1160     napi_status status;
1161     napi_value result = nullptr;
1162     size_t argc = ARGS_TWO;
1163     napi_value argv[ARGS_TWO] = {0};
1164     napi_value thisVar = nullptr;
1165 
1166     MediaLibraryTracer tracer;
1167     tracer.Start("JSGetFileAssets");
1168 
1169     GET_JS_ARGS(env, info, argc, argv, thisVar);
1170     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1171     napi_get_undefined(env, &result);
1172 
1173     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1174     asyncContext->mediaTypes.clear();
1175     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1176     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1177     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1178         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1179         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1180 
1181         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
1182             GetFileAssetsAsyncCallbackComplete);
1183     }
1184 
1185     return result;
1186 }
1187 
1188 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatSetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1189 static void CompatSetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1190 {
1191     MediaLibraryTracer tracer;
1192     tracer.Start("CompatSetAlbumCoverUri");
1193     DataSharePredicates predicates;
1194     int err;
1195     if (album->GetAlbumType() == PhotoAlbumType::USER) {
1196         err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates, false);
1197     } else {
1198         err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates, false);
1199     }
1200     if (err < 0) {
1201         NAPI_WARN_LOG("Failed to set cover uri for album subtype: %{public}d", album->GetAlbumSubType());
1202         return;
1203     }
1204     predicates.OrderByDesc(MediaColumn::MEDIA_DATE_ADDED);
1205     predicates.Limit(1, 0);
1206 
1207     Uri uri(URI_QUERY_PHOTO_MAP);
1208     vector<string> columns;
1209     columns.assign(MediaColumn::DEFAULT_FETCH_COLUMNS.begin(), MediaColumn::DEFAULT_FETCH_COLUMNS.end());
1210     auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1211     if (resultSet == nullptr) {
1212         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", err);
1213         context->SaveError(err);
1214         return;
1215     }
1216     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1217     if (fetchResult->GetCount() == 0) {
1218         return;
1219     }
1220     auto fileAsset = fetchResult->GetFirstObject();
1221     if (fileAsset == nullptr) {
1222         NAPI_WARN_LOG("Failed to get cover asset!");
1223         return;
1224     }
1225     album->SetCoverUri(fileAsset->GetUri());
1226 }
1227 
SetCompatAlbumName(AlbumAsset * albumData)1228 static void SetCompatAlbumName(AlbumAsset *albumData)
1229 {
1230     string albumName;
1231     switch (albumData->GetAlbumSubType()) {
1232         case PhotoAlbumSubType::CAMERA:
1233             albumName = CAMERA_ALBUM_NAME;
1234             break;
1235         case PhotoAlbumSubType::SCREENSHOT:
1236             albumName = SCREEN_SHOT_ALBUM_NAME;
1237             break;
1238         default:
1239             NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
1240     }
1241     albumData->SetAlbumName(albumName);
1242 }
1243 
CompatSetAlbumCount(unique_ptr<AlbumAsset> & album)1244 static void CompatSetAlbumCount(unique_ptr<AlbumAsset> &album)
1245 {
1246     MediaLibraryTracer tracer;
1247     tracer.Start("CompatSetAlbumCount");
1248     DataSharePredicates predicates;
1249     int err;
1250     if (album->GetAlbumType() == PhotoAlbumType::USER) {
1251         err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates, false);
1252     } else {
1253         err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates, false);
1254     }
1255     if (err < 0) {
1256         NAPI_WARN_LOG("Failed to set count for album subtype: %{public}d", album->GetAlbumSubType());
1257         album->SetCount(0);
1258         return;
1259     }
1260 
1261     Uri uri(URI_QUERY_PHOTO_MAP);
1262     vector<string> columns;
1263     auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1264     if (resultSet == nullptr) {
1265         NAPI_WARN_LOG("Query for assets failed! errorCode is = %{public}d", err);
1266         album->SetCount(0);
1267         return;
1268     }
1269     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1270     int32_t count = fetchResult->GetCount();
1271     album->SetCount(count);
1272 }
1273 #else
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1274 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1275 {
1276     MediaLibraryTracer tracer;
1277     tracer.Start("SetAlbumCoverUri");
1278     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1279     DataShare::DataSharePredicates predicates;
1280     predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
1281     predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
1282     predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
1283     vector<string> columns;
1284     string queryUri = MEDIALIBRARY_DATA_URI;
1285     if (!context->networkId.empty()) {
1286         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1287         NAPI_DEBUG_LOG("querycoverUri is = %{private}s", queryUri.c_str());
1288     }
1289     Uri uri(queryUri);
1290     int errCode = 0;
1291     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
1292         uri, predicates, columns, errCode);
1293     if (resultSet == nullptr) {
1294         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
1295         return;
1296     }
1297     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1298     fetchFileResult->SetNetworkId(context->networkId);
1299     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1300     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
1301     string coverUri = fileAsset->GetUri();
1302     album->SetCoverUri(coverUri);
1303     NAPI_DEBUG_LOG("coverUri is = %{private}s", album->GetCoverUri().c_str());
1304 }
1305 #endif
1306 
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)1307 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1308     const string &networkId)
1309 {
1310 #ifdef MEDIALIBRARY_COMPATIBILITY
1311     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
1312         TYPE_INT32)));
1313     albumData->SetAlbumType(static_cast<PhotoAlbumType>(
1314         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
1315     albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
1316         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
1317     SetCompatAlbumName(albumData);
1318 #else
1319     // Get album id index and value
1320     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
1321         TYPE_INT32)));
1322 
1323     // Get album title index and value
1324     albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
1325         TYPE_STRING)));
1326 #endif
1327 
1328     // Get album asset count index and value
1329     albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
1330     MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
1331         MEDIA_API_VERSION_DEFAULT);
1332     albumData->SetAlbumUri(fileUri.ToString());
1333     // Get album relativePath index and value
1334     albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
1335         resultSet, TYPE_STRING)));
1336     albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
1337         resultSet, TYPE_INT64)));
1338 }
1339 
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)1340 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
1341 {
1342     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1343         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1344         context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
1345         context->fetchAlbumResult->SetNetworkId(context->networkId);
1346         context->fetchAlbumResult->SetResultNapiType(context->resultNapiType);
1347         return;
1348     }
1349 
1350     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1351         unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
1352         if (albumData != nullptr) {
1353             SetAlbumData(albumData.get(), resultSet, context->networkId);
1354 #ifdef MEDIALIBRARY_COMPATIBILITY
1355             CompatSetAlbumCoverUri(context, albumData);
1356             CompatSetAlbumCount(albumData);
1357 #else
1358             SetAlbumCoverUri(context, albumData);
1359 #endif
1360             context->albumNativeArray.push_back(move(albumData));
1361         } else {
1362             context->SaveError(E_NO_MEMORY);
1363         }
1364     }
1365 }
1366 
1367 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)1368 static void ReplaceAlbumName(const string &arg, string &argInstead)
1369 {
1370     if (arg == CAMERA_ALBUM_NAME) {
1371         argInstead = to_string(PhotoAlbumSubType::CAMERA);
1372     } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
1373         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1374     } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
1375         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1376     } else {
1377         argInstead = arg;
1378     }
1379 }
1380 
DoReplaceRelativePath(const string & arg,string & argInstead)1381 static bool DoReplaceRelativePath(const string &arg, string &argInstead)
1382 {
1383     if (arg == CAMERA_PATH) {
1384         argInstead = to_string(PhotoAlbumSubType::CAMERA);
1385     } else if (arg == SCREEN_SHOT_PATH) {
1386         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1387     } else if (arg == SCREEN_RECORD_PATH) {
1388         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1389     } else if (arg.empty()) {
1390         argInstead = arg;
1391         return false;
1392     } else {
1393         argInstead = arg;
1394     }
1395     return true;
1396 }
1397 
ReplaceRelativePath(string & selection,size_t pos,const string & keyInstead,const string & arg,string & argInstead)1398 static inline void ReplaceRelativePath(string &selection, size_t pos, const string &keyInstead, const string &arg,
1399     string &argInstead)
1400 {
1401     bool shouldReplace = DoReplaceRelativePath(arg, argInstead);
1402     if (shouldReplace) {
1403         selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), keyInstead);
1404     }
1405 }
1406 
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead,const int32_t mode)1407 void MediaLibraryNapi::ReplaceSelection(string &selection, vector<string> &selectionArgs,
1408     const string &key, const string &keyInstead, const int32_t mode)
1409 {
1410     for (size_t pos = 0; pos != string::npos;) {
1411         pos = selection.find(key, pos);
1412         if (pos == string::npos) {
1413             break;
1414         }
1415 
1416         size_t argPos = selection.find('?', pos);
1417         if (argPos == string::npos) {
1418             break;
1419         }
1420         size_t argIndex = 0;
1421         for (size_t i = 0; i < argPos; i++) {
1422             if (selection[i] == '?') {
1423                 argIndex++;
1424             }
1425         }
1426         if (argIndex > selectionArgs.size() - 1) {
1427             NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
1428                 selection.c_str());
1429             break;
1430         }
1431         const string &arg = selectionArgs[argIndex];
1432         string argInstead = arg;
1433         if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
1434             if (mode == ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH) {
1435                 argInstead = MediaFileUtils::AddDocsToRelativePath(arg);
1436             } else {
1437                 ReplaceRelativePath(selection, pos, keyInstead, arg, argInstead);
1438             }
1439         } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
1440             ReplaceAlbumName(arg, argInstead);
1441             selection.replace(pos, key.length(), keyInstead);
1442         } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
1443             selection.replace(pos, key.length(), keyInstead);
1444         }
1445         selectionArgs[argIndex] = argInstead;
1446         argPos = selection.find('?', pos);
1447         if (argPos == string::npos) {
1448             break;
1449         }
1450         pos = argPos + 1;
1451     }
1452 }
1453 
UpdateCompatSelection(MediaLibraryAsyncContext * context)1454 static void UpdateCompatSelection(MediaLibraryAsyncContext *context)
1455 {
1456     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1457         MEDIA_DATA_DB_BUCKET_ID, PhotoAlbumColumns::ALBUM_ID);
1458     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1459         MEDIA_DATA_DB_BUCKET_NAME, PhotoAlbumColumns::ALBUM_SUBTYPE);
1460     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1461         MEDIA_DATA_DB_RELATIVE_PATH, PhotoAlbumColumns::ALBUM_SUBTYPE);
1462     static const string COMPAT_QUERY_FILTER = PhotoAlbumColumns::ALBUM_SUBTYPE + " IN (" +
1463         to_string(PhotoAlbumSubType::SCREENSHOT) + "," +
1464         to_string(PhotoAlbumSubType::CAMERA) + ")";
1465     if (!context->selection.empty()) {
1466         context->selection = COMPAT_QUERY_FILTER + " AND " + context->selection;
1467     } else {
1468         context->selection = COMPAT_QUERY_FILTER;
1469     }
1470 }
1471 #endif
1472 
GetResultDataExecute(napi_env env,void * data)1473 static void GetResultDataExecute(napi_env env, void *data)
1474 {
1475     MediaLibraryTracer tracer;
1476     tracer.Start("GetResultDataExecute");
1477 
1478     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1479 
1480 #ifdef MEDIALIBRARY_COMPATIBILITY
1481     UpdateCompatSelection(context);
1482 #else
1483     MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
1484 #endif
1485     context->predicates.SetWhereClause(context->selection);
1486     context->predicates.SetWhereArgs(context->selectionArgs);
1487     if (!context->order.empty()) {
1488         context->predicates.SetOrder(context->order);
1489     }
1490 
1491 #ifdef MEDIALIBRARY_COMPATIBILITY
1492     vector<string> columns;
1493     const set<string> &defaultFetchCols = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
1494     columns.assign(defaultFetchCols.begin(), defaultFetchCols.end());
1495     columns.push_back(PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
1496 #else
1497     vector<string> columns;
1498 #endif
1499     string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1500     if (!context->networkId.empty()) {
1501         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
1502             MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1503         NAPI_DEBUG_LOG("queryAlbumUri is = %{private}s", queryUri.c_str());
1504     }
1505     Uri uri(queryUri);
1506     int errCode = 0;
1507     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode);
1508 
1509     if (resultSet == nullptr) {
1510         NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr, errCode is %{public}d", errCode);
1511         context->SaveError(errCode);
1512         return;
1513     }
1514 
1515     GetAlbumResult(context, resultSet);
1516 }
1517 
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1518 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1519     unique_ptr<JSAsyncContextOutput> &jsContext)
1520 {
1521     if (context->albumNativeArray.empty()) {
1522         napi_value albumNoArray = nullptr;
1523         napi_create_array(env, &albumNoArray);
1524         jsContext->status = true;
1525         napi_get_undefined(env, &jsContext->error);
1526         jsContext->data = albumNoArray;
1527     } else {
1528         napi_value albumArray = nullptr;
1529         napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
1530         for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
1531             napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
1532             napi_set_element(env, albumArray, i, albumNapiObj);
1533         }
1534         jsContext->status = true;
1535         napi_get_undefined(env, &jsContext->error);
1536         jsContext->data = albumArray;
1537     }
1538 }
1539 
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1540 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1541     unique_ptr<JSAsyncContextOutput> &jsContext)
1542 {
1543     if (context->fetchAlbumResult->GetCount() < 0) {
1544         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1545             "find no data by options");
1546     } else {
1547         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
1548         if (fileResult == nullptr) {
1549             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1550                 "Failed to create js object for Fetch Album Result");
1551         } else {
1552             jsContext->data = fileResult;
1553             jsContext->status = true;
1554             napi_get_undefined(env, &jsContext->error);
1555         }
1556     }
1557 }
1558 
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1559 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1560     unique_ptr<JSAsyncContextOutput> &jsContext)
1561 {
1562     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1563         MediaLibAlbumsAsyncResult(env, context, jsContext);
1564     } else {
1565         UserFileMgrAlbumsAsyncResult(env, context, jsContext);
1566     }
1567 }
1568 
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1569 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1570 {
1571     MediaLibraryTracer tracer;
1572     tracer.Start("AlbumsAsyncCallbackComplete");
1573 
1574     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1575     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1576     jsContext->status = false;
1577     napi_get_undefined(env, &jsContext->error);
1578     if (context->error != ERR_DEFAULT) {
1579         napi_get_undefined(env, &jsContext->data);
1580         context->HandleError(env, jsContext->error);
1581     } else {
1582         AlbumsAsyncResult(env, context, jsContext);
1583     }
1584 
1585     tracer.Finish();
1586     if (context->work != nullptr) {
1587         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1588                                                    context->work, *jsContext);
1589     }
1590     delete context;
1591 }
1592 
JSGetAlbums(napi_env env,napi_callback_info info)1593 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
1594 {
1595     napi_status status;
1596     napi_value result = nullptr;
1597     size_t argc = ARGS_TWO;
1598     napi_value argv[ARGS_TWO] = {0};
1599     napi_value thisVar = nullptr;
1600 
1601     MediaLibraryTracer tracer;
1602     tracer.Start("JSGetAlbums");
1603 
1604     GET_JS_ARGS(env, info, argc, argv, thisVar);
1605     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1606     napi_get_undefined(env, &result);
1607 
1608     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1609     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1610     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1611         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1612         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1613 
1614         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
1615             AlbumsAsyncCallbackComplete);
1616     }
1617 
1618     return result;
1619 }
1620 
1621 #ifndef MEDIALIBRARY_COMPATIBILITY
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1622 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1623 {
1624     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1625     vector<string> columns;
1626     DataShare::DataSharePredicates predicates;
1627 
1628     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1629     predicates.SetWhereArgs({ to_string(id) });
1630 
1631     string queryUri = MEDIALIBRARY_DATA_URI;
1632     Uri uri(queryUri);
1633     int errCode = 0;
1634 
1635     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
1636     CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
1637 
1638     // Create FetchResult object using the contents of resultSet
1639     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1640     CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1641     context->fetchFileResult->SetNetworkId(networkId);
1642     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1643         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1644         context->fetchFileResult->SetResultNapiType(context->resultNapiType);
1645     }
1646     if (context->fetchFileResult->GetCount() < 1) {
1647         NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1648         return;
1649     }
1650     unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1651     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1652     context->fileAsset = move(fileAsset);
1653 }
1654 #endif
1655 
1656 #ifdef MEDIALIBRARY_COMPATIBILITY
SetFileAssetByIdV9(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1657 static void SetFileAssetByIdV9(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1658 {
1659     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1660     bool isValid = false;
1661     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1662     if (!isValid) {
1663         NAPI_ERR_LOG("get title is invalid");
1664         return;
1665     }
1666     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1667     if (!isValid) {
1668         NAPI_ERR_LOG("get relativePath is invalid");
1669         return;
1670     }
1671     unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1672     fileAsset->SetId(id);
1673     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1674     string uri;
1675     if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
1676         MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1677         uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(MediaType::MEDIA_TYPE_FILE,
1678             to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1679         relativePath = MediaFileUtils::RemoveDocsFromRelativePath(relativePath);
1680     } else {
1681         uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(mediaType,
1682             to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1683     }
1684     fileAsset->SetUri(uri);
1685     fileAsset->SetMediaType(mediaType);
1686     fileAsset->SetDisplayName(displayName);
1687     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1688     fileAsset->SetResultNapiType(ResultNapiType::TYPE_MEDIALIBRARY);
1689     fileAsset->SetRelativePath(relativePath);
1690     context->fileAsset = move(fileAsset);
1691 }
1692 #endif
1693 
SetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1694 static void SetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1695                                 MediaLibraryAsyncContext *context)
1696 {
1697     bool isValid = false;
1698     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1699     if (!isValid) {
1700         NAPI_ERR_LOG("getting title is invalid");
1701         return;
1702     }
1703     unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1704     fileAsset->SetId(id);
1705     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1706     fileAsset->SetUri(uri);
1707     fileAsset->SetMediaType(mediaType);
1708     fileAsset->SetDisplayName(displayName);
1709     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1710     fileAsset->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1711     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1712     context->fileAsset = move(fileAsset);
1713 }
1714 
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1715 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1716                                            MediaLibraryAsyncContext *context)
1717 {
1718     bool isValid = false;
1719     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1720     if (!isValid) {
1721         NAPI_ERR_LOG("getting title is invalid");
1722         return;
1723     }
1724     auto fileAsset = make_unique<FileAsset>();
1725     fileAsset->SetId(id);
1726     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1727     fileAsset->SetUri(uri);
1728     fileAsset->SetMediaType(mediaType);
1729     fileAsset->SetDisplayName(displayName);
1730     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1731     fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1732     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1733     context->fileAsset = move(fileAsset);
1734 }
1735 
JSCreateUriArrayInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1736 static void JSCreateUriArrayInCallback(napi_env env, MediaLibraryAsyncContext *context,
1737     unique_ptr<JSAsyncContextOutput> &jsContext)
1738 {
1739     napi_value jsObject = nullptr;
1740     if (context->uriArray.empty()) {
1741         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1742             "Obtain file asset uri array failed");
1743         napi_get_undefined(env, &jsContext->data);
1744     } else {
1745         napi_status status = napi_create_array(env, &jsObject);
1746         int count = 0;
1747         for (const auto &uri : context->uriArray) {
1748             napi_value uriObject = nullptr;
1749             status = napi_create_string_utf8(env, uri.c_str(), NAPI_AUTO_LENGTH, &uriObject);
1750             if (status != napi_ok || uriObject == nullptr) {
1751                 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1752                 napi_get_undefined(env, &jsContext->data);
1753                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1754                     "System inner fail");
1755                 return;
1756             }
1757 
1758             status = napi_set_element(env, jsObject, count, uriObject);
1759             if (status != napi_ok) {
1760                 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1761                 napi_get_undefined(env, &jsContext->data);
1762                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1763                     "System inner fail");
1764                 return;
1765             }
1766             ++count;
1767         }
1768 
1769         if (status != napi_ok || jsObject == nullptr) {
1770             NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1771             napi_get_undefined(env, &jsContext->data);
1772             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1773                 "System inner fail");
1774         } else {
1775             jsContext->data = jsObject;
1776             napi_get_undefined(env, &jsContext->error);
1777             jsContext->status = true;
1778         }
1779     }
1780 }
1781 
JSCreateUriInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1782 static void JSCreateUriInCallback(napi_env env, MediaLibraryAsyncContext *context,
1783     unique_ptr<JSAsyncContextOutput> &jsContext)
1784 {
1785     napi_value jsObject = nullptr;
1786     if (context->uri.empty()) {
1787         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1788             "Obtain file asset uri failed");
1789         napi_get_undefined(env, &jsContext->data);
1790     } else {
1791         napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1792         if (status != napi_ok || jsObject == nullptr) {
1793             NAPI_ERR_LOG("Failed to get file asset uri napi object");
1794             napi_get_undefined(env, &jsContext->data);
1795             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1796                 "System inner fail");
1797         } else {
1798             jsContext->data = jsObject;
1799             napi_get_undefined(env, &jsContext->error);
1800             jsContext->status = true;
1801         }
1802     }
1803 }
1804 
JSCreateAssetInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1805 static void JSCreateAssetInCallback(napi_env env, MediaLibraryAsyncContext *context,
1806     unique_ptr<JSAsyncContextOutput> &jsContext)
1807 {
1808     napi_value jsFileAsset = nullptr;
1809     if (context->fileAsset == nullptr) {
1810         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1811             "Obtain file asset failed");
1812         napi_get_undefined(env, &jsContext->data);
1813     } else {
1814         jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1815         if (jsFileAsset == nullptr) {
1816             NAPI_ERR_LOG("Failed to get file asset napi object");
1817             napi_get_undefined(env, &jsContext->data);
1818             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1819                 "System inner fail");
1820         } else {
1821             NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1822             jsContext->data = jsFileAsset;
1823             napi_get_undefined(env, &jsContext->error);
1824             jsContext->status = true;
1825         }
1826     }
1827 }
1828 
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1829 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1830 {
1831     MediaLibraryTracer tracer;
1832     tracer.Start("JSCreateAssetCompleteCallback");
1833 
1834     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
1835     auto jsContext = make_unique<JSAsyncContextOutput>();
1836     jsContext->status = false;
1837 
1838     if (context->error == ERR_DEFAULT) {
1839         if (context->isCreateByAgent) {
1840             JSCreateUriArrayInCallback(env, context, jsContext);
1841         } else if (context->isCreateByComponent) {
1842             JSCreateUriInCallback(env, context, jsContext);
1843         } else {
1844             JSCreateAssetInCallback(env, context, jsContext);
1845         }
1846     } else {
1847         context->HandleError(env, jsContext->error);
1848         napi_get_undefined(env, &jsContext->data);
1849     }
1850 
1851     tracer.Finish();
1852     if (context->work != nullptr) {
1853         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1854                                                    context->work, *jsContext);
1855     }
1856     delete context;
1857 }
1858 
JSPhotoUriPermissionCallback(napi_env env,napi_status status,void * data)1859 static void JSPhotoUriPermissionCallback(napi_env env, napi_status status, void *data)
1860 {
1861     MediaLibraryTracer tracer;
1862     tracer.Start("JSPhotoUriPermissionCallback");
1863 
1864     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1865     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1866 
1867     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1868     jsContext->status = false;
1869 
1870     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1871     if (context->error != ERR_DEFAULT) {
1872         context->HandleError(env, jsContext->error);
1873         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1874     } else {
1875         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
1876         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1877         jsContext->status = true;
1878     }
1879 
1880     tracer.Finish();
1881     if (context->work != nullptr) {
1882         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1883                                                    context->work, *jsContext);
1884     }
1885     delete context;
1886 }
1887 
CheckDisplayNameParams(MediaLibraryAsyncContext * context)1888 static bool CheckDisplayNameParams(MediaLibraryAsyncContext *context)
1889 {
1890     if (context == nullptr) {
1891         NAPI_ERR_LOG("Async context is null");
1892         return false;
1893     }
1894     if (!context->isCreateByComponent) {
1895         bool isValid = false;
1896         string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1897         if (!isValid) {
1898             NAPI_ERR_LOG("getting displayName is invalid");
1899             return false;
1900         }
1901         if (displayName.empty()) {
1902             return false;
1903         }
1904     }
1905 
1906     return true;
1907 }
1908 
GetFirstDirName(const string & relativePath)1909 static string GetFirstDirName(const string &relativePath)
1910 {
1911     string firstDirName = "";
1912     if (!relativePath.empty()) {
1913         string::size_type pos = relativePath.find_first_of('/');
1914         if (pos == relativePath.length()) {
1915             return relativePath;
1916         }
1917         firstDirName = relativePath.substr(0, pos + 1);
1918         NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
1919     }
1920     return firstDirName;
1921 }
1922 
IsDirectory(const string & dirName)1923 static bool IsDirectory(const string &dirName)
1924 {
1925     struct stat statInfo {};
1926     if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == E_SUCCESS) {
1927         if (statInfo.st_mode & S_IFDIR) {
1928             return true;
1929         }
1930     }
1931 
1932     return false;
1933 }
1934 
CheckTypeOfType(const string & firstDirName,int32_t fileMediaType)1935 static bool CheckTypeOfType(const string &firstDirName, int32_t fileMediaType)
1936 {
1937     // "CDSA/"
1938     if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
1939         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1940             return true;
1941         } else {
1942             return false;
1943         }
1944     }
1945     // "Movies/"
1946     if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
1947         if (fileMediaType == MEDIA_TYPE_VIDEO) {
1948             return true;
1949         } else {
1950             return false;
1951         }
1952     }
1953     if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_2].c_str())) {
1954         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
1955             return true;
1956         } else {
1957             NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
1958             return false;
1959         }
1960     }
1961     if (!strcmp(firstDirName.c_str(), directoryEnumValues[NUM_3].c_str())) {
1962         if (fileMediaType == MEDIA_TYPE_AUDIO) {
1963             return true;
1964         } else {
1965             return false;
1966         }
1967     }
1968     return true;
1969 }
CheckRelativePathParams(MediaLibraryAsyncContext * context)1970 static bool CheckRelativePathParams(MediaLibraryAsyncContext *context)
1971 {
1972     if (context == nullptr) {
1973         NAPI_ERR_LOG("Async context is null");
1974         return false;
1975     }
1976     bool isValid = false;
1977     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1978     if (!isValid) {
1979         NAPI_DEBUG_LOG("getting relativePath is invalid");
1980         return false;
1981     }
1982     isValid = false;
1983     int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
1984     if (!isValid) {
1985         NAPI_DEBUG_LOG("getting fileMediaType is invalid");
1986         return false;
1987     }
1988     if (relativePath.empty()) {
1989         return false;
1990     }
1991 
1992     if (IsDirectory(relativePath)) {
1993         return true;
1994     }
1995 
1996     string firstDirName = GetFirstDirName(relativePath);
1997     if (!firstDirName.empty() && IsDirectory(firstDirName)) {
1998         return true;
1999     }
2000 
2001     if (!firstDirName.empty()) {
2002         NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
2003         for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
2004             NAPI_DEBUG_LOG("directoryEnumValues%{private}d = %{private}s", i, directoryEnumValues[i].c_str());
2005             if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
2006                 return CheckTypeOfType(firstDirName, fileMediaType);
2007             }
2008             if (!strcmp(firstDirName.c_str(), DOCS_PATH.c_str())) {
2009                 return true;
2010             }
2011         }
2012         NAPI_ERR_LOG("Failed to check relative path, firstDirName = %{private}s", firstDirName.c_str());
2013     }
2014     return false;
2015 }
2016 
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2017 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
2018                                    MediaLibraryAsyncContext &asyncContext)
2019 {
2020     const int32_t refCount = 1;
2021     napi_value result = nullptr;
2022     auto context = &asyncContext;
2023     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2024     int32_t fileMediaType = 0;
2025     size_t res = 0;
2026     char relativePathBuffer[PATH_MAX];
2027     char titleBuffer[PATH_MAX];
2028     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2029 
2030     for (size_t i = PARAM0; i < argc; i++) {
2031         napi_valuetype valueType = napi_undefined;
2032         napi_typeof(env, argv[i], &valueType);
2033         if (i == PARAM0 && valueType == napi_number) {
2034             napi_get_value_int32(env, argv[i], &fileMediaType);
2035         } else if (i == PARAM1 && valueType == napi_string) {
2036             napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
2037             NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
2038         } else if (i == PARAM2 && valueType == napi_string) {
2039             napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
2040             NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
2041         } else if (i == PARAM3 && valueType == napi_function) {
2042             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2043         } else {
2044             NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
2045             return result;
2046     }
2047     }
2048 
2049     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
2050     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
2051     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
2052 
2053     context->assetType = TYPE_DEFAULT;
2054     if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
2055         context->assetType = TYPE_PHOTO;
2056     } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
2057         context->assetType = TYPE_AUDIO;
2058     }
2059 
2060     NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
2061     // Return true napi_value if params are successfully obtained
2062     napi_get_boolean(env, true, &result);
2063     return result;
2064 }
2065 
GetCreateUri(MediaLibraryAsyncContext * context,string & uri)2066 static void GetCreateUri(MediaLibraryAsyncContext *context, string &uri)
2067 {
2068     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
2069         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
2070         switch (context->assetType) {
2071             case TYPE_PHOTO:
2072                 uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
2073                     ((context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO) :
2074                     ((context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT : PAH_CREATE_PHOTO);
2075                 break;
2076             case TYPE_AUDIO:
2077                 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
2078                 break;
2079             default:
2080                 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
2081                 return;
2082         }
2083         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2084     } else {
2085 #ifdef MEDIALIBRARY_COMPATIBILITY
2086         bool isValid = false;
2087         string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2088         if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
2089             MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
2090             uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2091             MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
2092             return;
2093         }
2094         switch (context->assetType) {
2095             case TYPE_PHOTO:
2096                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2097                 break;
2098             case TYPE_AUDIO:
2099                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2100                 break;
2101             case TYPE_DEFAULT:
2102                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2103                 break;
2104             default:
2105                 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
2106                 return;
2107         }
2108         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
2109 #else
2110         uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2111 #endif
2112     }
2113 }
2114 
JSCreateAssetExecute(napi_env env,void * data)2115 static void JSCreateAssetExecute(napi_env env, void *data)
2116 {
2117     MediaLibraryTracer tracer;
2118     tracer.Start("JSCreateAssetExecute");
2119 
2120     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2121     if (!CheckDisplayNameParams(context)) {
2122         context->error = JS_E_DISPLAYNAME;
2123         return;
2124     }
2125     if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathParams(context))) {
2126         context->error = JS_E_RELATIVEPATH;
2127         return;
2128     }
2129     bool isValid = false;
2130     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2131     if (isValid) {
2132         if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
2133             MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
2134             context->valuesBucket.valuesMap.erase(MEDIA_DATA_DB_RELATIVE_PATH);
2135             context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, DOCS_PATH + relativePath);
2136         }
2137     }
2138 
2139     string uri;
2140     GetCreateUri(context, uri);
2141     Uri createFileUri(uri);
2142     string outUri;
2143     int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
2144     if (index < 0) {
2145         context->SaveError(index);
2146     } else {
2147         if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2148             if (context->isCreateByComponent) {
2149                 context->uri = outUri;
2150             } else {
2151                 SetFileAssetByIdV10(index, "", outUri, context);
2152             }
2153         } else {
2154 #ifdef MEDIALIBRARY_COMPATIBILITY
2155             SetFileAssetByIdV9(index, "", context);
2156 #else
2157             getFileAssetById(index, "", context);
2158 #endif
2159             LogMedialibraryAPI(context->fileAsset->GetUri());
2160         }
2161     }
2162 }
2163 
JSCreateAsset(napi_env env,napi_callback_info info)2164 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
2165 {
2166     napi_status status;
2167     napi_value result = nullptr;
2168     size_t argc = ARGS_FOUR;
2169     napi_value argv[ARGS_FOUR] = {0};
2170     napi_value thisVar = nullptr;
2171 
2172     MediaLibraryTracer tracer;
2173     tracer.Start("JSCreateAsset");
2174 
2175     GET_JS_ARGS(env, info, argc, argv, thisVar);
2176     NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
2177     napi_get_undefined(env, &result);
2178 
2179     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2180     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2181     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2182     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2183         result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
2184         ASSERT_NULLPTR_CHECK(env, result);
2185 
2186         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
2187             JSCreateAssetCompleteCallback);
2188     }
2189 
2190     return result;
2191 }
2192 
2193 #ifdef MEDIALIBRARY_COMPATIBILITY
HandleCompatTrashAudio(MediaLibraryAsyncContext * context,const string & deleteId)2194 static void HandleCompatTrashAudio(MediaLibraryAsyncContext *context, const string &deleteId)
2195 {
2196     DataShareValuesBucket valuesBucket;
2197     valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
2198     DataSharePredicates predicates;
2199     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2200     predicates.SetWhereArgs({ deleteId });
2201     Uri uri(URI_DELETE_AUDIO);
2202     int32_t changedRows = UserFileClient::Delete(uri, predicates);
2203     if (changedRows < 0) {
2204         context->SaveError(changedRows);
2205         return;
2206     }
2207     context->retVal = changedRows;
2208 }
2209 
HandleCompatDeletePhoto(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2210 static void HandleCompatDeletePhoto(MediaLibraryAsyncContext *context,
2211     const string &mediaType, const string &deleteId)
2212 {
2213     Uri uri(URI_COMPAT_DELETE_PHOTOS);
2214     DataSharePredicates predicates;
2215     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ deleteId }));
2216     DataShareValuesBucket valuesBucket;
2217     valuesBucket.Put(MediaColumn::MEDIA_ID, deleteId);
2218     int changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2219     if (changedRows < 0) {
2220         context->SaveError(changedRows);
2221         return;
2222     }
2223     context->retVal = changedRows;
2224 }
2225 
HandleCompatDelete(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2226 static inline void HandleCompatDelete(MediaLibraryAsyncContext *context,
2227     const string &mediaType, const string &deleteId)
2228 {
2229     if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE) {
2230         return HandleCompatDeletePhoto(context, mediaType, deleteId);
2231     }
2232     if (mediaType == AUDIO_ASSET_TYPE) {
2233         return HandleCompatTrashAudio(context, deleteId);
2234     }
2235 
2236     NAPI_WARN_LOG("Ignore unsupported media type deletion: %{private}s", mediaType.c_str());
2237 }
2238 #endif
2239 
JSDeleteAssetExecute(napi_env env,void * data)2240 static void JSDeleteAssetExecute(napi_env env, void *data)
2241 {
2242     MediaLibraryTracer tracer;
2243     tracer.Start("JSDeleteAssetExecute");
2244 
2245     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2246     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2247 
2248     string mediaType;
2249     string deleteId;
2250     bool isValid = false;
2251     string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2252     if (!isValid) {
2253         context->error = ERR_INVALID_OUTPUT;
2254         return;
2255     }
2256 #ifdef MEDIALIBRARY_COMPATIBILITY
2257     notifyUri = MediaFileUtils::GetRealUriFromVirtualUri(notifyUri);
2258 #endif
2259     size_t index = notifyUri.rfind('/');
2260     if (index != string::npos) {
2261         deleteId = notifyUri.substr(index + 1);
2262         notifyUri = notifyUri.substr(0, index);
2263         size_t indexType = notifyUri.rfind('/');
2264         if (indexType != string::npos) {
2265             mediaType = notifyUri.substr(indexType + 1);
2266         }
2267     }
2268     if (MediaFileUtils::IsUriV10(mediaType)) {
2269         NAPI_ERR_LOG("Unsupported media type: %{private}s", mediaType.c_str());
2270         context->SaveError(E_INVALID_URI);
2271         return;
2272     }
2273 #ifdef MEDIALIBRARY_COMPATIBILITY
2274     if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE || mediaType == AUDIO_ASSET_TYPE) {
2275         return HandleCompatDelete(context, mediaType, deleteId);
2276     }
2277 #endif
2278     notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
2279     string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET;
2280     Uri deleteAssetUri(deleteUri);
2281     DataSharePredicates predicates;
2282     predicates.EqualTo(MEDIA_DATA_DB_ID, deleteId);
2283     int retVal = UserFileClient::Delete(deleteAssetUri, predicates);
2284     if (retVal < 0) {
2285         context->SaveError(retVal);
2286     } else {
2287         context->retVal = retVal;
2288         Uri deleteNotify(notifyUri);
2289         UserFileClient::NotifyChange(deleteNotify);
2290     }
2291 }
2292 
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)2293 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
2294 {
2295     MediaLibraryTracer tracer;
2296     tracer.Start("JSDeleteAssetCompleteCallback");
2297 
2298     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2299     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2300     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2301     jsContext->status = false;
2302 
2303     if (context->error == ERR_DEFAULT) {
2304         NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
2305         napi_create_int32(env, context->retVal, &jsContext->data);
2306         napi_get_undefined(env, &jsContext->error);
2307         jsContext->status = true;
2308     } else {
2309         context->HandleError(env, jsContext->error);
2310         napi_get_undefined(env, &jsContext->data);
2311     }
2312 
2313     tracer.Finish();
2314     if (context->work != nullptr) {
2315         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2316                                                    context->work, *jsContext);
2317     }
2318 
2319     delete context;
2320 }
2321 
JSTrashAssetExecute(napi_env env,void * data)2322 static void JSTrashAssetExecute(napi_env env, void *data)
2323 {
2324     MediaLibraryTracer tracer;
2325     tracer.Start("JSTrashAssetExecute");
2326 
2327     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2328     string uri = context->uri;
2329     if (uri.empty()) {
2330         context->error = ERR_INVALID_OUTPUT;
2331         return;
2332     }
2333     MediaFileUri::RemoveAllFragment(uri);
2334     string trashId = MediaFileUtils::GetIdFromUri(uri);
2335     string trashUri;
2336     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
2337         trashUri = UFM_UPDATE_PHOTO;
2338     } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
2339         trashUri = UFM_UPDATE_AUDIO;
2340     } else {
2341         context->error = E_VIOLATION_PARAMETERS;
2342         return;
2343     }
2344     MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2345     Uri updateAssetUri(trashUri);
2346     DataSharePredicates predicates;
2347     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2348     predicates.SetWhereArgs({ trashId });
2349     DataShareValuesBucket valuesBucket;
2350     valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
2351     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2352     if (changedRows < 0) {
2353         context->SaveError(changedRows);
2354         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
2355     }
2356 }
2357 
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)2358 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
2359 {
2360     MediaLibraryTracer tracer;
2361     tracer.Start("JSTrashAssetCompleteCallback");
2362 
2363     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2364     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2365     jsContext->status = false;
2366     napi_get_undefined(env, &jsContext->data);
2367     if (context->error == ERR_DEFAULT) {
2368         jsContext->status = true;
2369     } else {
2370         context->HandleError(env, jsContext->error);
2371     }
2372     if (context->work != nullptr) {
2373         tracer.Finish();
2374         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2375             context->work, *jsContext);
2376     }
2377 
2378     delete context;
2379 }
2380 
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2381 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
2382                                    MediaLibraryAsyncContext &asyncContext)
2383 {
2384     const int32_t refCount = 1;
2385     napi_value result = nullptr;
2386     auto context = &asyncContext;
2387     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2388     size_t res = 0;
2389     char buffer[PATH_MAX];
2390 
2391     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2392 
2393     for (size_t i = PARAM0; i < argc; i++) {
2394         napi_valuetype valueType = napi_undefined;
2395         napi_typeof(env, argv[i], &valueType);
2396 
2397         if (i == PARAM0 && valueType == napi_string) {
2398             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2399         } else if (i == PARAM1 && valueType == napi_function) {
2400             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2401             break;
2402         } else {
2403             NAPI_ASSERT(env, false, "type mismatch");
2404         }
2405     }
2406 
2407     context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
2408 
2409     // Return true napi_value if params are successfully obtained
2410     napi_get_boolean(env, true, &result);
2411     return result;
2412 }
2413 
JSDeleteAsset(napi_env env,napi_callback_info info)2414 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
2415 {
2416     napi_status status;
2417     napi_value result = nullptr;
2418     size_t argc = ARGS_TWO;
2419     napi_value argv[ARGS_TWO] = {0};
2420     napi_value thisVar = nullptr;
2421 
2422     MediaLibraryTracer tracer;
2423     tracer.Start("JSDeleteAsset");
2424 
2425     GET_JS_ARGS(env, info, argc, argv, thisVar);
2426     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2427     napi_get_undefined(env, &result);
2428 
2429     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2430     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2431     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2432         result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
2433         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2434 
2435         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
2436             JSDeleteAssetCompleteCallback);
2437     }
2438 
2439     return result;
2440 }
2441 
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2442 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2443 {
2444     napi_value value;
2445     napi_status status = napi_create_int32(env, intValue, &value);
2446     if (status != napi_ok) {
2447         NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2448         return status;
2449     }
2450     status = napi_set_named_property(env, result, fieldStr, value);
2451     if (status != napi_ok) {
2452         NAPI_ERR_LOG("Set int32 named property error! field: %{public}s", fieldStr);
2453     }
2454     return status;
2455 }
2456 
SetValueArray(const napi_env & env,const char * fieldStr,const std::list<Uri> listValue,napi_value & result)2457 static napi_status SetValueArray(const napi_env& env,
2458     const char* fieldStr, const std::list<Uri> listValue, napi_value& result)
2459 {
2460     napi_value value = nullptr;
2461     napi_status status = napi_create_array_with_length(env, listValue.size(), &value);
2462     if (status != napi_ok) {
2463         NAPI_ERR_LOG("Create array error! field: %{public}s", fieldStr);
2464         return status;
2465     }
2466     int elementIndex = 0;
2467     for (auto uri : listValue) {
2468         napi_value uriRet = nullptr;
2469         napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &uriRet);
2470         status = napi_set_element(env, value, elementIndex++, uriRet);
2471         if (status != napi_ok) {
2472             NAPI_ERR_LOG("Set lite item failed, error: %d", status);
2473         }
2474     }
2475     status = napi_set_named_property(env, result, fieldStr, value);
2476     if (status != napi_ok) {
2477         NAPI_ERR_LOG("Set array named property error! field: %{public}s", fieldStr);
2478     }
2479 
2480     return status;
2481 }
2482 
GetFileIdFromUri(const string & uri)2483 static string GetFileIdFromUri(const string& uri)
2484 {
2485     auto startIndex = uri.find(PhotoColumn::PHOTO_URI_PREFIX);
2486     if (startIndex == std::string::npos) {
2487         return "";
2488     }
2489     auto endIndex = uri.find("/", startIndex + PhotoColumn::PHOTO_URI_PREFIX.length());
2490     if (endIndex == std::string::npos) {
2491         return uri.substr(startIndex + PhotoColumn::PHOTO_URI_PREFIX.length());
2492     }
2493     return uri.substr(startIndex + PhotoColumn::PHOTO_URI_PREFIX.length(),
2494         endIndex - startIndex - PhotoColumn::PHOTO_URI_PREFIX.length());
2495 }
2496 
GetAlbumIdFromUri(const string & uri)2497 static string GetAlbumIdFromUri(const string& uri)
2498 {
2499     string albumId = "";
2500     auto startIndex = uri.find(PhotoAlbumColumns::ALBUM_URI_PREFIX);
2501     if (startIndex != std::string::npos) {
2502         albumId = uri.substr(startIndex + PhotoAlbumColumns::ALBUM_URI_PREFIX.length());
2503     }
2504     return albumId;
2505 }
2506 
GetSharedPhotoAssets(const napi_env & env,vector<string> & fileIds)2507 static napi_value GetSharedPhotoAssets(const napi_env& env, vector<string>& fileIds)
2508 {
2509     string queryUri = PAH_QUERY_PHOTO;
2510     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2511     Uri photoUri(queryUri);
2512     DataShare::DataSharePredicates predicates;
2513     predicates.In(MediaColumn::MEDIA_ID, fileIds);
2514     std::vector<std::string> columns = PHOTO_COLUMN;
2515     std::shared_ptr<NativeRdb::AbsSharedResultSet> result = UserFileClient::QueryRdb(photoUri, predicates, columns);
2516     napi_value value = nullptr;
2517     napi_status status = napi_create_array_with_length(env, fileIds.size(), &value);
2518     if (status != napi_ok) {
2519         NAPI_ERR_LOG("Create array error!");
2520         return value;
2521     }
2522     if (result == nullptr) {
2523         return value;
2524     }
2525     int elementIndex = 0;
2526     int err = result->GoToFirstRow();
2527     if (err != napi_ok) {
2528         NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
2529         return value;
2530     }
2531     do {
2532         napi_value assetValue = MediaLibraryNapiUtils::GetNextRowObject(env, result, true);
2533         if (assetValue == nullptr) {
2534             return nullptr;
2535         }
2536         status = napi_set_element(env, value, elementIndex++, assetValue);
2537         if (status != napi_ok) {
2538             NAPI_ERR_LOG("Set photo asset Value failed");
2539             return nullptr;
2540         }
2541     } while (result->GoToNextRow() == E_OK);
2542     result->Close();
2543     return value;
2544 }
2545 
GetSharedAlbumAssets(const napi_env & env,vector<string> & albumIds)2546 static napi_value GetSharedAlbumAssets(const napi_env& env, vector<string>& albumIds)
2547 {
2548     string queryUri = PAH_QUERY_PHOTO_ALBUM;
2549     Uri albumUri(queryUri);
2550     DataShare::DataSharePredicates predicates;
2551     predicates.In(PhotoAlbumColumns::ALBUM_ID, albumIds);
2552     std::vector<std::string> columns = ALBUM_COLUMN;
2553     std::shared_ptr<NativeRdb::AbsSharedResultSet> result = UserFileClient::QueryRdb(albumUri, predicates, columns);
2554     napi_value value = nullptr;
2555     napi_status status = napi_create_array_with_length(env, albumIds.size(), &value);
2556     if (status != napi_ok) {
2557         NAPI_ERR_LOG("Create array error!");
2558         return value;
2559     }
2560     if (result == nullptr) {
2561         return value;
2562     }
2563     int err = result->GoToFirstRow();
2564     if (err != napi_ok) {
2565         NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
2566         return value;
2567     }
2568     int elementIndex = 0;
2569     do {
2570         napi_value assetValue = MediaLibraryNapiUtils::GetNextRowAlbumObject(env, result);
2571         if (assetValue == nullptr) {
2572             return nullptr;
2573         }
2574         status = napi_set_element(env, value, elementIndex++, assetValue);
2575         if (status != napi_ok) {
2576             NAPI_ERR_LOG("Set albumn asset Value failed");
2577             return nullptr;
2578         }
2579     } while (result->GoToNextRow() == E_OK);
2580     result->Close();
2581     return value;
2582 }
2583 
SetSharedAssetArray(const napi_env & env,const char * fieldStr,const std::list<Uri> & listValue,napi_value & result,bool isPhoto)2584 static napi_status SetSharedAssetArray(const napi_env& env, const char* fieldStr,
2585     const std::list<Uri>& listValue, napi_value& result, bool isPhoto)
2586 {
2587     std::vector<std::string> assetIds;
2588     napi_status status = napi_ok;
2589     if (listValue.size() > MAX_QUERY_LIMIT) {
2590         return status;
2591     }
2592     for (auto& uri : listValue) {
2593         string assetId = isPhoto ? GetFileIdFromUri(uri.ToString()) : GetAlbumIdFromUri(uri.ToString());
2594         if (assetId == "") {
2595             NAPI_ERR_LOG("Failed to read assetId");
2596             status = napi_invalid_arg;
2597             return status;
2598         }
2599         assetIds.push_back(assetId);
2600     }
2601     napi_value assetResults = isPhoto ? GetSharedPhotoAssets(env, assetIds) :
2602         GetSharedAlbumAssets(env, assetIds);
2603     if (assetResults == nullptr) {
2604         NAPI_ERR_LOG("Failed to get assets Result from rdb");
2605         status = napi_invalid_arg;
2606         return status;
2607     }
2608     status = napi_set_named_property(env, result, fieldStr, assetResults);
2609     if (status != napi_ok) {
2610         NAPI_ERR_LOG("set array named property error: %{public}s", fieldStr);
2611     }
2612     return status;
2613 }
2614 
SetSubUris(const napi_env & env,const shared_ptr<MessageParcel> parcel,napi_value & result)2615 static napi_status SetSubUris(const napi_env& env, const shared_ptr<MessageParcel> parcel, napi_value& result)
2616 {
2617     uint32_t len = 0;
2618     napi_status status = napi_invalid_arg;
2619     if (!parcel->ReadUint32(len)) {
2620         NAPI_ERR_LOG("Failed to read sub uri list length");
2621         return status;
2622     }
2623     if (len > MAX_QUERY_LIMIT) {
2624         NAPI_ERR_LOG("suburi length exceed the limit.");
2625         return status;
2626     }
2627     napi_value subUriArray = nullptr;
2628     napi_create_array_with_length(env, len, &subUriArray);
2629     int subElementIndex = 0;
2630     vector<std::string> fileIds;
2631     for (uint32_t i = 0; i < len; i++) {
2632         string subUri = parcel->ReadString();
2633         if (subUri.empty()) {
2634             NAPI_ERR_LOG("Failed to read sub uri");
2635             return status;
2636         }
2637         napi_value subUriRet = nullptr;
2638         napi_create_string_utf8(env, subUri.c_str(), NAPI_AUTO_LENGTH, &subUriRet);
2639         napi_set_element(env, subUriArray, subElementIndex++, subUriRet);
2640         string fileId = GetFileIdFromUri(subUri);
2641         if (fileId == "") {
2642             NAPI_ERR_LOG("Failed to read sub uri fileId");
2643             continue;
2644         }
2645         fileIds.push_back(fileId);
2646     }
2647     status = napi_set_named_property(env, result, "extraUris", subUriArray);
2648     if (status != napi_ok) {
2649         NAPI_ERR_LOG("Set subUri named property error!");
2650     }
2651     napi_value photoAssetArray = GetSharedPhotoAssets(env, fileIds);
2652     if (photoAssetArray == nullptr) {
2653         NAPI_ERR_LOG("Failed to get sharedPhotoAsset");
2654     }
2655     status = napi_set_named_property(env, result, "sharedExtraPhotoAssets", photoAssetArray);
2656     if (status != napi_ok) {
2657         NAPI_ERR_LOG("Set extraAssets named property error!");
2658     }
2659     return status;
2660 }
2661 
GetTrashAlbumUri()2662 string ChangeListenerNapi::GetTrashAlbumUri()
2663 {
2664     if (!trashAlbumUri_.empty()) {
2665         return trashAlbumUri_;
2666     }
2667     string queryUri = UFM_QUERY_PHOTO_ALBUM;
2668     Uri uri(queryUri);
2669     int errCode = 0;
2670     DataSharePredicates predicates;
2671     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::TRASH));
2672     vector<string> columns;
2673     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2674     unique_ptr<FetchResult<PhotoAlbum>> albumSet = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
2675     if (albumSet == nullptr) {
2676         return trashAlbumUri_;
2677     }
2678     if (albumSet->GetCount() != 1) {
2679         return trashAlbumUri_;
2680     }
2681     unique_ptr<PhotoAlbum> albumAssetPtr = albumSet->GetFirstObject();
2682     if (albumAssetPtr == nullptr) {
2683         return trashAlbumUri_;
2684     }
2685     return albumSet->GetFirstObject()->GetAlbumUri();
2686 }
2687 
SolveOnChange(napi_env env,UvChangeMsg * msg)2688 napi_value ChangeListenerNapi::SolveOnChange(napi_env env, UvChangeMsg *msg)
2689 {
2690     static napi_value result;
2691     if (msg->changeInfo_.uris_.empty()) {
2692         napi_get_undefined(env, &result);
2693         return result;
2694     }
2695     napi_create_object(env, &result);
2696     SetValueArray(env, "uris", msg->changeInfo_.uris_, result);
2697     if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2698         SetSharedAssetArray(env, "sharedAlbumAssets", msg->changeInfo_.uris_, result, false);
2699     } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2700         SetSharedAssetArray(env, "sharedPhotoAssets", msg->changeInfo_.uris_, result, true);
2701     } else {
2702         NAPI_DEBUG_LOG("other albums notify");
2703     }
2704 
2705     if (msg->changeInfo_.uris_.size() == DEFAULT_ALBUM_COUNT) {
2706         if (msg->changeInfo_.uris_.front().ToString().compare(GetTrashAlbumUri()) == 0) {
2707             if (!MediaLibraryNapiUtils::IsSystemApp()) {
2708                 napi_get_undefined(env, &result);
2709                 return nullptr;
2710             }
2711         }
2712     }
2713     if (msg->data_ != nullptr && msg->changeInfo_.size_ > 0) {
2714         if ((int)msg->changeInfo_.changeType_ == ChangeType::INSERT) {
2715             SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_ADD_ASSET, result);
2716         } else {
2717             SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, result);
2718         }
2719         shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
2720         if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(msg->data_), msg->changeInfo_.size_)) {
2721             napi_status status = SetSubUris(env, parcel, result);
2722             if (status != napi_ok) {
2723                 NAPI_ERR_LOG("Set subArray named property error! field: subUris");
2724                 return nullptr;
2725             }
2726         }
2727     } else {
2728         SetValueInt32(env, "type", (int)msg->changeInfo_.changeType_, result);
2729     }
2730     return result;
2731 }
2732 
OnChange(MediaChangeListener & listener,const napi_ref cbRef)2733 void ChangeListenerNapi::OnChange(MediaChangeListener &listener, const napi_ref cbRef)
2734 {
2735     uv_loop_s *loop = nullptr;
2736     napi_get_uv_event_loop(env_, &loop);
2737     if (loop == nullptr) {
2738         return;
2739     }
2740 
2741     uv_work_t *work = new (nothrow) uv_work_t;
2742     if (work == nullptr) {
2743         return;
2744     }
2745 
2746     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef, listener.changeInfo, listener.strUri);
2747     if (msg == nullptr) {
2748         delete work;
2749         return;
2750     }
2751     if (!listener.changeInfo.uris_.empty()) {
2752         if (listener.changeInfo.changeType_ == DataShare::DataShareObserver::ChangeType::OTHER) {
2753             NAPI_ERR_LOG("changeInfo.changeType_ is other");
2754             delete msg;
2755             delete work;
2756             return;
2757         }
2758         if (msg->changeInfo_.size_ > 0) {
2759             msg->data_ = (uint8_t *)malloc(msg->changeInfo_.size_);
2760             if (msg->data_ == nullptr) {
2761                 NAPI_ERR_LOG("new msg->data failed");
2762                 delete msg;
2763                 delete work;
2764                 return;
2765             }
2766             int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
2767             if (copyRet != 0) {
2768                 NAPI_ERR_LOG("Parcel data copy failed, err = %{public}d", copyRet);
2769             }
2770         }
2771     }
2772     work->data = reinterpret_cast<void *>(msg);
2773 
2774     int ret = UvQueueWork(loop, work);
2775     if (ret != 0) {
2776         NAPI_ERR_LOG("Failed to execute libuv work queue, ret: %{public}d", ret);
2777         free(msg->data_);
2778         delete msg;
2779         delete work;
2780     }
2781 }
2782 
UvQueueWork(uv_loop_s * loop,uv_work_t * work)2783 int ChangeListenerNapi::UvQueueWork(uv_loop_s *loop, uv_work_t *work)
2784 {
2785     return uv_queue_work(loop, work, [](uv_work_t *w) {}, [](uv_work_t *w, int s) {
2786         // js thread
2787         if (w == nullptr) {
2788             return;
2789         }
2790 
2791         UvChangeMsg *msg = reinterpret_cast<UvChangeMsg *>(w->data);
2792         do {
2793             if (msg == nullptr) {
2794                 NAPI_ERR_LOG("UvChangeMsg is null");
2795                 break;
2796             }
2797             napi_env env = msg->env_;
2798             NapiScopeHandler scopeHandler(env);
2799             if (!scopeHandler.IsValid()) {
2800                 break;
2801             }
2802 
2803             napi_value jsCallback = nullptr;
2804             napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
2805             if (status != napi_ok) {
2806                 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2807                 break;
2808             }
2809             napi_value retVal = nullptr;
2810             napi_value result[ARGS_ONE];
2811             result[PARAM0] = ChangeListenerNapi::SolveOnChange(env, msg);
2812             if (result[PARAM0] == nullptr) {
2813                 break;
2814             }
2815             napi_call_function(env, nullptr, jsCallback, ARGS_ONE, result, &retVal);
2816             if (status != napi_ok) {
2817                 NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
2818                 break;
2819             }
2820         } while (0);
2821         delete msg;
2822         delete w;
2823     });
2824 }
2825 
GetListenerType(const string & str) const2826 int32_t MediaLibraryNapi::GetListenerType(const string &str) const
2827 {
2828     auto iter = ListenerTypeMaps.find(str);
2829     if (iter == ListenerTypeMaps.end()) {
2830         NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
2831         return INVALID_LISTENER;
2832     }
2833 
2834     return iter->second;
2835 }
2836 
RegisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)2837 void MediaLibraryNapi::RegisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
2838 {
2839     NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
2840 
2841     int32_t typeEnum = GetListenerType(type);
2842     switch (typeEnum) {
2843         case AUDIO_LISTENER:
2844             listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
2845             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
2846             break;
2847         case VIDEO_LISTENER:
2848             listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
2849             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
2850             break;
2851         case IMAGE_LISTENER:
2852             listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
2853             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
2854             break;
2855         case FILE_LISTENER:
2856             listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
2857             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
2858             break;
2859         case SMARTALBUM_LISTENER:
2860             listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
2861             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
2862                 listObj.smartAlbumDataObserver_);
2863             break;
2864         case DEVICE_LISTENER:
2865             listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
2866             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
2867             break;
2868         case REMOTEFILE_LISTENER:
2869             listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
2870             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
2871             break;
2872         case ALBUM_LISTENER:
2873             listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
2874             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
2875             break;
2876         default:
2877             NAPI_ERR_LOG("Invalid Media Type!");
2878     }
2879 }
2880 
RegisterNotifyChange(napi_env env,const std::string & uri,bool isDerived,napi_ref ref,ChangeListenerNapi & listObj)2881 void MediaLibraryNapi::RegisterNotifyChange(napi_env env,
2882     const std::string &uri, bool isDerived, napi_ref ref, ChangeListenerNapi &listObj)
2883 {
2884     Uri notifyUri(uri);
2885     shared_ptr<MediaOnNotifyObserver> observer= make_shared<MediaOnNotifyObserver>(listObj, uri, ref);
2886     UserFileClient::RegisterObserverExt(notifyUri,
2887         static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), isDerived);
2888     lock_guard<mutex> lock(sOnOffMutex_);
2889     listObj.observers_.push_back(observer);
2890 }
2891 
JSOnCallback(napi_env env,napi_callback_info info)2892 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
2893 {
2894     MediaLibraryTracer tracer;
2895     tracer.Start("JSOnCallback");
2896     napi_value undefinedResult = nullptr;
2897     napi_get_undefined(env, &undefinedResult);
2898     size_t argc = ARGS_TWO;
2899     napi_value argv[ARGS_TWO] = {nullptr};
2900     napi_value thisVar = nullptr;
2901     GET_JS_ARGS(env, info, argc, argv, thisVar);
2902     NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
2903     MediaLibraryNapi *obj = nullptr;
2904     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2905     if (status == napi_ok && obj != nullptr) {
2906         napi_valuetype valueType = napi_undefined;
2907         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
2908             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
2909             return undefinedResult;
2910         }
2911         char buffer[ARG_BUF_SIZE];
2912         size_t res = 0;
2913         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2914             NAPI_ERR_LOG("Failed to get value string utf8 for type");
2915             return undefinedResult;
2916         }
2917         string type = string(buffer);
2918         const int32_t refCount = 1;
2919         napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
2920         tracer.Start("RegisterChange");
2921         obj->RegisterChange(env, type, *g_listObj);
2922         tracer.Finish();
2923     }
2924     return undefinedResult;
2925 }
2926 
CheckRef(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,bool isOff,const string & uri)2927 bool MediaLibraryNapi::CheckRef(napi_env env,
2928     napi_ref ref, ChangeListenerNapi &listObj, bool isOff, const string &uri)
2929 {
2930     napi_value offCallback = nullptr;
2931     napi_status status = napi_get_reference_value(env, ref, &offCallback);
2932     if (status != napi_ok) {
2933         NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2934         return false;
2935     }
2936     bool isSame = false;
2937     shared_ptr<DataShare::DataShareObserver> obs;
2938     string obsUri;
2939     {
2940         lock_guard<mutex> lock(sOnOffMutex_);
2941         for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
2942             napi_value onCallback = nullptr;
2943             status = napi_get_reference_value(env, (*it)->ref_, &onCallback);
2944             if (status != napi_ok) {
2945                 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2946                 return false;
2947             }
2948             napi_strict_equals(env, offCallback, onCallback, &isSame);
2949             if (isSame) {
2950                 obsUri = (*it)->uri_;
2951                 if ((isOff) && (uri.compare(obsUri) == 0)) {
2952                     obs = static_cast<shared_ptr<DataShare::DataShareObserver>>(*it);
2953                     listObj.observers_.erase(it);
2954                     break;
2955                 }
2956                 if (uri.compare(obsUri) != 0) {
2957                     return true;
2958                 }
2959                 return false;
2960             }
2961         }
2962     }
2963     if (isSame && isOff) {
2964         if (obs != nullptr) {
2965             UserFileClient::UnregisterObserverExt(Uri(obsUri), obs);
2966         }
2967     }
2968     return true;
2969 }
2970 
UserFileMgrOnCallback(napi_env env,napi_callback_info info)2971 napi_value MediaLibraryNapi::UserFileMgrOnCallback(napi_env env, napi_callback_info info)
2972 {
2973     MediaLibraryTracer tracer;
2974     tracer.Start("UserFileMgrOnCallback");
2975     napi_value undefinedResult = nullptr;
2976     napi_get_undefined(env, &undefinedResult);
2977     size_t argc = ARGS_THREE;
2978     napi_value argv[ARGS_THREE] = {nullptr};
2979     napi_value thisVar = nullptr;
2980     GET_JS_ARGS(env, info, argc, argv, thisVar);
2981     if (argc == ARGS_TWO) {
2982         return JSOnCallback(env, info);
2983     }
2984     NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
2985     MediaLibraryNapi *obj = nullptr;
2986     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
2987     if (status == napi_ok && obj != nullptr) {
2988         napi_valuetype valueType = napi_undefined;
2989         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
2990             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
2991             napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
2992             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2993             return undefinedResult;
2994         }
2995         char buffer[ARG_BUF_SIZE];
2996         size_t res = 0;
2997         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
2998             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2999             return undefinedResult;
3000         }
3001         string uri = string(buffer);
3002         bool isDerived = false;
3003         if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
3004             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3005             return undefinedResult;
3006         }
3007         const int32_t refCount = 1;
3008         napi_ref cbOnRef = nullptr;
3009         napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
3010         tracer.Start("RegisterNotifyChange");
3011         if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
3012             obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
3013         } else {
3014             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3015             napi_delete_reference(env, cbOnRef);
3016             return undefinedResult;
3017         }
3018         tracer.Finish();
3019     }
3020     return undefinedResult;
3021 }
3022 
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)3023 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
3024 {
3025     NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
3026 
3027     MediaType mediaType;
3028     int32_t typeEnum = GetListenerType(type);
3029 
3030     switch (typeEnum) {
3031         case AUDIO_LISTENER:
3032             CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
3033             mediaType = MEDIA_TYPE_AUDIO;
3034             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
3035             listObj.audioDataObserver_ = nullptr;
3036             break;
3037         case VIDEO_LISTENER:
3038             CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
3039             mediaType = MEDIA_TYPE_VIDEO;
3040             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
3041             listObj.videoDataObserver_ = nullptr;
3042             break;
3043         case IMAGE_LISTENER:
3044             CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
3045             mediaType = MEDIA_TYPE_IMAGE;
3046             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
3047             listObj.imageDataObserver_ = nullptr;
3048             break;
3049         case FILE_LISTENER:
3050             CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
3051             mediaType = MEDIA_TYPE_FILE;
3052             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
3053             listObj.fileDataObserver_ = nullptr;
3054             break;
3055         case SMARTALBUM_LISTENER:
3056             CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
3057             mediaType = MEDIA_TYPE_SMARTALBUM;
3058             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
3059                 listObj.smartAlbumDataObserver_);
3060             listObj.smartAlbumDataObserver_ = nullptr;
3061             break;
3062         case DEVICE_LISTENER:
3063             CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
3064             mediaType = MEDIA_TYPE_DEVICE;
3065             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
3066             listObj.deviceDataObserver_ = nullptr;
3067             break;
3068         case REMOTEFILE_LISTENER:
3069             CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
3070             mediaType = MEDIA_TYPE_REMOTEFILE;
3071             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
3072             listObj.remoteFileDataObserver_ = nullptr;
3073             break;
3074         case ALBUM_LISTENER:
3075             CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
3076             mediaType = MEDIA_TYPE_ALBUM;
3077             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
3078             listObj.albumDataObserver_ = nullptr;
3079             break;
3080         default:
3081             NAPI_ERR_LOG("Invalid Media Type");
3082             return;
3083     }
3084 
3085     if (listObj.cbOffRef_ != nullptr) {
3086         MediaChangeListener listener;
3087         listener.mediaType = mediaType;
3088         listObj.OnChange(listener, listObj.cbOffRef_);
3089     }
3090 }
3091 
UnRegisterNotifyChange(napi_env env,const std::string & uri,napi_ref ref,ChangeListenerNapi & listObj)3092 void MediaLibraryNapi::UnRegisterNotifyChange(napi_env env,
3093     const std::string &uri, napi_ref ref, ChangeListenerNapi &listObj)
3094 {
3095     if (ref != nullptr) {
3096         CheckRef(env, ref, listObj, true, uri);
3097         return;
3098     }
3099     if (listObj.observers_.size() == 0) {
3100         return;
3101     }
3102     std::vector<std::shared_ptr<MediaOnNotifyObserver>> offObservers;
3103     {
3104         lock_guard<mutex> lock(sOnOffMutex_);
3105         for (auto iter = listObj.observers_.begin(); iter != listObj.observers_.end();) {
3106             if (uri.compare((*iter)->uri_) == 0) {
3107                 offObservers.push_back(*iter);
3108                 vector<shared_ptr<MediaOnNotifyObserver>>::iterator tmp = iter;
3109                 iter = listObj.observers_.erase(tmp);
3110             } else {
3111                 iter++;
3112             }
3113         }
3114     }
3115     for (auto obs : offObservers) {
3116         UserFileClient::UnregisterObserverExt(Uri(uri),
3117             static_cast<shared_ptr<DataShare::DataShareObserver>>(obs));
3118     }
3119 }
3120 
JSOffCallback(napi_env env,napi_callback_info info)3121 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
3122 {
3123     MediaLibraryTracer tracer;
3124     tracer.Start("JSOffCallback");
3125     napi_value undefinedResult = nullptr;
3126     napi_get_undefined(env, &undefinedResult);
3127     size_t argc = ARGS_TWO;
3128     napi_value argv[ARGS_TWO] = {nullptr};
3129     napi_value thisVar = nullptr;
3130     GET_JS_ARGS(env, info, argc, argv, thisVar);
3131     NAPI_ASSERT(env, ARGS_ONE <= argc && argc <= ARGS_TWO, "requires one or two parameters");
3132     if (thisVar == nullptr || argv[PARAM0] == nullptr) {
3133         NAPI_ERR_LOG("Failed to retrieve details about the callback");
3134         return undefinedResult;
3135     }
3136     MediaLibraryNapi *obj = nullptr;
3137     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3138     if (status == napi_ok && obj != nullptr) {
3139         napi_valuetype valueType = napi_undefined;
3140         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
3141             return undefinedResult;
3142         }
3143         if (argc == ARGS_TWO) {
3144             auto status = napi_typeof(env, argv[PARAM1], &valueType);
3145             if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
3146                 argc -= 1;
3147             }
3148         }
3149         size_t res = 0;
3150         char buffer[ARG_BUF_SIZE];
3151         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3152             NAPI_ERR_LOG("Failed to get value string utf8 for type");
3153             return undefinedResult;
3154         }
3155         string type = string(buffer);
3156         if (argc == ARGS_TWO) {
3157             if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
3158                 g_listObj == nullptr) {
3159                 return undefinedResult;
3160             }
3161             const int32_t refCount = 1;
3162             napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
3163         }
3164 
3165         tracer.Start("UnregisterChange");
3166         obj->UnregisterChange(env, type, *g_listObj);
3167         tracer.Finish();
3168     }
3169 
3170     return undefinedResult;
3171 }
3172 
UserFileMgrOffCheckArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3173 static napi_value UserFileMgrOffCheckArgs(napi_env env, napi_callback_info info,
3174     unique_ptr<MediaLibraryAsyncContext> &context)
3175 {
3176     napi_value thisVar = nullptr;
3177     context->argc = ARGS_TWO;
3178     GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
3179     NAPI_ASSERT(env, ARGS_ONE <= context->argc && context->argc<= ARGS_TWO, "requires one or two parameters");
3180     if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
3181         return nullptr;
3182     }
3183 
3184     napi_valuetype valueType = napi_undefined;
3185     if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
3186         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3187         return nullptr;
3188     }
3189 
3190     if (context->argc == ARGS_TWO) {
3191         auto status = napi_typeof(env, context->argv[PARAM1], &valueType);
3192         if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
3193             context->argc -= 1;
3194         }
3195     }
3196 
3197     return thisVar;
3198 }
3199 
UserFileMgrOffCallback(napi_env env,napi_callback_info info)3200 napi_value MediaLibraryNapi::UserFileMgrOffCallback(napi_env env, napi_callback_info info)
3201 {
3202     MediaLibraryTracer tracer;
3203     tracer.Start("UserFileMgrOffCallback");
3204     napi_value undefinedResult = nullptr;
3205     napi_get_undefined(env, &undefinedResult);
3206 
3207     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3208     napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
3209     MediaLibraryNapi *obj = nullptr;
3210     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3211     if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
3212         return undefinedResult;
3213     }
3214     size_t res = 0;
3215     char buffer[ARG_BUF_SIZE];
3216     if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3217         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3218         return undefinedResult;
3219     }
3220 
3221     string uri = string(buffer);
3222     napi_valuetype valueType = napi_undefined;
3223     if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
3224         if (asyncContext->argc == ARGS_TWO) {
3225             if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3226                 return undefinedResult;
3227             }
3228             const int32_t refCount = 1;
3229             napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
3230         }
3231         obj->UnregisterChange(env, uri, *g_listObj);
3232         return undefinedResult;
3233     }
3234     napi_ref cbOffRef = nullptr;
3235     if (asyncContext->argc == ARGS_TWO) {
3236         if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3237             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3238             return undefinedResult;
3239         }
3240         const int32_t refCount = 1;
3241         napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
3242     }
3243     tracer.Start("UnRegisterNotifyChange");
3244     obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
3245     return undefinedResult;
3246 }
3247 
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3248 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
3249                                       MediaLibraryAsyncContext *context)
3250 {
3251     MediaLibraryTracer tracer;
3252     tracer.Start("JSReleaseCompleteCallback");
3253 
3254     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3255 
3256     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3257     jsContext->status = false;
3258     if (context->objectInfo != nullptr) {
3259         napi_create_int32(env, E_SUCCESS, &jsContext->data);
3260         jsContext->status = true;
3261         napi_get_undefined(env, &jsContext->error);
3262     } else {
3263         NAPI_ERR_LOG("JSReleaseCompleteCallback context->objectInfo == nullptr");
3264         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3265             "UserFileClient is invalid");
3266         napi_get_undefined(env, &jsContext->data);
3267     }
3268 
3269     tracer.Finish();
3270     if (context->work != nullptr) {
3271         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3272                                                    context->work, *jsContext);
3273     }
3274 
3275     delete context;
3276 }
3277 
JSRelease(napi_env env,napi_callback_info info)3278 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
3279 {
3280     napi_status status;
3281     napi_value result = nullptr;
3282     size_t argc = ARGS_ONE;
3283     napi_value argv[ARGS_ONE] = {0};
3284     napi_value thisVar = nullptr;
3285     napi_value resource = nullptr;
3286     int32_t refCount = 1;
3287 
3288     MediaLibraryTracer tracer;
3289     tracer.Start("JSRelease");
3290 
3291     GET_JS_ARGS(env, info, argc, argv, thisVar);
3292     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
3293     napi_get_undefined(env, &result);
3294 
3295     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3296     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3297     NAPI_ASSERT(env, status == napi_ok && asyncContext->objectInfo != nullptr, "Failed to get object info");
3298 
3299     if (argc == PARAM1) {
3300         napi_valuetype valueType = napi_undefined;
3301         napi_typeof(env, argv[PARAM0], &valueType);
3302         if (valueType == napi_function) {
3303             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
3304         }
3305     }
3306     CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3307 
3308     NAPI_CALL(env, napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
3309     NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3310     NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRelease", asyncContext);
3311 
3312     status = napi_create_async_work(
3313         env, nullptr, resource, [](napi_env env, void *data) {},
3314         reinterpret_cast<CompleteCallback>(JSReleaseCompleteCallback),
3315         static_cast<void *>(asyncContext.get()), &asyncContext->work);
3316     if (status != napi_ok) {
3317         napi_get_undefined(env, &result);
3318     } else {
3319         napi_queue_async_work(env, asyncContext->work);
3320         asyncContext.release();
3321     }
3322 
3323     return result;
3324 }
3325 
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)3326 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
3327 {
3328     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3329     if (smartAlbum == nullptr) {
3330         NAPI_ERR_LOG("SmartAlbumAsset is nullptr");
3331         return;
3332     }
3333     if (smartAlbum->GetAlbumCapacity() == 0) {
3334         return;
3335     }
3336     string trashPrefix;
3337     if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
3338         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
3339     } else {
3340         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
3341     }
3342     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
3343     context->selectionArgs.emplace_back("0");
3344     context->selectionArgs.emplace_back(to_string(smartAlbum->GetAlbumId()));
3345     DataShare::DataSharePredicates predicates;
3346     predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC LIMIT 0,1 ");
3347     predicates.SetWhereClause(context->selection);
3348     predicates.SetWhereArgs(context->selectionArgs);
3349     vector<string> columns;
3350     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + ASSETMAP_VIEW_NAME);
3351     int errCode = 0;
3352     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3353     if (resultSet == nullptr) {
3354         NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
3355         return;
3356     }
3357     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
3358     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
3359     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
3360     string coverUri = fileAsset->GetUri();
3361     smartAlbum->SetCoverUri(coverUri);
3362     NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
3363 }
3364 
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)3365 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
3366     MediaLibraryAsyncContext *context)
3367 {
3368     CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
3369     smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
3370     smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
3371         TYPE_STRING)));
3372     smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUMASSETS_ALBUMCAPACITY,
3373         resultSet, TYPE_INT32)));
3374     MediaFileUri fileUri(MEDIA_TYPE_SMARTALBUM, to_string(smartAlbumData->GetAlbumId()), context->networkId,
3375         MEDIA_API_VERSION_DEFAULT);
3376     smartAlbumData->SetAlbumUri(fileUri.ToString());
3377     smartAlbumData->SetDescription(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_DESCRIPTION, resultSet,
3378         TYPE_STRING)));
3379     smartAlbumData->SetExpiredTime(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_EXPIRED_TIME, resultSet,
3380         TYPE_INT32)));
3381     smartAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_COVER_URI, resultSet,
3382         TYPE_STRING)));
3383     smartAlbumData->SetResultNapiType(context->resultNapiType);
3384 }
3385 
3386 #ifndef MEDIALIBRARY_COMPATIBILITY
GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3387 static void GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3388 {
3389     MediaLibraryTracer tracer;
3390     tracer.Start("GetAllSmartAlbumResultDataExecute");
3391 
3392     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3393     NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
3394 
3395     if (context->privateAlbumType == TYPE_TRASH) {
3396         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
3397         NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
3398     }
3399     if (context->privateAlbumType == TYPE_FAVORITE) {
3400         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
3401         NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
3402     }
3403 
3404     vector<string> columns;
3405     string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3406     if (!context->networkId.empty()) {
3407         uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
3408             "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3409     }
3410     Uri uri(uriStr);
3411     int errCode = 0;
3412     auto resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode);
3413     if (resultSet == nullptr) {
3414         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
3415         context->error = E_PERMISSION_DENIED;
3416         return;
3417     }
3418 
3419     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
3420         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
3421         context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
3422         context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
3423         context->fetchSmartAlbumResult->SetResultNapiType(context->resultNapiType);
3424         return;
3425     }
3426     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3427         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3428         SetSmartAlbumData(albumData.get(), resultSet, context);
3429         if (albumData->GetCoverUri().empty()) {
3430             SetSmartAlbumCoverUri(context, albumData);
3431         }
3432         context->privateSmartAlbumNativeArray.push_back(move(albumData));
3433     }
3434 }
3435 
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3436 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3437     unique_ptr<JSAsyncContextOutput> &jsContext)
3438 {
3439     if (context->smartAlbumData != nullptr) {
3440         NAPI_ERR_LOG("context->smartAlbumData != nullptr");
3441         jsContext->status = true;
3442         napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3443         napi_get_undefined(env, &jsContext->error);
3444         jsContext->data = albumNapiObj;
3445     } else if (!context->privateSmartAlbumNativeArray.empty()) {
3446         jsContext->status = true;
3447         napi_value albumArray = nullptr;
3448         napi_create_array(env, &albumArray);
3449         for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
3450             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3451                 context->privateSmartAlbumNativeArray[i]);
3452             napi_set_element(env, albumArray, i, albumNapiObj);
3453         }
3454         napi_get_undefined(env, &jsContext->error);
3455         jsContext->data = albumArray;
3456     } else {
3457         NAPI_ERR_LOG("No fetch file result found!");
3458         napi_get_undefined(env, &jsContext->data);
3459         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3460             "Failed to obtain Fetch File Result");
3461     }
3462 }
3463 
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3464 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3465     unique_ptr<JSAsyncContextOutput> &jsContext)
3466 {
3467     if (context->fetchSmartAlbumResult->GetCount() < 0) {
3468         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
3469             "find no data by options");
3470     } else {
3471         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
3472         if (fileResult == nullptr) {
3473             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3474                 "Failed to create js object for Fetch SmartAlbum Result");
3475         } else {
3476             jsContext->data = fileResult;
3477             jsContext->status = true;
3478             napi_get_undefined(env, &jsContext->error);
3479         }
3480     }
3481 }
3482 
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3483 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3484     unique_ptr<JSAsyncContextOutput> &jsContext)
3485 {
3486     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
3487         MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
3488     } else {
3489         UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
3490     }
3491 }
3492 
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)3493 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
3494 {
3495     MediaLibraryTracer tracer;
3496     tracer.Start("GetPrivateAlbumCallbackComplete");
3497 
3498     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3499     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3500     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3501     jsContext->status = false;
3502     napi_get_undefined(env, &jsContext->error);
3503     if (context->error != ERR_DEFAULT) {
3504         napi_get_undefined(env, &jsContext->data);
3505         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3506             "Query for get fileAssets failed");
3507     } else {
3508         SmartAlbumsAsyncResult(env, context, jsContext);
3509     }
3510 
3511     tracer.Finish();
3512     if (context->work != nullptr) {
3513         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3514                                                    context->work, *jsContext);
3515     }
3516     delete context;
3517 }
3518 #endif
3519 
GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3520 static void GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3521 {
3522     DataShare::DataSharePredicates predicates;
3523     predicates.SetWhereClause(context->selection);
3524     predicates.SetWhereArgs(context->selectionArgs);
3525     vector<string> columns;
3526     Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3527     int errCode = 0;
3528     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3529     if (resultSet == nullptr) {
3530         NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3531         context->error = ERR_INVALID_OUTPUT;
3532         return;
3533     }
3534     if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
3535         context->smartAlbumData = make_unique<SmartAlbumAsset>();
3536         SetSmartAlbumData(context->smartAlbumData.get(), resultSet, context);
3537         SetSmartAlbumCoverUri(context, context->smartAlbumData);
3538     } else {
3539         NAPI_ERR_LOG("Failed to goToFirstRow");
3540         context->error = ERR_INVALID_OUTPUT;
3541         return;
3542     }
3543 }
3544 
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)3545 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
3546 {
3547     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3548     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3549     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3550     jsContext->status = false;
3551     napi_get_undefined(env, &jsContext->error);
3552     if (context->error != ERR_DEFAULT) {
3553         napi_get_undefined(env, &jsContext->data);
3554         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3555             "Query for get smartAlbums failed");
3556     } else {
3557         if (!context->smartAlbumNativeArray.empty()) {
3558             jsContext->status = true;
3559             napi_value albumArray = nullptr;
3560             napi_create_array(env, &albumArray);
3561             for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
3562                 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3563                     context->smartAlbumNativeArray[i]);
3564                 napi_set_element(env, albumArray, i, albumNapiObj);
3565             }
3566             napi_get_undefined(env, &jsContext->error);
3567             jsContext->data = albumArray;
3568         } else {
3569             NAPI_ERR_LOG("No SmartAlbums result found!");
3570             napi_get_undefined(env, &jsContext->data);
3571             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3572                 "Failed to obtain SmartAlbums Result");
3573         }
3574     }
3575     if (context->work != nullptr) {
3576         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3577                                                    context->work, *jsContext);
3578     }
3579     delete context;
3580 }
3581 
GetJSArgsForGetSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3582 napi_value GetJSArgsForGetSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3583                                      MediaLibraryAsyncContext &asyncContext)
3584 {
3585     napi_value result = nullptr;
3586     auto context = &asyncContext;
3587     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3588     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3589     for (size_t i = 0; i < argc; i++) {
3590         napi_valuetype valueType = napi_undefined;
3591         napi_typeof(env, argv[i], &valueType);
3592         if (i == 0 && valueType == napi_number) {
3593             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3594         } else if ((i == PARAM1) && valueType == napi_function) {
3595             napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3596             break;
3597         } else {
3598             NAPI_ASSERT(env, false, "type mismatch");
3599         }
3600     }
3601     if (context->parentSmartAlbumId < 0) {
3602         NAPI_ASSERT(env, false, "type mismatch");
3603     }
3604     napi_get_boolean(env, true, &result);
3605     return result;
3606 }
3607 
GetSmartAlbumsResultDataExecute(napi_env env,void * data)3608 static void GetSmartAlbumsResultDataExecute(napi_env env, void *data)
3609 {
3610     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3611     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3612     if (context->parentSmartAlbumId < 0) {
3613         context->error = ERR_INVALID_OUTPUT;
3614         NAPI_ERR_LOG("ParentSmartAlbumId is invalid");
3615         return;
3616     }
3617     DataShare::DataSharePredicates predicates;
3618     if (context->parentSmartAlbumId == 0) {
3619         predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " ISNULL");
3620     } else {
3621         predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " = ? ");
3622         predicates.SetWhereArgs({ to_string(context->parentSmartAlbumId) });
3623     }
3624     vector<string> columns;
3625     Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3626     int errCode = 0;
3627     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3628     if (resultSet == nullptr) {
3629         NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3630         context->error = ERR_INVALID_OUTPUT;
3631         return;
3632     }
3633     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3634         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3635         SetSmartAlbumData(albumData.get(), resultSet, context);
3636         if (albumData->GetCoverUri().empty()) {
3637             SetSmartAlbumCoverUri(context, albumData);
3638         }
3639         context->smartAlbumNativeArray.push_back(move(albumData));
3640     }
3641 }
3642 
JSGetSmartAlbums(napi_env env,napi_callback_info info)3643 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
3644 {
3645     napi_status status;
3646     napi_value result = nullptr;
3647     size_t argc = ARGS_TWO;
3648     napi_value argv[ARGS_TWO] = {0};
3649     napi_value thisVar = nullptr;
3650 
3651     GET_JS_ARGS(env, info, argc, argv, thisVar);
3652     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3653     napi_get_undefined(env, &result);
3654     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3655     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3656     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
3657     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3658     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3659         result = GetJSArgsForGetSmartAlbum(env, argc, argv, *asyncContext);
3660         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3661         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3662         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
3663             GetSmartAlbumsResultDataExecute, SmartAlbumsAsyncCallbackComplete);
3664     }
3665 
3666     return result;
3667 }
3668 
AddDefaultPhotoAlbumColumns(napi_env env,vector<string> & fetchColumn)3669 static napi_value AddDefaultPhotoAlbumColumns(napi_env env, vector<string> &fetchColumn)
3670 {
3671     auto validFetchColumns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
3672     for (const auto &column : fetchColumn) {
3673         if (PhotoAlbumColumns::IsPhotoAlbumColumn(column)) {
3674             validFetchColumns.insert(column);
3675         } else if (column.compare(MEDIA_DATA_DB_URI) == 0) {
3676             // uri is default property of album
3677             continue;
3678         } else {
3679             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3680             return nullptr;
3681         }
3682     }
3683     fetchColumn.assign(validFetchColumns.begin(), validFetchColumns.end());
3684 
3685     napi_value result = nullptr;
3686     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3687     return result;
3688 }
3689 
3690 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatGetPrivateAlbumExecute(napi_env env,void * data)3691 static void CompatGetPrivateAlbumExecute(napi_env env, void *data)
3692 {
3693     MediaLibraryTracer tracer;
3694     tracer.Start("CompatGetPrivateAlbumExecute");
3695 
3696     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3697     string queryUri = URI_QUERY_PHOTO_ALBUM;
3698     Uri uri(queryUri);
3699     int err = 0;
3700     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, err);
3701     if (resultSet == nullptr) {
3702         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", err);
3703         context->SaveError(err);
3704         return;
3705     }
3706     err = resultSet->GoToFirstRow();
3707     if (err != NativeRdb::E_OK) {
3708         context->SaveError(E_HAS_DB_ERROR);
3709         return;
3710     }
3711 
3712     auto albumData = make_unique<AlbumAsset>();
3713     SetAlbumData(albumData.get(), resultSet, "");
3714     CompatSetAlbumCoverUri(context, albumData);
3715     context->albumNativeArray.push_back(move(albumData));
3716 }
3717 
CompatGetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3718 static void CompatGetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
3719     unique_ptr<JSAsyncContextOutput> &jsContext)
3720 {
3721     jsContext->status = true;
3722     napi_value albumArray = nullptr;
3723     CHECK_ARGS_RET_VOID(env, napi_create_array(env, &albumArray), JS_INNER_FAIL);
3724     for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
3725         napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
3726         CHECK_ARGS_RET_VOID(env, napi_set_element(env, albumArray, i, albumNapiObj), JS_INNER_FAIL);
3727     }
3728     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3729     jsContext->data = albumArray;
3730 }
3731 
CompatGetPrivateAlbumComplete(napi_env env,napi_status status,void * data)3732 static void CompatGetPrivateAlbumComplete(napi_env env, napi_status status, void *data)
3733 {
3734     MediaLibraryTracer tracer;
3735     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
3736 
3737     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3738     auto jsContext = make_unique<JSAsyncContextOutput>();
3739     jsContext->status = false;
3740 
3741     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3742     if (context->error != ERR_DEFAULT || context->albumNativeArray.empty()) {
3743         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3744         context->HandleError(env, jsContext->error);
3745     } else {
3746         CompatGetPhotoAlbumQueryResult(env, context, jsContext);
3747     }
3748 
3749     tracer.Finish();
3750     if (context->work != nullptr) {
3751         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3752                                                    context->work, *jsContext);
3753     }
3754     delete context;
3755 }
3756 
ParseArgsGetPrivateAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3757 napi_value ParseArgsGetPrivateAlbum(napi_env env, napi_callback_info info,
3758     unique_ptr<MediaLibraryAsyncContext> &context)
3759 {
3760     int32_t privateAlbumType = -1;
3761     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, context, privateAlbumType),
3762         JS_ERR_PARAMETER_INVALID);
3763     if (privateAlbumType != PrivateAlbumType::TYPE_FAVORITE && privateAlbumType != PrivateAlbumType::TYPE_TRASH) {
3764         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3765         return nullptr;
3766     }
3767 
3768     PhotoAlbumSubType subType = ANY;
3769     switch (privateAlbumType) {
3770         case PrivateAlbumType::TYPE_FAVORITE: {
3771             subType = PhotoAlbumSubType::FAVORITE;
3772             break;
3773         }
3774         case PrivateAlbumType::TYPE_TRASH: {
3775             subType = PhotoAlbumSubType::TRASH;
3776             break;
3777         }
3778         default: {
3779             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3780             return nullptr;
3781         }
3782     }
3783     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
3784     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subType));
3785     CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
3786 
3787     napi_value result = nullptr;
3788     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3789     return result;
3790 }
3791 
CompatGetPrivateAlbum(napi_env env,napi_callback_info info)3792 napi_value CompatGetPrivateAlbum(napi_env env, napi_callback_info info)
3793 {
3794     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
3795     CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
3796 
3797     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CompatGetPrivateAlbum",
3798         CompatGetPrivateAlbumExecute, CompatGetPrivateAlbumComplete);
3799 }
3800 #endif // MEDIALIBRARY_COMPATIBILITY
3801 
JSGetPrivateAlbum(napi_env env,napi_callback_info info)3802 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
3803 {
3804 #ifdef MEDIALIBRARY_COMPATIBILITY
3805     return CompatGetPrivateAlbum(env, info);
3806 #else
3807     napi_status status;
3808     napi_value result = nullptr;
3809     size_t argc = ARGS_TWO;
3810     napi_value argv[ARGS_TWO] = {0};
3811     napi_value thisVar = nullptr;
3812     const int32_t refCount = 1;
3813 
3814     GET_JS_ARGS(env, info, argc, argv, thisVar);
3815     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3816     napi_get_undefined(env, &result);
3817     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3818     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3819     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3820     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3821         for (size_t i = PARAM0; i < argc; i++) {
3822             napi_valuetype valueType = napi_undefined;
3823             napi_typeof(env, argv[i], &valueType);
3824             if (i == PARAM0 && valueType == napi_number) {
3825                 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
3826             } else if (i == PARAM1 && valueType == napi_function) {
3827                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
3828                 break;
3829             } else {
3830                 NAPI_ASSERT(env, false, "type mismatch");
3831             }
3832         }
3833         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
3834             [](napi_env env, void *data) {
3835                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3836                 GetAllSmartAlbumResultDataExecute(context);
3837             }, GetPrivateAlbumCallbackComplete);
3838     }
3839     return result;
3840 #endif
3841 }
3842 
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3843 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3844                                         MediaLibraryAsyncContext &asyncContext)
3845 {
3846     const int32_t refCount = 1;
3847     napi_value result = nullptr;
3848     auto context = &asyncContext;
3849     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3850     size_t res = 0;
3851     char buffer[PATH_MAX];
3852     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3853     for (size_t i = 0; i < argc; i++) {
3854         napi_valuetype valueType = napi_undefined;
3855         napi_typeof(env, argv[i], &valueType);
3856         if (i == 0 && valueType == napi_number) {
3857             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3858         } else if (i == PARAM1 && valueType == napi_string) {
3859             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
3860         } else if (i == PARAM2 && valueType == napi_function) {
3861             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
3862             break;
3863         } else {
3864             NAPI_ASSERT(env, false, "type mismatch");
3865         }
3866     }
3867     if (context->parentSmartAlbumId < 0) {
3868         NAPI_ASSERT(env, false, "type mismatch");
3869     }
3870     string smartName = string(buffer);
3871     if (smartName.empty()) {
3872         NAPI_ASSERT(env, false, "type mismatch");
3873     }
3874     context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
3875     napi_get_boolean(env, true, &result);
3876     return result;
3877 }
3878 
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3879 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
3880                                                MediaLibraryAsyncContext *context)
3881 {
3882     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3883     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3884     jsContext->status = false;
3885     if (context->error == ERR_DEFAULT) {
3886         if (context->smartAlbumData == nullptr) {
3887             NAPI_ERR_LOG("No albums found");
3888             napi_get_undefined(env, &jsContext->data);
3889             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3890                 "No albums found");
3891         } else {
3892             jsContext->status = true;
3893             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3894             jsContext->data = albumNapiObj;
3895             napi_get_undefined(env, &jsContext->error);
3896         }
3897     } else {
3898         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3899             "File asset creation failed");
3900         napi_get_undefined(env, &jsContext->data);
3901     }
3902     if (context->work != nullptr) {
3903         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3904                                                    context->work, *jsContext);
3905     }
3906     delete context;
3907 }
3908 
CreateSmartAlbumExecute(MediaLibraryAsyncContext * context)3909 static void CreateSmartAlbumExecute(MediaLibraryAsyncContext *context)
3910 {
3911     context->valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
3912     Uri CreateSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMOPRN + "/" +
3913                             MEDIA_SMARTALBUMOPRN_CREATEALBUM);
3914     int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
3915     if (retVal < 0) {
3916         context->SaveError(retVal);
3917         NAPI_ERR_LOG("CreateSmartAlbum failed, retVal = %{private}d", retVal);
3918         return;
3919     }
3920     context->selection = SMARTALBUM_DB_ID + " = ?";
3921     context->selectionArgs = { to_string(retVal) };
3922     GetSmartAlbumResultDataExecute(context);
3923     // If parentSmartAlbumId == 0 do not need to add to smart map
3924     if (context->parentSmartAlbumId != 0) {
3925         DataShare::DataShareValuesBucket valuesBucket;
3926         valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
3927         valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ALBUM_ID, retVal);
3928         NAPI_DEBUG_LOG("CreateSmartAlbumExecute retVal = %{public}d, parentSmartAlbumId = %{public}d",
3929             retVal, context->parentSmartAlbumId);
3930         Uri addAsseturi(MEDIALIBRARY_DATA_URI +
3931             "/" + MEDIA_SMARTALBUMMAPOPRN + "/" + MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM);
3932         int32_t changedRows = UserFileClient::Insert(addAsseturi, valuesBucket);
3933         context->SaveError(changedRows);
3934     }
3935 }
3936 
JSCreateSmartAlbum(napi_env env,napi_callback_info info)3937 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
3938 {
3939     napi_status status;
3940     napi_value result = nullptr;
3941     size_t argc = ARGS_THREE;
3942     napi_value argv[ARGS_THREE] = {0};
3943     napi_value thisVar = nullptr;
3944     napi_value resource = nullptr;
3945 
3946     GET_JS_ARGS(env, info, argc, argv, thisVar);
3947     NAPI_ASSERT(env, (argc == ARGS_TWO || argc == ARGS_THREE), "requires 3 parameters maximum");
3948     napi_get_undefined(env, &result);
3949     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3950     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3951     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3952     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3953         result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
3954         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3955         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3956         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
3957         status = napi_create_async_work(
3958             env, nullptr, resource, [](napi_env env, void *data) {
3959                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3960                 CreateSmartAlbumExecute(context);
3961             },
3962             reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
3963             static_cast<void *>(asyncContext.get()), &asyncContext->work);
3964         if (status != napi_ok) {
3965             napi_get_undefined(env, &result);
3966         } else {
3967             napi_queue_async_work(env, asyncContext->work);
3968             asyncContext.release();
3969         }
3970     }
3971     return result;
3972 }
3973 
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)3974 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
3975 {
3976     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3977     if (context->smartAlbumId == TYPE_TRASH) {
3978         NAPI_ERR_LOG("Trash smartalbum can not be deleted");
3979         context->error = E_TRASHALBUM_CAN_NOT_DELETE;
3980         return;
3981     }
3982     if (context->smartAlbumId == TYPE_FAVORITE) {
3983         NAPI_ERR_LOG("Facorite smartalbum can not be deleted");
3984         context->error = E_FAVORITEALBUM_CAN_NOT_DELETE;
3985         return;
3986     }
3987     DataShare::DataShareValuesBucket valuesBucket;
3988     valuesBucket.Put(SMARTALBUM_DB_ID, context->smartAlbumId);
3989     Uri DeleteSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" +
3990         MEDIA_SMARTALBUMOPRN + "/" + MEDIA_SMARTALBUMOPRN_DELETEALBUM);
3991     int retVal = UserFileClient::Insert(DeleteSmartAlbumUri, valuesBucket);
3992     NAPI_DEBUG_LOG("JSDeleteSmartAlbumExecute retVal = %{private}d, smartAlbumId = %{private}d",
3993         retVal, context->smartAlbumId);
3994     if (retVal < 0) {
3995         context->SaveError(retVal);
3996     } else {
3997         context->retVal = retVal;
3998     }
3999 }
4000 
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)4001 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
4002                                         MediaLibraryAsyncContext &asyncContext)
4003 {
4004     napi_value result = nullptr;
4005     auto context = &asyncContext;
4006     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
4007     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
4008     for (size_t i = 0; i < argc; i++) {
4009         napi_valuetype valueType = napi_undefined;
4010         napi_typeof(env, argv[i], &valueType);
4011         if (i == 0 && valueType == napi_number) {
4012             napi_get_value_int32(env, argv[i], &context->smartAlbumId);
4013         } else if (i == PARAM1 && valueType == napi_function) {
4014             napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
4015             break;
4016         } else {
4017             NAPI_ASSERT(env, false, "type mismatch");
4018         }
4019     }
4020     if (context->smartAlbumId < 0) {
4021         NAPI_ASSERT(env, false, "type mismatch");
4022     }
4023     napi_get_boolean(env, true, &result);
4024     return result;
4025 }
4026 
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4027 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
4028                                                MediaLibraryAsyncContext *context)
4029 {
4030     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4031     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4032     jsContext->status = false;
4033     if (context->error == ERR_DEFAULT) {
4034         napi_create_int32(env, context->retVal, &jsContext->data);
4035         napi_get_undefined(env, &jsContext->error);
4036         jsContext->status = true;
4037     } else {
4038         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4039             "UserFileClient is invalid");
4040         napi_get_undefined(env, &jsContext->data);
4041     }
4042     if (context->work != nullptr) {
4043         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4044                                                    context->work, *jsContext);
4045     }
4046     delete context;
4047 }
4048 
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)4049 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
4050 {
4051     napi_status status;
4052     napi_value result = nullptr;
4053     size_t argc = ARGS_TWO;
4054     napi_value argv[ARGS_TWO] = {0};
4055     napi_value thisVar = nullptr;
4056     napi_value resource = nullptr;
4057 
4058     GET_JS_ARGS(env, info, argc, argv, thisVar);
4059     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
4060     napi_get_undefined(env, &result);
4061     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4062     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4063     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4064         result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
4065         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
4066         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4067         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
4068         status = napi_create_async_work(
4069             env, nullptr, resource, [](napi_env env, void *data) {
4070                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4071                 JSDeleteSmartAlbumExecute(context);
4072             },
4073             reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
4074             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4075         if (status != napi_ok) {
4076             napi_get_undefined(env, &result);
4077         } else {
4078             napi_queue_async_work(env, asyncContext->work);
4079             asyncContext.release();
4080         }
4081     }
4082     return result;
4083 }
4084 
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)4085 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
4086 {
4087     napi_value value;
4088     napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
4089     if (status != napi_ok) {
4090         NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
4091         return status;
4092     }
4093     status = napi_set_named_property(env, result, fieldStr, value);
4094     if (status != napi_ok) {
4095         NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
4096     }
4097     return status;
4098 }
4099 
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)4100 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
4101 {
4102     napi_value value = nullptr;
4103     napi_status status = napi_get_boolean(env, boolvalue, &value);
4104     if (status != napi_ok) {
4105         NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
4106         return status;
4107     }
4108     status = napi_set_named_property(env, result, fieldStr, value);
4109     if (status != napi_ok) {
4110         NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
4111     }
4112     return status;
4113 }
4114 
PeerInfoToJsArray(const napi_env & env,const vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)4115 static void PeerInfoToJsArray(const napi_env &env, const vector<unique_ptr<PeerInfo>> &vecPeerInfo,
4116     const int32_t idx, napi_value &arrayResult)
4117 {
4118     if (idx >= (int32_t) vecPeerInfo.size()) {
4119         return;
4120     }
4121     auto info = vecPeerInfo[idx].get();
4122     if (info == nullptr) {
4123         return;
4124     }
4125     napi_value result = nullptr;
4126     napi_create_object(env, &result);
4127     SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
4128     SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
4129     SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
4130     SetValueBool(env, "isOnline", info->isOnline, result);
4131 
4132     napi_status status = napi_set_element(env, arrayResult, idx, result);
4133     if (status != napi_ok) {
4134         NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
4135     }
4136 }
4137 
QueryActivePeer(int & errCode,MediaLibraryAsyncContext * context,string & uriType)4138 shared_ptr<DataShare::DataShareResultSet> QueryActivePeer(int &errCode,
4139     MediaLibraryAsyncContext *context, string &uriType)
4140 {
4141     vector<string> columns;
4142     DataShare::DataSharePredicates predicates;
4143     Uri uri(uriType);
4144     if (uriType == MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE) {
4145         string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
4146         predicates.SetWhereClause(strQueryCondition);
4147     } else if (uriType == MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE) {
4148         predicates.SetWhereClause(context->selection);
4149     }
4150     predicates.SetWhereArgs(context->selectionArgs);
4151     return UserFileClient::Query(uri, predicates, columns, errCode);
4152 }
4153 
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4154 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
4155     MediaLibraryAsyncContext *context)
4156 {
4157     napi_value jsPeerInfoArray = nullptr;
4158     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4159     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4160     jsContext->status = false;
4161     napi_get_undefined(env, &jsContext->data);
4162     string uriType = MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE;
4163     int errCode = 0;
4164     shared_ptr<DataShare::DataShareResultSet> resultSet = QueryActivePeer(errCode, context, uriType);
4165     if (resultSet == nullptr) {
4166         NAPI_ERR_LOG("JSGetActivePeers resultSet is null, errCode is %{public}d", errCode);
4167         delete context;
4168         return;
4169     }
4170 
4171     vector<unique_ptr<PeerInfo>> peerInfoArray;
4172     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
4173         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
4174         if (peerInfo != nullptr) {
4175             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
4176                 TYPE_STRING));
4177             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
4178                 TYPE_STRING));
4179             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
4180                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
4181             peerInfo->isOnline = true;
4182             peerInfoArray.push_back(move(peerInfo));
4183         }
4184     }
4185 
4186     if (napi_create_array(env, &jsPeerInfoArray) == napi_ok) {
4187         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
4188             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
4189         }
4190 
4191         jsContext->data = jsPeerInfoArray;
4192         napi_get_undefined(env, &jsContext->error);
4193         jsContext->status = true;
4194     }
4195 
4196     if (context->work != nullptr) {
4197         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4198                                                    context->work, *jsContext);
4199     }
4200 
4201     delete context;
4202 }
4203 
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4204 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
4205     MediaLibraryAsyncContext *context)
4206 {
4207     napi_value jsPeerInfoArray = nullptr;
4208     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4209     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4210     jsContext->status = false;
4211     napi_get_undefined(env, &jsContext->data);
4212     string uriType = MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE;
4213     int errCode = 0;
4214     shared_ptr<DataShare::DataShareResultSet> resultSet = QueryActivePeer(errCode, context, uriType);
4215     if (resultSet == nullptr) {
4216         NAPI_ERR_LOG("JSGetAllPeers resultSet is null, errCode is %{public}d", errCode);
4217         delete context;
4218         return;
4219     }
4220 
4221     vector<unique_ptr<PeerInfo>> peerInfoArray;
4222     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
4223         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
4224         if (peerInfo != nullptr) {
4225             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
4226                 TYPE_STRING));
4227             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
4228                 TYPE_STRING));
4229             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
4230                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
4231             peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
4232                 TYPE_INT32)) == 0);
4233             peerInfoArray.push_back(move(peerInfo));
4234         }
4235     }
4236 
4237     if (napi_create_array(env, &jsPeerInfoArray) == napi_ok) {
4238         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
4239             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
4240         }
4241 
4242         jsContext->data = jsPeerInfoArray;
4243         napi_get_undefined(env, &jsContext->error);
4244         jsContext->status = true;
4245     }
4246 
4247     if (context->work != nullptr) {
4248         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4249                                                    context->work, *jsContext);
4250     }
4251     delete context;
4252 }
4253 
JSGetActivePeers(napi_env env,napi_callback_info info)4254 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
4255 {
4256     napi_status status;
4257     napi_value result = nullptr;
4258     const int32_t refCount = 1;
4259     napi_value resource = nullptr;
4260     size_t argc = ARGS_ONE;
4261     napi_value argv[ARGS_ONE] = {0};
4262     napi_value thisVar = nullptr;
4263 
4264     MediaLibraryTracer tracer;
4265     tracer.Start("JSGetActivePeers");
4266 
4267     GET_JS_ARGS(env, info, argc, argv, thisVar);
4268     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
4269     napi_get_undefined(env, &result);
4270 
4271     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4272     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4273     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4274         if (argc == ARGS_ONE) {
4275             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
4276         }
4277 
4278         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4279         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetActivePeers", asyncContext);
4280         status = napi_create_async_work(
4281             env, nullptr, resource, [](napi_env env, void *data) {},
4282             reinterpret_cast<CompleteCallback>(JSGetActivePeersCompleteCallback),
4283             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4284         if (status != napi_ok) {
4285             napi_get_undefined(env, &result);
4286         } else {
4287             napi_queue_async_work(env, asyncContext->work);
4288             asyncContext.release();
4289         }
4290     }
4291 
4292     return result;
4293 }
4294 
JSGetAllPeers(napi_env env,napi_callback_info info)4295 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
4296 {
4297     napi_status status;
4298     napi_value result = nullptr;
4299     const int32_t refCount = 1;
4300     napi_value resource = nullptr;
4301     size_t argc = ARGS_ONE;
4302     napi_value argv[ARGS_ONE] = {0};
4303     napi_value thisVar = nullptr;
4304 
4305     MediaLibraryTracer tracer;
4306     tracer.Start("JSGetAllPeers");
4307 
4308     GET_JS_ARGS(env, info, argc, argv, thisVar);
4309     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
4310     napi_get_undefined(env, &result);
4311 
4312     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4313     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4314     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4315         if (argc == ARGS_ONE) {
4316             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
4317         }
4318 
4319         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4320         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetAllPeers", asyncContext);
4321         status = napi_create_async_work(
4322             env, nullptr, resource, [](napi_env env, void *data) {},
4323             reinterpret_cast<CompleteCallback>(JSGetAllPeersCompleteCallback),
4324             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4325         if (status != napi_ok) {
4326             napi_get_undefined(env, &result);
4327         } else {
4328             napi_queue_async_work(env, asyncContext->work);
4329             asyncContext.release();
4330         }
4331     }
4332 
4333     return result;
4334 }
4335 
CloseAsset(MediaLibraryAsyncContext * context,string uri)4336 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
4337 {
4338     string abilityUri = MEDIALIBRARY_DATA_URI;
4339     Uri closeAssetUri(URI_CLOSE_FILE);
4340     context->valuesBucket.Clear();
4341     context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
4342     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
4343     NAPI_DEBUG_LOG("File close asset %{public}d", ret);
4344     if (ret != E_SUCCESS) {
4345         context->error = ret;
4346         NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
4347     }
4348     return ret;
4349 }
4350 
GetStoreMediaAssetUri(MediaLibraryAsyncContext * context,string & uri)4351 static void GetStoreMediaAssetUri(MediaLibraryAsyncContext *context, string &uri)
4352 {
4353     bool isValid = false;
4354     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
4355     if (relativePath.find(CAMERA_DIR_VALUES) == 0 ||
4356         relativePath.find(VIDEO_DIR_VALUES) == 0 ||
4357         relativePath.find(PIC_DIR_VALUES) == 0) {
4358         uri = URI_CREATE_PHOTO;
4359     } else if (relativePath.find(AUDIO_DIR_VALUES) == 0) {
4360         uri = URI_CREATE_AUDIO;
4361     } else {
4362         uri = URI_CREATE_FILE;
4363     }
4364 }
4365 
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)4366 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
4367 {
4368     string realPath;
4369     if (!PathToRealPath(context->storeMediaSrc, realPath)) {
4370         NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
4371         context->error = JS_ERR_NO_SUCH_FILE;
4372         return;
4373     }
4374     context->error = JS_E_RELATIVEPATH;
4375     int32_t srcFd = open(realPath.c_str(), O_RDWR);
4376     CHECK_IF_EQUAL(srcFd != -1, "src path open fail, %{public}d", errno);
4377     struct stat statSrc;
4378     if (fstat(srcFd, &statSrc) == -1) {
4379         close(srcFd);
4380         NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
4381         return;
4382     }
4383     string uriString;
4384     GetStoreMediaAssetUri(context, uriString);
4385     Uri createFileUri(uriString);
4386     int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
4387     if (index < 0) {
4388         close(srcFd);
4389         NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
4390         return;
4391     }
4392     SetFileAssetByIdV9(index, "", context);
4393     LogMedialibraryAPI(context->fileAsset->GetUri());
4394     CHECK_NULL_PTR_RETURN_VOID(context->fileAsset, "JSGetStoreMediaAssetExecute: context->fileAsset is nullptr");
4395     Uri openFileUri(context->fileAsset->GetUri());
4396     int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE);
4397     if (destFd < 0) {
4398         context->error = destFd;
4399         NAPI_DEBUG_LOG("File open asset failed");
4400         close(srcFd);
4401         return;
4402     }
4403     if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
4404         close(srcFd);
4405         close(destFd);
4406         CloseAsset(context, context->fileAsset->GetUri());
4407         NAPI_ERR_LOG("copy file fail %{public}d ", errno);
4408         return;
4409     }
4410     close(srcFd);
4411     close(destFd);
4412     CloseAsset(context, context->fileAsset->GetUri());
4413     context->error = ERR_DEFAULT;
4414 }
4415 
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4416 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
4417     MediaLibraryAsyncContext *context)
4418 {
4419     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4420     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4421     CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
4422     jsContext->status = false;
4423     napi_get_undefined(env, &jsContext->data);
4424     if (context->error != ERR_DEFAULT) {
4425         NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
4426         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4427             "storeMediaAsset fail");
4428     } else {
4429         napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4430         jsContext->status = true;
4431         napi_get_undefined(env, &jsContext->error);
4432     }
4433 
4434     if (context->work != nullptr) {
4435         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4436                                                    context->work, *jsContext);
4437     }
4438     delete context;
4439 }
4440 
ConvertMediaType(const string & mimeType)4441 static int ConvertMediaType(const string &mimeType)
4442 {
4443     string res;
4444     // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
4445     size_t slash = mimeType.find('/');
4446     if (slash != string::npos) {
4447         res = mimeType.substr(0, slash);
4448         if (res.empty()) {
4449             return MediaType::MEDIA_TYPE_FILE;
4450         }
4451     }
4452     if (res == "image") {
4453         return MediaType::MEDIA_TYPE_IMAGE;
4454     } else if (res == "video") {
4455         return MediaType::MEDIA_TYPE_VIDEO;
4456     } else if (res == "audio") {
4457         return MediaType::MEDIA_TYPE_AUDIO;
4458     }
4459     return MediaType::MEDIA_TYPE_FILE;
4460 }
4461 
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)4462 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
4463 {
4464     napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
4465     if (value == nullptr) {
4466         NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
4467         return false;
4468     }
4469     unique_ptr<char[]> tmp;
4470     bool succ;
4471     tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
4472     if (!succ) {
4473         NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
4474         return false;
4475     }
4476     res = string(tmp.get());
4477     return true;
4478 }
4479 
GetDefaultDirectory(int mediaType)4480 static string GetDefaultDirectory(int mediaType)
4481 {
4482     string relativePath;
4483     if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
4484         relativePath = "Pictures/";
4485     } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
4486         relativePath = "Videos/";
4487     } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
4488         relativePath = "Audios/";
4489     } else {
4490         relativePath = DOCS_PATH + DOC_DIR_VALUES;
4491     }
4492     return relativePath;
4493 }
4494 
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)4495 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
4496     MediaLibraryAsyncContext &asyncContext)
4497 {
4498     auto context = &asyncContext;
4499     if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
4500         NAPI_ERR_LOG("param get fail");
4501         return nullptr;
4502     }
4503     string fileName = MediaFileUtils::GetFileName(context->storeMediaSrc);
4504     if (fileName.empty() || (fileName.at(0) == '.')) {
4505         NAPI_ERR_LOG("src file name is not proper");
4506         context->error = JS_E_RELATIVEPATH;
4507         return nullptr;
4508     };
4509     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
4510     string mimeType;
4511     if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
4512         NAPI_ERR_LOG("param get fail");
4513         return nullptr;
4514     }
4515     auto mediaType = ConvertMediaType(mimeType);
4516     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
4517     string relativePath;
4518     if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
4519         NAPI_DEBUG_LOG("optional relativePath param empty");
4520         relativePath = GetDefaultDirectory(mediaType);
4521     }
4522     relativePath = MediaFileUtils::AddDocsToRelativePath(relativePath);
4523     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
4524     NAPI_DEBUG_LOG("src:%{private}s mime:%{private}s relp:%{private}s filename:%{private}s",
4525         context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
4526     napi_value result = nullptr;
4527     napi_get_undefined(env, &result);
4528     return result;
4529 }
4530 
JSStoreMediaAsset(napi_env env,napi_callback_info info)4531 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
4532 {
4533     size_t argc = ARGS_TWO;
4534     napi_value argv[ARGS_TWO] = {0};
4535     napi_value thisVar = nullptr;
4536     GET_JS_ARGS(env, info, argc, argv, thisVar);
4537     napi_value result = nullptr;
4538     napi_get_undefined(env, &result);
4539     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4540     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4541     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4542     if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
4543         napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
4544         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
4545         if (argc == ARGS_TWO) {
4546             const int32_t refCount = 1;
4547             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4548         }
4549         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4550         napi_value resource = nullptr;
4551         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
4552         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4553                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4554                 JSGetStoreMediaAssetExecute(context);
4555             },
4556             reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
4557             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4558         if (status != napi_ok) {
4559             napi_get_undefined(env, &result);
4560         } else {
4561             napi_queue_async_work(env, asyncContext->work);
4562             asyncContext.release();
4563         }
4564     }
4565     return result;
4566 }
4567 
CreateAsyncCallbackInfo(napi_env env)4568 static Ability *CreateAsyncCallbackInfo(napi_env env)
4569 {
4570     if (env == nullptr) {
4571         NAPI_ERR_LOG("env == nullptr.");
4572         return nullptr;
4573     }
4574     napi_status ret;
4575     napi_value global = 0;
4576     const napi_extended_error_info *errorInfo = nullptr;
4577     ret = napi_get_global(env, &global);
4578     if (ret != napi_ok) {
4579         napi_get_last_error_info(env, &errorInfo);
4580         NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
4581     }
4582     napi_value abilityObj = 0;
4583     ret = napi_get_named_property(env, global, "ability", &abilityObj);
4584     if (ret != napi_ok) {
4585         napi_get_last_error_info(env, &errorInfo);
4586         NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
4587     }
4588     Ability *ability = nullptr;
4589     ret = napi_get_value_external(env, abilityObj, (void **)&ability);
4590     if (ret != napi_ok) {
4591         napi_get_last_error_info(env, &errorInfo);
4592         NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
4593     }
4594     return ability;
4595 }
4596 
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4597 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4598 {
4599     uint32_t arraySize = 0;
4600     if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
4601         NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
4602         return nullptr;
4603     }
4604     string uri = "";
4605     for (uint32_t i = 0; i < arraySize; i++) {
4606         napi_value jsValue = nullptr;
4607         if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
4608             NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
4609             return nullptr;
4610         }
4611         unique_ptr<char[]> inputStr;
4612         bool succ;
4613         tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
4614         if (!succ) {
4615             NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
4616             return nullptr;
4617         }
4618         uri += MediaLibraryNapiUtils::TransferUri(string(inputStr.get()));
4619         uri += "?";
4620     }
4621     context.uri = uri.substr(0, uri.length() - 1);
4622     NAPI_DEBUG_LOG("GetImagePreviewArgs res %{private}s", context.uri.c_str());
4623     napi_value res;
4624     napi_get_undefined(env, &res);
4625     return res;
4626 }
4627 
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4628 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4629 {
4630     context.imagePreviewIndex = 0;
4631     napi_valuetype valueType = napi_undefined;
4632     napi_typeof(env, param, &valueType);
4633     if (valueType != napi_number) {
4634         NAPI_ERR_LOG("not napi value");
4635         return nullptr;
4636     }
4637     if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
4638         NAPI_ERR_LOG("get property value fail");
4639     }
4640     NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
4641     napi_value res;
4642     napi_get_undefined(env, &res);
4643     return res;
4644 }
4645 
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)4646 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
4647 {
4648     if (context->ability_ == nullptr) {
4649         NAPI_ERR_LOG("ability_ is not exist");
4650         context->error = ERR_INVALID_OUTPUT;
4651         return;
4652     }
4653     Want want;
4654     want.SetType("image/jpeg");
4655     want.SetAction("ohos.want.action.viewData");
4656     want.SetUri(context->uri);
4657     want.SetParam("viewIndex", context->imagePreviewIndex + 1);
4658     context->error = context->ability_->StartAbility(want);
4659 }
4660 
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4661 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
4662     MediaLibraryAsyncContext *context)
4663 {
4664     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4665     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4666     CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
4667     jsContext->status = true;
4668     napi_get_undefined(env, &jsContext->data);
4669     if (context->error != 0) {
4670         jsContext->status = false;
4671         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4672             "startImagePreview currently fail");
4673     }
4674     if (context->work != nullptr) {
4675         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4676                                                    context->work, *jsContext);
4677     }
4678     delete context;
4679 }
4680 
JSStartImagePreview(napi_env env,napi_callback_info info)4681 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
4682 {
4683     size_t argc = ARGS_THREE;
4684     napi_value argv[ARGS_THREE] = {0};
4685     napi_value thisVar = nullptr;
4686     GET_JS_ARGS(env, info, argc, argv, thisVar);
4687     napi_value result = nullptr;
4688     napi_get_undefined(env, &result);
4689     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4690     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4691     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4692     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4693         napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
4694         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
4695         GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
4696         asyncContext->ability_ = CreateAsyncCallbackInfo(env);
4697         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
4698         const int32_t refCount = 1;
4699         if (argc == ARGS_THREE) {
4700             GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
4701         } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
4702             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4703         }
4704         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4705         napi_value resource = nullptr;
4706         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
4707         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4708                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4709                 JSStartImagePreviewExecute(context);
4710             },
4711             reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
4712             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4713         if (status != napi_ok) {
4714             napi_get_undefined(env, &result);
4715         } else {
4716             napi_queue_async_work(env, asyncContext->work);
4717             asyncContext.release();
4718         }
4719     }
4720     return result;
4721 }
4722 
CheckCreateOption(MediaLibraryAsyncContext & context)4723 static napi_status CheckCreateOption(MediaLibraryAsyncContext &context)
4724 {
4725     bool isValid = false;
4726     int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
4727     string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
4728     if (isValid) {
4729         if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
4730             NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
4731             return napi_invalid_arg;
4732         }
4733         if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
4734             NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
4735             return napi_invalid_arg;
4736         } else {
4737             context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
4738         }
4739     }
4740 
4741     return napi_ok;
4742 }
4743 
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4744 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4745 {
4746     for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
4747         string param = iter.first;
4748         bool present = false;
4749         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4750         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4751         if (!present) {
4752             continue;
4753         }
4754         napi_value value;
4755         result = napi_get_named_property(env, arg, param.c_str(), &value);
4756         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
4757         napi_valuetype valueType = napi_undefined;
4758         result = napi_typeof(env, value, &valueType);
4759         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
4760         if (valueType == napi_number) {
4761             int32_t number = 0;
4762             result = napi_get_value_int32(env, value, &number);
4763             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
4764             context.valuesBucket.Put(iter.second, number);
4765         } else if (valueType == napi_boolean) {
4766             bool isTrue = false;
4767             result = napi_get_value_bool(env, value, &isTrue);
4768             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
4769             context.valuesBucket.Put(iter.second, isTrue);
4770         } else if (valueType == napi_string) {
4771             char buffer[ARG_BUF_SIZE];
4772             size_t res = 0;
4773             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
4774             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
4775             context.valuesBucket.Put(iter.second, string(buffer));
4776         } else if (valueType == napi_undefined || valueType == napi_null) {
4777             continue;
4778         } else {
4779             NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
4780             return napi_invalid_arg;
4781         }
4782     }
4783 
4784     return CheckCreateOption(context);
4785 }
4786 
ParseCreateOptions(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4787 static napi_status ParseCreateOptions(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4788 {
4789     for (const auto &iter : CREATE_OPTIONS_PARAM) {
4790         string param = iter.first;
4791         bool present = false;
4792         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4793         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4794         if (!present) {
4795             continue;
4796         }
4797         napi_value value;
4798         result = napi_get_named_property(env, arg, param.c_str(), &value);
4799         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
4800         napi_valuetype valueType = napi_undefined;
4801         result = napi_typeof(env, value, &valueType);
4802         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
4803         if (valueType == napi_number) {
4804             int32_t number = 0;
4805             result = napi_get_value_int32(env, value, &number);
4806             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
4807             context.valuesBucket.Put(iter.second, number);
4808         } else if (valueType == napi_boolean) {
4809             bool isTrue = false;
4810             result = napi_get_value_bool(env, value, &isTrue);
4811             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
4812             context.valuesBucket.Put(iter.second, isTrue);
4813         } else if (valueType == napi_string) {
4814             char buffer[ARG_BUF_SIZE];
4815             size_t res = 0;
4816             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
4817             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
4818             context.valuesBucket.Put(iter.second, string(buffer));
4819         } else if (valueType == napi_undefined || valueType == napi_null) {
4820             continue;
4821         } else {
4822             NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
4823                 static_cast<int>(valueType));
4824             return napi_invalid_arg;
4825         }
4826     }
4827 
4828     return napi_ok;
4829 }
4830 
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4831 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
4832     unique_ptr<MediaLibraryAsyncContext> &context)
4833 {
4834     /* Parse the first argument into displayName */
4835     napi_valuetype valueType;
4836     MediaType mediaType;
4837     string displayName;
4838     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
4839         napi_ok, "Failed to get displayName");
4840     mediaType = MediaFileUtils::GetMediaType(displayName);
4841     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
4842     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
4843 
4844     /* Parse the second argument into albumUri if exists */
4845     string albumUri;
4846     if ((context->argc >= ARGS_TWO)) {
4847         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
4848         if (valueType == napi_string) {
4849             if (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok) {
4850                 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
4851             }
4852         } else if (valueType == napi_object) {
4853             NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
4854                 "Parse asset create option failed");
4855         }
4856     }
4857 
4858     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4859     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
4860 
4861     napi_value result = nullptr;
4862     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4863     return result;
4864 }
4865 
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4866 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
4867     unique_ptr<MediaLibraryAsyncContext> &context)
4868 {
4869     /* Parse the first argument into displayName */
4870     napi_valuetype valueType;
4871     MediaType mediaType;
4872     int32_t type = 0;
4873     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
4874         "Failed to get type value");
4875     mediaType = static_cast<MediaType>(type);
4876     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
4877 
4878     /* Parse the second argument into albumUri if exists */
4879     string extension;
4880     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extension) ==
4881         napi_ok, "Failed to get extension");
4882     CHECK_COND_WITH_MESSAGE(env, mediaType == MediaFileUtils::GetMediaType("." + extension),
4883         "Failed to check extension");
4884     context->valuesBucket.Put(ASSET_EXTENTION, extension);
4885 
4886     /* Parse the third argument into albumUri if exists */
4887     if (context->argc >= ARGS_THREE) {
4888         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
4889         if (valueType == napi_object) {
4890             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
4891                 "Parse asset create option failed");
4892         } else if (valueType != napi_function) {
4893             NAPI_ERR_LOG("Napi type is wrong in create options");
4894             return nullptr;
4895         }
4896     }
4897 
4898     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
4899 
4900     napi_value result = nullptr;
4901     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4902     return result;
4903 }
4904 
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4905 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
4906     unique_ptr<MediaLibraryAsyncContext> &context)
4907 {
4908     constexpr size_t minArgs = ARGS_ONE;
4909     constexpr size_t maxArgs = ARGS_FOUR;
4910     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
4911         napi_ok, "Failed to get object info");
4912 
4913     napi_valuetype valueType;
4914     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
4915     if (valueType == napi_string) {
4916         context->isCreateByComponent = false;
4917         if (!MediaLibraryNapiUtils::IsSystemApp()) {
4918             NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4919             return nullptr;
4920         }
4921         return ParseArgsCreatePhotoAssetSystem(env, info, context);
4922     } else if (valueType == napi_number) {
4923         context->isCreateByComponent = true;
4924         return ParseArgsCreatePhotoAssetComponent(env, info, context);
4925     } else {
4926         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
4927         return nullptr;
4928     }
4929 }
4930 
ParseArgsGrantPhotoUriPermissionInner(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4931 static napi_value ParseArgsGrantPhotoUriPermissionInner(napi_env env, napi_callback_info info,
4932     unique_ptr<MediaLibraryAsyncContext> &context)
4933 {
4934     // parse appid
4935     string appid;
4936     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], appid) ==
4937         napi_ok, "Failed to get appid");
4938     if (appid.empty()) {
4939         NAPI_ERR_LOG("appid is empty");
4940         return nullptr;
4941     }
4942     context->valuesBucket.Put(AppUriPermissionColumn::APP_ID, appid);
4943 
4944     // parse fileId
4945     string uri;
4946     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], uri) ==
4947         napi_ok, "Failed to get uri");
4948     int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
4949     if (fileId < 0) {
4950         return nullptr;
4951     }
4952     context->valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
4953 
4954     // parse permissionType
4955     int32_t permissionType;
4956     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_TWO], permissionType) ==
4957         napi_ok, "Failed to get permissionType");
4958     if (AppUriPermissionColumn::PERMISSION_TYPES_PICKER.find((int)permissionType) ==
4959         AppUriPermissionColumn::PERMISSION_TYPES_PICKER.end()) {
4960         NAPI_ERR_LOG("invalid picker permissionType, permissionType=%{public}d", permissionType);
4961         return nullptr;
4962     }
4963     context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
4964 
4965     // parse hideSensitiveType
4966     int32_t hideSensitiveType;
4967     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_THREE], hideSensitiveType) ==
4968         napi_ok, "Failed to get hideSensitiveType");
4969     if (AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.find((int)hideSensitiveType) ==
4970         AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.end()) {
4971         NAPI_ERR_LOG("invalid picker hideSensitiveType, hideSensitiveType=%{public}d", permissionType);
4972         return nullptr;
4973     }
4974     context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
4975 
4976     // parsing fileId ensured uri is photo.
4977     context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
4978 
4979     napi_value result = nullptr;
4980     NAPI_CALL(env, napi_get_boolean(env, true, &result));
4981     return result;
4982 }
4983 
ParseArgsGrantPhotoUriPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)4984 static napi_value ParseArgsGrantPhotoUriPermission(napi_env env, napi_callback_info info,
4985     unique_ptr<MediaLibraryAsyncContext> &context)
4986 {
4987     constexpr size_t minArgs = ARGS_ONE;
4988     constexpr size_t maxArgs = ARGS_FOUR;
4989     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
4990         napi_ok, "Failed to get object info");
4991 
4992     context->isCreateByComponent = false;
4993     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4994         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4995         return nullptr;
4996     }
4997 
4998     return ParseArgsGrantPhotoUriPermissionInner(env, info, context);
4999 }
5000 
ParseUriTypes(std::string & appid,int & permissionType,int & sensitiveType,std::vector<std::string> & uris,unique_ptr<MediaLibraryAsyncContext> & context)5001 static bool ParseUriTypes(std::string &appid, int &permissionType, int &sensitiveType, std::vector<std::string> &uris,
5002     unique_ptr<MediaLibraryAsyncContext> &context)
5003 {
5004     // used for deduplication
5005     std::set<int32_t> fileIdSet;
5006     for (const auto &uri : uris) {
5007         OHOS::DataShare::DataShareValuesBucket valuesBucket;
5008         int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5009         if (fileId < 0) {
5010             return false;
5011         }
5012         if (fileIdSet.find(fileId) != fileIdSet.end()) {
5013             continue;
5014         }
5015         fileIdSet.insert(fileId);
5016         valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5017         valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5018         valuesBucket.Put(AppUriPermissionColumn::APP_ID, appid);
5019         valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, sensitiveType);
5020         // parsing fileId ensured uri is photo.
5021         valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5022         context->valuesBucketArray.push_back(move(valuesBucket));
5023     }
5024     return true;
5025 }
5026 
ParseArgsGrantPhotoUrisPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5027 static napi_value ParseArgsGrantPhotoUrisPermission(napi_env env, napi_callback_info info,
5028     unique_ptr<MediaLibraryAsyncContext> &context)
5029 {
5030     constexpr size_t minArgs = ARGS_ONE;
5031     constexpr size_t maxArgs = ARGS_FOUR;
5032     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5033         napi_ok, "Failed to get object info");
5034 
5035     context->isCreateByComponent = false;
5036     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5037         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5038         return nullptr;
5039     }
5040     // parse appid
5041     string appid;
5042     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], appid) ==
5043         napi_ok, "Failed to get appid");
5044     if (appid.empty()) {
5045         NAPI_ERR_LOG("appid is empty");
5046         return nullptr;
5047     }
5048 
5049     // parse uris
5050     vector<string> uris;
5051     CHECK_ARGS(env, MediaLibraryNapiUtils::GetStringArray(env, context->argv[ARGS_ONE], uris),
5052         JS_ERR_PARAMETER_INVALID);
5053     constexpr size_t urisMaxSize = 1000;
5054     if (uris.empty() || uris.size() > urisMaxSize) {
5055         NAPI_ERR_LOG("the size of uriList is invalid");
5056         return nullptr;
5057     }
5058 
5059     // parse permissionType
5060     int32_t permissionType;
5061     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_TWO], permissionType) ==
5062         napi_ok, "Failed to get permissionType");
5063     if (AppUriPermissionColumn::PERMISSION_TYPES_PICKER.find((int)permissionType) ==
5064         AppUriPermissionColumn::PERMISSION_TYPES_PICKER.end()) {
5065         NAPI_ERR_LOG("invalid picker permissionType, permissionType=%{public}d", permissionType);
5066         return nullptr;
5067     }
5068 
5069     // parse hideSensitiveType
5070     int32_t hideSensitiveType;
5071     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_THREE], hideSensitiveType) ==
5072         napi_ok, "Failed to get hideSensitiveType");
5073     if (AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.find((int)hideSensitiveType) ==
5074         AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.end()) {
5075         NAPI_ERR_LOG("invalid picker hideSensitiveType, hideSensitiveType=%{public}d", permissionType);
5076         return nullptr;
5077     }
5078 
5079     if (!ParseUriTypes(appid, permissionType, hideSensitiveType, uris, context)) {
5080         return nullptr;
5081     }
5082 
5083     napi_value result = nullptr;
5084     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5085     return result;
5086 }
5087 
ParseArgsCancelPhotoUriPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5088 static napi_value ParseArgsCancelPhotoUriPermission(napi_env env, napi_callback_info info,
5089     unique_ptr<MediaLibraryAsyncContext> &context)
5090 {
5091     constexpr size_t minArgs = ARGS_ONE;
5092     constexpr size_t maxArgs = ARGS_THREE;
5093     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5094         napi_ok, "Failed to get object info");
5095 
5096     context->isCreateByComponent = false;
5097     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5098         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5099         return nullptr;
5100     }
5101     // parse appid
5102     string appid;
5103     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], appid) ==
5104         napi_ok, "Failed to get appid");
5105     if (appid.empty()) {
5106         NAPI_ERR_LOG("appid is empty");
5107         return nullptr;
5108     }
5109     context->predicates.And()->EqualTo(AppUriPermissionColumn::APP_ID, appid);
5110 
5111     // parse fileId
5112     string uri;
5113     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], uri) ==
5114         napi_ok, "Failed to get uri");
5115     int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5116     if (fileId < 0) {
5117         return nullptr;
5118     }
5119     context->predicates.And()->EqualTo(AppUriPermissionColumn::FILE_ID, fileId);
5120 
5121     // parse permissionType
5122     int32_t permissionType;
5123     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_TWO], permissionType) ==
5124         napi_ok, "Failed to get permissionType");
5125     if (AppUriPermissionColumn::PERMISSION_TYPES_PICKER.find((int)permissionType) ==
5126             AppUriPermissionColumn::PERMISSION_TYPES_PICKER.end()) {
5127         NAPI_ERR_LOG("invalid picker permissionType, permissionType=%{public}d", permissionType);
5128         return nullptr;
5129     }
5130     context->predicates.And()->EqualTo(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5131 
5132     // parsing fileId ensured uri is photo.
5133     context->predicates.And()->EqualTo(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5134 
5135     napi_value result = nullptr;
5136     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5137     return result;
5138 }
5139 
ParseCreateConfig(napi_env env,napi_value arg,BundleInfo bundleInfo,MediaLibraryAsyncContext & context)5140 static napi_status ParseCreateConfig(napi_env env, napi_value arg,
5141     BundleInfo bundleInfo, MediaLibraryAsyncContext &context)
5142 {
5143     const std::map<std::string, std::string> PHOTO_CREATE_CONFIG_PARAM = {
5144         { PHOTO_TYPE, MEDIA_DATA_DB_MEDIA_TYPE },
5145         { PHOTO_SUB_TYPE, PhotoColumn::PHOTO_SUBTYPE },
5146         { TITLE, MediaColumn::MEDIA_TITLE },
5147         { EXTENSION, ASSET_EXTENTION }
5148     };
5149 
5150     OHOS::DataShare::DataShareValuesBucket valuesBucket;
5151     for (const auto &iter : PHOTO_CREATE_CONFIG_PARAM) {
5152         string param = iter.first;
5153         bool present = false;
5154         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
5155         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
5156         if (!present) {
5157             continue;
5158         }
5159         napi_value value;
5160         result = napi_get_named_property(env, arg, param.c_str(), &value);
5161         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5162         napi_valuetype valueType = napi_undefined;
5163         result = napi_typeof(env, value, &valueType);
5164         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5165         if (valueType == napi_number) {
5166             int32_t number = 0;
5167             result = napi_get_value_int32(env, value, &number);
5168             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5169             valuesBucket.Put(iter.second, number);
5170         } else if (valueType == napi_string) {
5171             char buffer[ARG_BUF_SIZE];
5172             size_t res = 0;
5173             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5174             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5175             string bufferString(buffer);
5176             if (!bufferString.empty()) {
5177                 valuesBucket.Put(iter.second, bufferString);
5178             }
5179         } else if (valueType == napi_undefined || valueType == napi_null) {
5180             continue;
5181         } else {
5182             NAPI_ERR_LOG("ParseCreateConfig failed, valueType %{public}d is unaccepted",
5183                 static_cast<int>(valueType));
5184             return napi_invalid_arg;
5185         }
5186     }
5187     valuesBucket.Put(MEDIA_DATA_DB_OWNER_PACKAGE, bundleInfo.bundleName);
5188     valuesBucket.Put(MEDIA_DATA_DB_OWNER_APPID, bundleInfo.appId);
5189     valuesBucket.Put(MEDIA_DATA_DB_PACKAGE_NAME, bundleInfo.packageName);
5190     context.valuesBucketArray.push_back(move(valuesBucket));
5191     return napi_ok;
5192 }
5193 
ParseArgsCreateAgentCreateAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5194 static napi_value ParseArgsCreateAgentCreateAssets(napi_env env, napi_callback_info info,
5195     unique_ptr<MediaLibraryAsyncContext> &context)
5196 {
5197     /* Parse the arguments */
5198     BundleInfo bundleInfo;
5199     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO],
5200         bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
5201     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
5202         bundleInfo.packageName) == napi_ok, "Failed to get appName");
5203     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_TWO],
5204         bundleInfo.appId) == napi_ok, "Failed to get appId");
5205 
5206     napi_value result = nullptr;
5207     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5208 
5209     vector<napi_value> napiValues;
5210     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_THREE], napiValues));
5211     if (napiValues.empty()) {
5212         return result;
5213     }
5214 
5215     for (const auto& napiValue : napiValues) {
5216         CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context) == napi_ok,
5217             "Parse asset create config failed");
5218     }
5219 
5220     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
5221         == napi_ok, "Failed to get callback");
5222     return result;
5223 }
5224 
ParseArgsAgentCreateAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5225 static napi_value ParseArgsAgentCreateAssets(napi_env env, napi_callback_info info,
5226     unique_ptr<MediaLibraryAsyncContext> &context)
5227 {
5228     constexpr size_t minArgs = ARGS_FOUR;
5229     constexpr size_t maxArgs = ARGS_FOUR;
5230     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5231         napi_ok, "Failed to get object info");
5232 
5233     context->isCreateByComponent = false;
5234     context->isCreateByAgent = true;
5235 
5236     return ParseArgsCreateAgentCreateAssets(env, info, context);
5237 }
5238 
ParseArgsCreateAudioAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5239 static napi_value ParseArgsCreateAudioAssetSystem(napi_env env, napi_callback_info info,
5240     unique_ptr<MediaLibraryAsyncContext> &context)
5241 {
5242     /* Parse the first argument into displayName */
5243     string displayName;
5244     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
5245         napi_ok, "Failed to get displayName");
5246 
5247     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_AUDIO);
5248     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
5249 
5250     napi_value result = nullptr;
5251     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5252     return result;
5253 }
5254 
ParseArgsCreateAudioAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5255 static napi_value ParseArgsCreateAudioAssetComponent(napi_env env, napi_callback_info info,
5256     unique_ptr<MediaLibraryAsyncContext> &context)
5257 {
5258     /* Parse the first argument into displayName */
5259     napi_valuetype valueType;
5260     MediaType mediaType;
5261     int32_t type = 0;
5262     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
5263         "Failed to get type value");
5264     mediaType = static_cast<MediaType>(type);
5265     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_AUDIO), "invalid file type");
5266 
5267     /* Parse the second argument into albumUri if exists */
5268     string extention;
5269     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
5270         napi_ok, "Failed to get extention");
5271     context->valuesBucket.Put(ASSET_EXTENTION, extention);
5272 
5273     /* Parse the third argument into albumUri if exists */
5274     if (context->argc >= ARGS_THREE) {
5275         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
5276         if (valueType == napi_object) {
5277             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
5278                 "Parse asset create option failed");
5279         } else if (valueType != napi_function) {
5280             NAPI_ERR_LOG("Napi type is wrong in create options");
5281             return nullptr;
5282         }
5283     }
5284 
5285     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5286     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
5287 
5288     napi_value result = nullptr;
5289     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5290     return result;
5291 }
5292 
ParseArgsCreateAudioAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5293 static napi_value ParseArgsCreateAudioAsset(napi_env env, napi_callback_info info,
5294     unique_ptr<MediaLibraryAsyncContext> &context)
5295 {
5296     constexpr size_t minArgs = ARGS_ONE;
5297     constexpr size_t maxArgs = ARGS_FOUR;
5298     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5299         napi_ok, "Failed to get object info");
5300 
5301     napi_valuetype valueType;
5302     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
5303     if (valueType == napi_string) {
5304         context->isCreateByComponent = false;
5305         return ParseArgsCreateAudioAssetSystem(env, info, context);
5306     } else if (valueType == napi_number) {
5307         context->isCreateByComponent = true;
5308         return ParseArgsCreateAudioAssetComponent(env, info, context);
5309     } else {
5310         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5311         return nullptr;
5312     }
5313 }
5314 
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5315 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
5316     unique_ptr<MediaLibraryAsyncContext> &context)
5317 {
5318     constexpr size_t minArgs = ARGS_ONE;
5319     constexpr size_t maxArgs = ARGS_TWO;
5320     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5321         JS_ERR_PARAMETER_INVALID);
5322 
5323     /* Parse the first argument */
5324     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
5325         JS_INNER_FAIL);
5326     auto &predicates = context->predicates;
5327     switch (context->assetType) {
5328         case TYPE_AUDIO: {
5329             CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5330                 AudioColumn::IsAudioColumn, TYPE_AUDIO));
5331             break;
5332         }
5333         case TYPE_PHOTO: {
5334             CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5335                 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
5336             break;
5337         }
5338         default: {
5339             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5340             return nullptr;
5341         }
5342     }
5343     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
5344     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5345     if (context->assetType == TYPE_PHOTO) {
5346         predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
5347         predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
5348         predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
5349             to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
5350     }
5351 
5352     napi_value result = nullptr;
5353     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5354     return result;
5355 }
5356 
ParseArgsGetBurstAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5357 static napi_value ParseArgsGetBurstAssets(napi_env env, napi_callback_info info,
5358     unique_ptr<MediaLibraryAsyncContext> &context)
5359 {
5360     constexpr size_t minArgs = ARGS_ONE;
5361     constexpr size_t maxArgs = ARGS_TWO;
5362     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5363         OHOS_INVALID_PARAM_CODE);
5364 
5365     /* Parse the first argument */
5366     std::string burstKey;
5367     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], burstKey),
5368         OHOS_INVALID_PARAM_CODE);
5369     if (burstKey.empty()) {
5370         NAPI_ERR_LOG("The input burstkey cannot be empty");
5371         return nullptr;
5372     }
5373     /* Parse the second argument */
5374     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ASSET_FETCH_OPT, context),
5375         JS_INNER_FAIL);
5376 
5377     auto &predicates = context->predicates;
5378     if (context->assetType != TYPE_PHOTO) {
5379         return nullptr;
5380     }
5381     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5382         PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
5383     predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_KEY, burstKey);
5384     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5385     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
5386     predicates.OrderByAsc(MediaColumn::MEDIA_NAME);
5387 
5388     napi_value result = nullptr;
5389     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5390     return result;
5391 }
5392 
ParseArgsIndexUri(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,string & uri,string & albumUri)5393 static napi_status ParseArgsIndexUri(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, string &uri,
5394     string &albumUri)
5395 {
5396     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], uri),
5397         "Failed to get first string argument");
5398     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri),
5399         "Failed to get second string argument");
5400     return napi_ok;
5401 }
5402 
ParseArgsIndexof(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5403 static napi_value ParseArgsIndexof(napi_env env, napi_callback_info info,
5404     unique_ptr<MediaLibraryAsyncContext> &context)
5405 {
5406     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5407         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5408         return nullptr;
5409     }
5410 
5411     constexpr size_t minArgs = ARGS_THREE;
5412     constexpr size_t maxArgs = ARGS_FOUR;
5413     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5414         JS_ERR_PARAMETER_INVALID);
5415 
5416     string uri;
5417     string album;
5418     CHECK_ARGS(env, ParseArgsIndexUri(env, context, uri, album), JS_INNER_FAIL);
5419     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM2], ASSET_FETCH_OPT, context),
5420         JS_INNER_FAIL);
5421     auto &predicates = context->predicates;
5422     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
5423     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5424     predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
5425     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
5426     predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
5427         to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
5428 
5429     context->fetchColumn.clear();
5430     MediaFileUri photoUri(uri);
5431     CHECK_COND(env, photoUri.GetUriType() == API10_PHOTO_URI, JS_ERR_PARAMETER_INVALID);
5432     context->fetchColumn.emplace_back(photoUri.GetFileId());
5433     if (!album.empty()) {
5434         MediaFileUri albumUri(album);
5435         CHECK_COND(env, albumUri.GetUriType() == API10_PHOTOALBUM_URI ||
5436             albumUri.GetUriType() == API10_ANALYSISALBUM_URI, JS_ERR_PARAMETER_INVALID);
5437         context->isAnalysisAlbum = (albumUri.GetUriType() == API10_ANALYSISALBUM_URI);
5438         context->fetchColumn.emplace_back(albumUri.GetFileId());
5439     } else {
5440         context->fetchColumn.emplace_back(album);
5441     }
5442     napi_value result = nullptr;
5443     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5444     return result;
5445 }
5446 
JSGetAssetsExecute(napi_env env,void * data)5447 static void JSGetAssetsExecute(napi_env env, void *data)
5448 {
5449     MediaLibraryTracer tracer;
5450     tracer.Start("JSGetAssetsExecute");
5451 
5452     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5453     string queryUri;
5454     switch (context->assetType) {
5455         case TYPE_AUDIO: {
5456             queryUri = UFM_QUERY_AUDIO;
5457             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5458             break;
5459         }
5460         case TYPE_PHOTO: {
5461             queryUri = UFM_QUERY_PHOTO;
5462             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5463             break;
5464         }
5465         default: {
5466             context->SaveError(-EINVAL);
5467             return;
5468         }
5469     }
5470 
5471     Uri uri(queryUri);
5472     int errCode = 0;
5473     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
5474         context->predicates, context->fetchColumn, errCode);
5475     if (resultSet == nullptr) {
5476         context->SaveError(errCode);
5477         return;
5478     }
5479     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
5480     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
5481 }
5482 
GetPhotoIndexAsyncCallbackComplete(napi_env env,napi_status status,void * data)5483 static void GetPhotoIndexAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5484 {
5485     MediaLibraryTracer tracer;
5486     tracer.Start("GetPhotoIndexAsyncCallbackComplete");
5487 
5488     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5489     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5490 
5491     auto jsContext = make_unique<JSAsyncContextOutput>();
5492     jsContext->status = false;
5493     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
5494     if (context->error != ERR_DEFAULT) {
5495         context->HandleError(env, jsContext->error);
5496     } else {
5497         int32_t count = -1;
5498         if (context->fetchFileResult != nullptr) {
5499             auto fileAsset = context->fetchFileResult->GetFirstObject();
5500             if (fileAsset != nullptr) {
5501                 count = fileAsset->GetPhotoIndex();
5502             }
5503         }
5504         jsContext->status = true;
5505         napi_create_int32(env, count, &jsContext->data);
5506     }
5507 
5508     tracer.Finish();
5509     if (context->work != nullptr) {
5510         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5511                                                    context->work, *jsContext);
5512     }
5513     delete context;
5514 }
5515 
GetPhotoIndexExec(napi_env env,void * data,ResultNapiType type)5516 static void GetPhotoIndexExec(napi_env env, void *data, ResultNapiType type)
5517 {
5518     MediaLibraryTracer tracer;
5519     tracer.Start("JsGetPhotoIndexExec");
5520     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5521     string queryUri = context->isAnalysisAlbum ? PAH_GET_ANALYSIS_INDEX : UFM_GET_INDEX;
5522     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5523     Uri uri(queryUri);
5524     int errCode = 0;
5525     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
5526     if (resultSet == nullptr) {
5527         context->SaveError(errCode);
5528         return;
5529     }
5530     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
5531     context->fetchFileResult->SetResultNapiType(type);
5532 }
5533 
PhotoAccessGetPhotoIndexExec(napi_env env,void * data)5534 static void PhotoAccessGetPhotoIndexExec(napi_env env, void *data)
5535 {
5536     GetPhotoIndexExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
5537 }
5538 
JsGetPhotoIndexExec(napi_env env,void * data)5539 static void JsGetPhotoIndexExec(napi_env env, void *data)
5540 {
5541     GetPhotoIndexExec(env, data, ResultNapiType::TYPE_USERFILE_MGR);
5542 }
5543 
JSGetPhotoIndex(napi_env env,napi_callback_info info)5544 napi_value MediaLibraryNapi::JSGetPhotoIndex(napi_env env, napi_callback_info info)
5545 {
5546     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5547     CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
5548     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
5549         JsGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
5550 }
5551 
PhotoAccessGetPhotoIndex(napi_env env,napi_callback_info info)5552 napi_value MediaLibraryNapi::PhotoAccessGetPhotoIndex(napi_env env, napi_callback_info info)
5553 {
5554     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5555     CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
5556     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
5557         PhotoAccessGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
5558 }
5559 
GetIndexConstructProgressAsyncCallbackComplete(napi_env env,napi_status status,void * data)5560 static void GetIndexConstructProgressAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5561 {
5562     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5563     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5564     auto jsContext = make_unique<JSAsyncContextOutput>();
5565     jsContext->status = false;
5566 
5567     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
5568     if (context->error != ERR_DEFAULT) {
5569         context->HandleError(env, jsContext->error);
5570     } else {
5571         CHECK_ARGS_RET_VOID(
5572             env, napi_create_string_utf8(env, context->indexProgress.c_str(), NAPI_AUTO_LENGTH, &jsContext->data),
5573             JS_INNER_FAIL);
5574         jsContext->status = true;
5575     }
5576 
5577     if (context->work != nullptr) {
5578         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5579             context->work, *jsContext);
5580     }
5581     delete context;
5582 }
5583 
GetProgressStr(const shared_ptr<DataShare::DataShareResultSet> & resultSet,string & progress)5584 static bool GetProgressStr(const shared_ptr<DataShare::DataShareResultSet> &resultSet, string &progress)
5585 {
5586     const vector<string> columns = {
5587         PHOTO_COMPLETE_NUM,
5588         PHOTO_TOTAL_NUM,
5589         VIDEO_COMPLETE_NUM,
5590         VIDEO_TOTAL_NUM
5591     };
5592     int32_t index = 0;
5593     string value = "";
5594     progress = "{";
5595     for (const auto &item : columns) {
5596         if (resultSet->GetColumnIndex(item, index) != DataShare::E_OK) {
5597             NAPI_ERR_LOG("ResultSet GetColumnIndex failed, progressObject=%{public}s", item.c_str());
5598             return false;
5599         }
5600         if (resultSet->GetString(index, value) != DataShare::E_OK) {
5601             NAPI_ERR_LOG("ResultSet GetString failed, progressObject=%{public}s", item.c_str());
5602             return false;
5603         }
5604         progress += "\"" + item + "\":" + value + ",";
5605     }
5606     progress = progress.substr(0, progress.length() - 1);
5607     progress += "}";
5608     NAPI_DEBUG_LOG("GetProgressStr progress=%{public}s", progress.c_str());
5609     return true;
5610 }
5611 
GetProgressFromResultSet(const shared_ptr<DataShare::DataShareResultSet> & resultSet,string & progress)5612 static bool GetProgressFromResultSet(const shared_ptr<DataShare::DataShareResultSet> &resultSet, string &progress)
5613 {
5614     if (resultSet == nullptr) {
5615         NAPI_ERR_LOG("ResultSet is null");
5616         return false;
5617     }
5618     int32_t count = 0;
5619     int32_t errCode = resultSet->GetRowCount(count);
5620     if (errCode != DataShare::E_OK) {
5621         NAPI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
5622         return false;
5623     }
5624     if (count == 0) {
5625         NAPI_ERR_LOG("Can not find index construction progress");
5626         return false;
5627     }
5628     errCode = resultSet->GoToFirstRow();
5629     if (errCode != DataShare::E_OK) {
5630         NAPI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
5631         return false;
5632     }
5633 
5634     return GetProgressStr(resultSet, progress);
5635 }
5636 
PhotoAccessGetIndexConstructProgressExec(napi_env env,void * data)5637 static void PhotoAccessGetIndexConstructProgressExec(napi_env env, void *data)
5638 {
5639     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5640     auto jsContext = make_unique<JSAsyncContextOutput>();
5641     jsContext->status = false;
5642     string queryUri = MEDIALIBRARY_DATA_URI + "/" + SEARCH_INDEX_CONSTRUCTION_STATUS + "/" + OPRN_QUERY;
5643     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5644     Uri uri(queryUri);
5645     int errCode = 0;
5646     string indexProgress;
5647     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
5648     if (!GetProgressFromResultSet(resultSet, indexProgress)) {
5649         if (errCode == E_PERMISSION_DENIED) {
5650             context->error = OHOS_PERMISSION_DENIED_CODE;
5651         } else {
5652             context->SaveError(E_FAIL);
5653         }
5654     } else {
5655         context->indexProgress = indexProgress;
5656     }
5657 }
5658 
PhotoAccessGetIndexConstructProgress(napi_env env,napi_callback_info info)5659 napi_value MediaLibraryNapi::PhotoAccessGetIndexConstructProgress(napi_env env, napi_callback_info info)
5660 {
5661     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5662         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5663         return nullptr;
5664     }
5665 
5666     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5667 
5668     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, 0, 0),
5669         JS_ERR_PARAMETER_INVALID);
5670 
5671     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetIndexConstructProgress",
5672         PhotoAccessGetIndexConstructProgressExec, GetIndexConstructProgressAsyncCallbackComplete);
5673 }
5674 
CheckFormId(string & formId)5675 static napi_status CheckFormId(string &formId)
5676 {
5677     if (formId.empty() || formId.length() > FORMID_MAX_LEN) {
5678         return napi_invalid_arg;
5679     }
5680     for (uint32_t i = 0; i < formId.length(); i++) {
5681         if (!isdigit(formId[i])) {
5682             return napi_invalid_arg;
5683         }
5684     }
5685     unsigned long long num = stoull(formId);
5686     if (num > MAX_INT64) {
5687         return napi_invalid_arg;
5688     }
5689     return napi_ok;
5690 }
5691 
ParseSaveFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)5692 static napi_status ParseSaveFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
5693 {
5694     const std::string formId = "formId";
5695     const std::string uri = "uri";
5696     const std::map<std::string, std::string> saveFormInfoOptionsParam = {
5697         { formId, FormMap::FORMMAP_FORM_ID },
5698         { uri, FormMap::FORMMAP_URI }
5699     };
5700     for (const auto &iter : saveFormInfoOptionsParam) {
5701         string param = iter.first;
5702         bool present = false;
5703         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
5704         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
5705         if (!present) {
5706             return napi_invalid_arg;
5707         }
5708         napi_value value;
5709         result = napi_get_named_property(env, arg, param.c_str(), &value);
5710         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5711         char buffer[ARG_BUF_SIZE];
5712         size_t res = 0;
5713         result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5714         CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5715         context.valuesBucket.Put(iter.second, string(buffer));
5716     }
5717     bool isValid = false;
5718     string tempFormId = context.valuesBucket.Get(FormMap::FORMMAP_FORM_ID, isValid);
5719     if (!isValid) {
5720         return napi_invalid_arg;
5721     }
5722     return CheckFormId(tempFormId);
5723 }
5724 
ParseArgsSaveFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5725 static napi_value ParseArgsSaveFormInfo(napi_env env, napi_callback_info info,
5726     unique_ptr<MediaLibraryAsyncContext> &context)
5727 {
5728     constexpr size_t minArgs = ARGS_ONE;
5729     constexpr size_t maxArgs = ARGS_TWO;
5730     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
5731         maxArgs) == napi_ok, "Failed to get object info");
5732 
5733     CHECK_COND_WITH_MESSAGE(env, ParseSaveFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
5734         "Parse formInfo Option failed");
5735 
5736     napi_value result = nullptr;
5737     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5738     return result;
5739 }
5740 
SaveFormInfoExec(napi_env env,void * data,ResultNapiType type)5741 static void SaveFormInfoExec(napi_env env, void *data, ResultNapiType type)
5742 {
5743     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5744     context->resultNapiType = type;
5745     string uri = PAH_STORE_FORM_MAP;
5746     Uri createFormIdUri(uri);
5747     auto ret = UserFileClient::Insert(createFormIdUri, context->valuesBucket);
5748     if (ret < 0) {
5749         if (ret == E_PERMISSION_DENIED) {
5750             context->error = OHOS_PERMISSION_DENIED_CODE;
5751         } else if (ret == E_GET_PRAMS_FAIL) {
5752             context->error = OHOS_INVALID_PARAM_CODE;
5753         } else {
5754             context->SaveError(ret);
5755         }
5756         NAPI_ERR_LOG("store formInfo failed, ret: %{public}d", ret);
5757     }
5758 }
5759 
SaveFormInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)5760 static void SaveFormInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5761 {
5762     MediaLibraryTracer tracer;
5763     tracer.Start("SaveFormInfoAsyncCallbackComplete");
5764 
5765     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5766     auto jsContext = make_unique<JSAsyncContextOutput>();
5767     jsContext->status = false;
5768     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5769     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5770     if (context->error != ERR_DEFAULT) {
5771         context->HandleError(env, jsContext->error);
5772     } else {
5773         jsContext->status = true;
5774     }
5775     tracer.Finish();
5776     if (context->work != nullptr) {
5777         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5778                                                    context->work, *jsContext);
5779     }
5780     delete context;
5781 }
5782 
ParseArgsRemoveFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5783 static napi_value ParseArgsRemoveFormInfo(napi_env env, napi_callback_info info,
5784     unique_ptr<MediaLibraryAsyncContext> &context)
5785 {
5786     constexpr size_t minArgs = ARGS_ONE;
5787     constexpr size_t maxArgs = ARGS_TWO;
5788     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
5789         maxArgs) == napi_ok, "Failed to get object info");
5790 
5791     bool present = false;
5792     CHECK_COND_WITH_MESSAGE(env, napi_has_named_property(env, context->argv[ARGS_ZERO], "formId", &present) == napi_ok,
5793         "Failed to get object info");
5794     if (!present) {
5795         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check empty formId!");
5796         return nullptr;
5797     }
5798 
5799     napi_value value;
5800     CHECK_COND_WITH_MESSAGE(env, napi_get_named_property(env, context->argv[ARGS_ZERO], "formId", &value) == napi_ok,
5801         "failed to get named property");
5802     char buffer[ARG_BUF_SIZE];
5803     size_t res = 0;
5804     CHECK_COND_WITH_MESSAGE(env, napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res) == napi_ok,
5805         "failed to get string param");
5806     context->formId = string(buffer);
5807     CHECK_COND_WITH_MESSAGE(env, CheckFormId(context->formId) == napi_ok, "FormId is invalid");
5808     napi_value result = nullptr;
5809     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5810     return result;
5811 }
5812 
RemoveFormInfoExec(napi_env env,void * data,ResultNapiType type)5813 static void RemoveFormInfoExec(napi_env env, void *data, ResultNapiType type)
5814 {
5815     MediaLibraryTracer tracer;
5816     tracer.Start("RemoveFormInfoExec");
5817 
5818     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5819     context->resultNapiType = type;
5820     string formId = context->formId;
5821     if (formId.empty()) {
5822         context->error = OHOS_INVALID_PARAM_CODE;
5823         return;
5824     }
5825     context->predicates.EqualTo(FormMap::FORMMAP_FORM_ID, formId);
5826     string deleteUri = PAH_REMOVE_FORM_MAP;
5827     Uri uri(deleteUri);
5828     int ret = UserFileClient::Delete(uri, context->predicates);
5829     if (ret < 0) {
5830         if (ret == E_PERMISSION_DENIED) {
5831             context->error = OHOS_PERMISSION_DENIED_CODE;
5832         } else {
5833             context->SaveError(ret);
5834         }
5835         NAPI_ERR_LOG("remove formInfo failed, ret: %{public}d", ret);
5836     }
5837 }
5838 
RemoveFormInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)5839 static void RemoveFormInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5840 {
5841     MediaLibraryTracer tracer;
5842     tracer.Start("RemoveFormInfoAsyncCallbackComplete");
5843 
5844     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5845     auto jsContext = make_unique<JSAsyncContextOutput>();
5846     jsContext->status = false;
5847     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5848     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5849     if (context->error != ERR_DEFAULT) {
5850         context->HandleError(env, jsContext->error);
5851     } else {
5852         jsContext->status = true;
5853     }
5854     tracer.Finish();
5855     if (context->work != nullptr) {
5856         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5857                                                    context->work, *jsContext);
5858     }
5859     delete context;
5860 }
5861 
PhotoAccessSaveFormInfoExec(napi_env env,void * data)5862 static void PhotoAccessSaveFormInfoExec(napi_env env, void *data)
5863 {
5864     SaveFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
5865 }
5866 
PhotoAccessSaveFormInfo(napi_env env,napi_callback_info info)5867 napi_value MediaLibraryNapi::PhotoAccessSaveFormInfo(napi_env env, napi_callback_info info)
5868 {
5869     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5870     CHECK_NULLPTR_RET(ParseArgsSaveFormInfo(env, info, asyncContext));
5871     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessSaveFormInfo",
5872         PhotoAccessSaveFormInfoExec, SaveFormInfoAsyncCallbackComplete);
5873 }
5874 
PhotoAccessRemoveFormInfoExec(napi_env env,void * data)5875 static void PhotoAccessRemoveFormInfoExec(napi_env env, void *data)
5876 {
5877     RemoveFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
5878 }
5879 
PhotoAccessRemoveFormInfo(napi_env env,napi_callback_info info)5880 napi_value MediaLibraryNapi::PhotoAccessRemoveFormInfo(napi_env env, napi_callback_info info)
5881 {
5882     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5883     CHECK_NULLPTR_RET(ParseArgsRemoveFormInfo(env, info, asyncContext));
5884     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveFormInfo",
5885         PhotoAccessRemoveFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
5886 }
5887 
ParseArgsStartCreateThumbnailTask(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5888 static napi_value ParseArgsStartCreateThumbnailTask(napi_env env,
5889     napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
5890 {
5891     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5892         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5893         return nullptr;
5894     }
5895 
5896     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
5897         env, info, context, ARGS_TWO, ARGS_TWO), JS_ERR_PARAMETER_INVALID);
5898     CHECK_COND_WITH_MESSAGE(env, context->callbackRef, "Can not get callback function");
5899     CHECK_ARGS(env, MediaLibraryNapiUtils::ParsePredicates(env,
5900         context->argv[PARAM0], context, ASSET_FETCH_OPT), JS_INNER_FAIL);
5901 
5902     napi_value result = nullptr;
5903     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5904     return result;
5905 }
5906 
RegisterThumbnailGenerateObserver(napi_env env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)5907 static void RegisterThumbnailGenerateObserver(napi_env env,
5908     std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
5909 {
5910     std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
5911     if (thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
5912         NAPI_INFO_LOG("RequestId: %{public}d exist in observer map, no need to register", requestId);
5913         return;
5914     }
5915     dataObserver = std::make_shared<ThumbnailBatchGenerateObserver>();
5916     std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
5917     UserFileClient::RegisterObserverExt(Uri(observerUri), dataObserver, false);
5918     thumbnailGenerateObserverMap.Insert(requestId, dataObserver);
5919 }
5920 
UnregisterThumbnailGenerateObserver(int32_t requestId)5921 static void UnregisterThumbnailGenerateObserver(int32_t requestId)
5922 {
5923     std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
5924     if (!thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
5925         return;
5926     }
5927 
5928     std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
5929     UserFileClient::UnregisterObserverExt(Uri(observerUri), dataObserver);
5930     thumbnailGenerateObserverMap.Erase(requestId);
5931 }
5932 
DeleteThumbnailHandler(int32_t requestId)5933 static void DeleteThumbnailHandler(int32_t requestId)
5934 {
5935     std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
5936     if (!thumbnailGenerateHandlerMap.Find(requestId, dataHandler)) {
5937         return;
5938     }
5939     napi_release_threadsafe_function(dataHandler->threadSafeFunc_, napi_tsfn_release);
5940     thumbnailGenerateHandlerMap.Erase(requestId);
5941 }
5942 
ReleaseThumbnailTask(int32_t requestId)5943 static void ReleaseThumbnailTask(int32_t requestId)
5944 {
5945     UnregisterThumbnailGenerateObserver(requestId);
5946     DeleteThumbnailHandler(requestId);
5947 }
5948 
CreateThumbnailHandler(napi_env env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)5949 static void CreateThumbnailHandler(napi_env env,
5950     std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
5951 {
5952     napi_value workName = nullptr;
5953     napi_create_string_utf8(env, "ThumbSafeThread", NAPI_AUTO_LENGTH, &workName);
5954     napi_threadsafe_function threadSafeFunc;
5955     napi_status status = napi_create_threadsafe_function(env, asyncContext->argv[PARAM1], NULL, workName, 0, 1,
5956         NULL, NULL, NULL, MediaLibraryNapi::OnThumbnailGenerated, &threadSafeFunc);
5957     if (status != napi_ok) {
5958         NAPI_ERR_LOG("napi_create_threadsafe_function fail");
5959         ReleaseThumbnailTask(requestId);
5960         asyncContext->SaveError(JS_INNER_FAIL);
5961         return;
5962     }
5963     std::shared_ptr<ThumbnailGenerateHandler> dataHandler =
5964         std::make_shared<ThumbnailGenerateHandler>(asyncContext->callbackRef, threadSafeFunc);
5965     thumbnailGenerateHandlerMap.Insert(requestId, dataHandler);
5966 }
5967 
OnThumbnailGenerated(napi_env env,napi_value cb,void * context,void * data)5968 void MediaLibraryNapi::OnThumbnailGenerated(napi_env env, napi_value cb, void *context, void *data)
5969 {
5970     if (env == nullptr) {
5971         return;
5972     }
5973     std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
5974     if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
5975         return;
5976     }
5977 
5978     napi_status status = napi_get_reference_value(env, dataHandler->callbackRef_, &cb);
5979     if (status != napi_ok) {
5980         NapiError::ThrowError(env, JS_INNER_FAIL, "napi_get_reference_value fail");
5981         return;
5982     }
5983 
5984     napi_value result = nullptr;
5985     status = napi_call_function(env, nullptr, cb, 0, nullptr, &result);
5986     if (status != napi_ok) {
5987         NapiError::ThrowError(env, JS_INNER_FAIL, "calling onDataPrepared failed");
5988     }
5989 }
5990 
AssignRequestId()5991 static int32_t AssignRequestId()
5992 {
5993     return ++requestIdCounter_;
5994 }
5995 
GetRequestId()5996 static int32_t GetRequestId()
5997 {
5998     return requestIdCounter_;
5999 }
6000 
PhotoAccessStartCreateThumbnailTask(napi_env env,napi_callback_info info)6001 napi_value MediaLibraryNapi::PhotoAccessStartCreateThumbnailTask(napi_env env, napi_callback_info info)
6002 {
6003     MediaLibraryTracer tracer;
6004     tracer.Start("PhotoAccessStartCreateThumbnailTask");
6005     std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
6006     CHECK_NULLPTR_RET(ParseArgsStartCreateThumbnailTask(env, info, asyncContext));
6007 
6008     ReleaseThumbnailTask(GetRequestId());
6009     int32_t requestId = AssignRequestId();
6010     RegisterThumbnailGenerateObserver(env, asyncContext, requestId);
6011     CreateThumbnailHandler(env, asyncContext, requestId);
6012 
6013     DataShareValuesBucket valuesBucket;
6014     valuesBucket.Put(THUMBNAIL_BATCH_GENERATE_REQUEST_ID, requestId);
6015     string updateUri = PAH_START_GENERATE_THUMBNAILS;
6016     MediaLibraryNapiUtils::UriAppendKeyValue(updateUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
6017     Uri uri(updateUri);
6018     int changedRows = UserFileClient::Update(uri, asyncContext->predicates, valuesBucket);
6019 
6020     napi_value result = nullptr;
6021     NAPI_CALL(env, napi_get_undefined(env, &result));
6022     if (changedRows < 0) {
6023         ReleaseThumbnailTask(requestId);
6024         asyncContext->SaveError(changedRows);
6025         NAPI_ERR_LOG("Create thumbnail task, update failed, err: %{public}d", changedRows);
6026         napi_create_int32(env, changedRows, &result);
6027         return result;
6028     }
6029     napi_create_int32(env, requestId, &result);
6030     return result;
6031 }
6032 
OnChange(const ChangeInfo & changeInfo)6033 void ThumbnailBatchGenerateObserver::OnChange(const ChangeInfo &changeInfo)
6034 {
6035     if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_THUMB_ADD)) {
6036         return;
6037     }
6038 
6039     for (auto &uri : changeInfo.uris_) {
6040         string uriString = uri.ToString();
6041         auto pos = uriString.find_last_of('/');
6042         if (pos == std::string::npos) {
6043             continue;
6044         }
6045         requestIdCallback_ = std::stoi(uriString.substr(pos + 1));
6046         std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6047         if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
6048             continue;
6049         }
6050 
6051         napi_status status = napi_acquire_threadsafe_function(dataHandler->threadSafeFunc_);
6052         if (status != napi_ok) {
6053             ReleaseThumbnailTask(requestIdCallback_);
6054             NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
6055             continue;
6056         }
6057         status = napi_call_threadsafe_function(dataHandler->threadSafeFunc_, NULL, napi_tsfn_blocking);
6058         if (status != napi_ok) {
6059             ReleaseThumbnailTask(requestIdCallback_);
6060             NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
6061             continue;
6062         }
6063     }
6064 }
6065 
ParseArgsStopCreateThumbnailTask(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6066 static napi_value ParseArgsStopCreateThumbnailTask(napi_env env,
6067     napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
6068 {
6069     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6070         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6071         return nullptr;
6072     }
6073 
6074     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env,
6075         info, context, ARGS_ONE, ARGS_ONE), JS_ERR_PARAMETER_INVALID);
6076     napi_value result = nullptr;
6077     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6078     return result;
6079 }
6080 
PhotoAccessStopCreateThumbnailTask(napi_env env,napi_callback_info info)6081 napi_value MediaLibraryNapi::PhotoAccessStopCreateThumbnailTask(napi_env env, napi_callback_info info)
6082 {
6083     MediaLibraryTracer tracer;
6084     tracer.Start("PhotoAccessStopCreateThumbnailTask");
6085     std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
6086     CHECK_NULLPTR_RET(ParseArgsStopCreateThumbnailTask(env, info, asyncContext));
6087 
6088     int32_t requestId = 0;
6089     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetInt32(env,
6090         asyncContext->argv[PARAM0], requestId) == napi_ok, "Failed to get requestId");
6091     if (requestId <= 0) {
6092         NAPI_WARN_LOG("Invalid requestId: %{public}d", requestId);
6093         RETURN_NAPI_UNDEFINED(env);
6094     }
6095     ReleaseThumbnailTask(requestId);
6096 
6097     DataShareValuesBucket valuesBucket;
6098     valuesBucket.Put(THUMBNAIL_BATCH_GENERATE_REQUEST_ID, requestId);
6099     string updateUri = PAH_STOP_GENERATE_THUMBNAILS;
6100     MediaLibraryNapiUtils::UriAppendKeyValue(updateUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
6101     Uri uri(updateUri);
6102     int changedRows = UserFileClient::Update(uri, asyncContext->predicates, valuesBucket);
6103     if (changedRows < 0) {
6104         asyncContext->SaveError(changedRows);
6105         NAPI_ERR_LOG("Stop create thumbnail task, update failed, err: %{public}d", changedRows);
6106     }
6107     RETURN_NAPI_UNDEFINED(env);
6108 }
6109 
JSGetPhotoAssets(napi_env env,napi_callback_info info)6110 napi_value MediaLibraryNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
6111 {
6112     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6113     asyncContext->assetType = TYPE_PHOTO;
6114     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
6115 
6116     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
6117         JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
6118 }
6119 
PhotoAccessGetAssetsExecute(napi_env env,void * data)6120 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
6121 {
6122     MediaLibraryTracer tracer;
6123     tracer.Start("PhotoAccessGetAssetsExecute");
6124 
6125     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6126     string queryUri;
6127     switch (context->assetType) {
6128         case TYPE_PHOTO: {
6129             queryUri = PAH_QUERY_PHOTO;
6130             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
6131             break;
6132         }
6133         default: {
6134             context->SaveError(-EINVAL);
6135             return;
6136         }
6137     }
6138 
6139     Uri uri(queryUri);
6140     int errCode = 0;
6141     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
6142         context->predicates, context->fetchColumn, errCode);
6143     if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
6144         Uri queryWithUri(context->uri);
6145         resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
6146     }
6147     if (resultSet == nullptr) {
6148         context->SaveError(errCode);
6149         return;
6150     }
6151     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
6152     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6153 }
6154 
PhotoAccessGetAssetsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)6155 static napi_value PhotoAccessGetAssetsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
6156 {
6157     auto context = &asyncContext;
6158     if (context->assetType != TYPE_PHOTO) {
6159         return nullptr;
6160     }
6161 
6162     string queryUri = PAH_QUERY_PHOTO;
6163     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
6164     Uri uri(queryUri);
6165     int errCode = 0;
6166     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
6167         context->predicates, context->fetchColumn, errCode);
6168     if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
6169         Uri queryWithUri(context->uri);
6170         resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
6171     }
6172     CHECK_NULLPTR_RET(resultSet);
6173     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
6174     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6175     CHECK_NULLPTR_RET(fetchResult);
6176 
6177     std::vector<std::unique_ptr<FileAsset>> fileAssetArray;
6178     auto file = fetchResult->GetFirstObject();
6179     while (file != nullptr) {
6180         fileAssetArray.push_back(move(file));
6181         file = fetchResult->GetNextObject();
6182     }
6183     size_t len = fileAssetArray.size();
6184     napi_value jsFileArray = nullptr;
6185     napi_create_array_with_length(env, len, &jsFileArray);
6186     size_t i = 0;
6187     for (i = 0; i < len; i++) {
6188         napi_value jsFileAsset = FileAssetNapi::CreateFileAsset(env, fileAssetArray[i]);
6189         if ((jsFileAsset == nullptr) || (napi_set_element(env, jsFileArray, i, jsFileAsset) != napi_ok)) {
6190             NAPI_ERR_LOG("Failed to get file asset napi object");
6191             break;
6192         }
6193     }
6194     return (i == len) ? jsFileArray : nullptr;
6195 }
6196 
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)6197 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
6198 {
6199     NAPI_DEBUG_LOG("MediaLibraryNapi::PhotoAccessGetPhotoAssets start");
6200     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6201     asyncContext->assetType = TYPE_PHOTO;
6202     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
6203 
6204     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
6205         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
6206 }
6207 
PhotoAccessGetBurstAssets(napi_env env,napi_callback_info info)6208 napi_value MediaLibraryNapi::PhotoAccessGetBurstAssets(napi_env env, napi_callback_info info)
6209 {
6210     NAPI_INFO_LOG("MediaLibraryNapi::PhotoAccessGetBurstAssets start");
6211     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6212     asyncContext->assetType = TYPE_PHOTO;
6213     CHECK_NULLPTR_RET(ParseArgsGetBurstAssets(env, info, asyncContext));
6214 
6215     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
6216         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
6217 }
6218 
PhotoAccessGetFileAssetsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)6219 static napi_value PhotoAccessGetFileAssetsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
6220 {
6221     auto context = &asyncContext;
6222     if (context->assetType != TYPE_PHOTO) {
6223         return nullptr;
6224     }
6225     string queryUri = PAH_QUERY_PHOTO;
6226     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
6227 
6228     Uri uri(queryUri);
6229     shared_ptr<NativeRdb::AbsSharedResultSet> resultSet = UserFileClient::QueryRdb(uri,
6230         context->predicates, context->fetchColumn);
6231     CHECK_NULLPTR_RET(resultSet);
6232 
6233     napi_value jsFileArray = 0;
6234     napi_create_array(env, &jsFileArray);
6235 
6236     int count = 0;
6237     while (!resultSet->GoToNextRow()) {
6238         napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet);
6239         napi_set_element(env, jsFileArray, count++, item);
6240     }
6241     resultSet->Close();
6242     return jsFileArray;
6243 }
6244 
PhotoAccessGetFileAssetsInfo(napi_env env,napi_callback_info info)6245 napi_value MediaLibraryNapi::PhotoAccessGetFileAssetsInfo(napi_env env, napi_callback_info info)
6246 {
6247     unique_ptr<MediaLibraryAsyncContext> context = make_unique<MediaLibraryAsyncContext>();
6248     context->assetType = TYPE_PHOTO;
6249     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, context));
6250 
6251     return PhotoAccessGetFileAssetsExecuteSync(env, *context);
6252 }
6253 
PhotoAccessGetPhotoAssetsSync(napi_env env,napi_callback_info info)6254 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssetsSync(napi_env env, napi_callback_info info)
6255 {
6256     MediaLibraryTracer tracer;
6257     tracer.Start("PhotoAccessGetPhotoAssetsSync");
6258 
6259     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6260     asyncContext->assetType = TYPE_PHOTO;
6261     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
6262     return PhotoAccessGetAssetsExecuteSync(env, *asyncContext);
6263 }
6264 
JSGetAudioAssets(napi_env env,napi_callback_info info)6265 napi_value MediaLibraryNapi::JSGetAudioAssets(napi_env env, napi_callback_info info)
6266 {
6267     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6268     asyncContext->assetType = TYPE_AUDIO;
6269     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
6270 
6271     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAudioAssets",
6272         JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
6273 }
6274 
GetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)6275 static void GetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
6276     unique_ptr<JSAsyncContextOutput> &jsContext)
6277 {
6278     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
6279     if (fileResult == nullptr) {
6280         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6281         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
6282             "Failed to create js object for Fetch Album Result");
6283         return;
6284     }
6285     jsContext->data = fileResult;
6286     jsContext->status = true;
6287     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6288 }
6289 
JSGetPhotoAlbumsExecute(napi_env env,void * data)6290 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
6291 {
6292     MediaLibraryTracer tracer;
6293     tracer.Start("JSGetPhotoAlbumsExecute");
6294 
6295     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6296     string queryUri;
6297     if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
6298         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6299             UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
6300     } else if (context->isAnalysisAlbum) {
6301         queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
6302             PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
6303     } else {
6304         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6305             UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
6306     }
6307     Uri uri(queryUri);
6308     int errCode = 0;
6309     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
6310     if (resultSet == nullptr) {
6311         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
6312         if (errCode == E_PERMISSION_DENIED) {
6313             if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
6314                 context->error = OHOS_PERMISSION_DENIED_CODE;
6315             } else {
6316                 context->SaveError(E_HAS_DB_ERROR);
6317             }
6318         } else {
6319             context->SaveError(E_HAS_DB_ERROR);
6320         }
6321         return;
6322     }
6323 
6324     context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
6325     context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
6326     context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
6327     context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
6328         PhotoAlbumSubType::GEOGRAPHY_LOCATION);
6329 }
6330 
JSGetPhotoAlbumsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)6331 static napi_value JSGetPhotoAlbumsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
6332 {
6333     auto context = &asyncContext;
6334     string queryUri;
6335     if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
6336         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6337             UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
6338     } else if (context->isAnalysisAlbum) {
6339         queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
6340             PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
6341     } else {
6342         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6343             UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
6344     }
6345     Uri uri(queryUri);
6346     int errCode = 0;
6347     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
6348     CHECK_NULLPTR_RET(resultSet);
6349 
6350     auto fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
6351     fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
6352     fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
6353     fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION);
6354     if (fetchPhotoAlbumResult->GetCount() <= 0) {
6355         return nullptr;
6356     }
6357     auto photoAlbum = fetchPhotoAlbumResult->GetFirstObject();
6358     CHECK_NULLPTR_RET(photoAlbum);
6359     return PhotoAlbumNapi::CreatePhotoAlbumNapi(env, photoAlbum);
6360 }
6361 
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)6362 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
6363 {
6364     MediaLibraryTracer tracer;
6365     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
6366 
6367     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6368     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
6369     jsContext->status = false;
6370     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6371     if (context->error != ERR_DEFAULT  || context->fetchPhotoAlbumResult == nullptr) {
6372         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6373         context->HandleError(env, jsContext->error);
6374     } else {
6375         GetPhotoAlbumQueryResult(env, context, jsContext);
6376     }
6377 
6378     tracer.Finish();
6379     if (context->work != nullptr) {
6380         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6381                                                    context->work, *jsContext);
6382     }
6383     delete context;
6384 }
6385 
JSGetPhotoAlbums(napi_env env,napi_callback_info info)6386 napi_value MediaLibraryNapi::JSGetPhotoAlbums(napi_env env, napi_callback_info info)
6387 {
6388     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6389     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext),
6390         JS_ERR_PARAMETER_INVALID);
6391     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6392 
6393     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAlbums", JSGetPhotoAlbumsExecute,
6394         JSGetPhotoAlbumsCompleteCallback);
6395 }
6396 
UserFileMgrCreatePhotoAsset(napi_env env,napi_callback_info info)6397 napi_value MediaLibraryNapi::UserFileMgrCreatePhotoAsset(napi_env env, napi_callback_info info)
6398 {
6399     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6400     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6401     asyncContext->assetType = TYPE_PHOTO;
6402     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
6403 
6404     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreatePhotoAsset",
6405         JSCreateAssetExecute, JSCreateAssetCompleteCallback);
6406 }
6407 
UserFileMgrCreateAudioAsset(napi_env env,napi_callback_info info)6408 napi_value MediaLibraryNapi::UserFileMgrCreateAudioAsset(napi_env env, napi_callback_info info)
6409 {
6410     napi_value ret = nullptr;
6411     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6412     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
6413     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6414     asyncContext->assetType = TYPE_AUDIO;
6415     NAPI_ASSERT(env, ParseArgsCreateAudioAsset(env, info, asyncContext), "Failed to parse js args");
6416 
6417     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAudioAsset",
6418         JSCreateAssetExecute, JSCreateAssetCompleteCallback);
6419 }
6420 
ParseArgsTrashAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6421 napi_value ParseArgsTrashAsset(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
6422 {
6423     string uri;
6424     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
6425         JS_ERR_PARAMETER_INVALID);
6426     if (uri.empty()) {
6427         NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
6428         return nullptr;
6429     }
6430     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos &&
6431         uri.find(AudioColumn::AUDIO_URI_PREFIX) == string::npos) {
6432         NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo or audio uri");
6433         return nullptr;
6434     }
6435     context->uri = uri;
6436 
6437     napi_value result = nullptr;
6438     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6439     return result;
6440 }
6441 
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)6442 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
6443 {
6444     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6445     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6446     CHECK_NULLPTR_RET(ParseArgsTrashAsset(env, info, asyncContext));
6447     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
6448         JSTrashAssetCompleteCallback);
6449 }
6450 
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)6451 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
6452 {
6453     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6454     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6455     CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
6456 
6457     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
6458         JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
6459 }
6460 
CreateMediaTypeEnum(napi_env env)6461 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
6462 {
6463     return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
6464 }
6465 
CreateMediaTypeUserFileEnum(napi_env env)6466 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
6467 {
6468     const int32_t startIdx = 1;
6469     return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
6470 }
6471 
CreateDirectoryTypeEnum(napi_env env)6472 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
6473 {
6474     return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
6475 }
6476 
CreateVirtualAlbumTypeEnum(napi_env env)6477 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
6478 {
6479     return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
6480 }
6481 
CreatePrivateAlbumTypeEnum(napi_env env)6482 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
6483 {
6484     return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
6485 }
6486 
CreateHiddenPhotosDisplayModeEnum(napi_env env)6487 napi_value MediaLibraryNapi::CreateHiddenPhotosDisplayModeEnum(napi_env env)
6488 {
6489     return CreateNumberEnumProperty(env, HIDDEN_PHOTOS_DISPLAY_MODE_ENUM, sHiddenPhotosDisplayModeEnumRef_);
6490 }
6491 
CreateFileKeyEnum(napi_env env)6492 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
6493 {
6494     return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
6495 }
6496 
UserFileMgrCreateFileKeyEnum(napi_env env)6497 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
6498 {
6499     return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
6500 }
6501 
CreateAudioKeyEnum(napi_env env)6502 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
6503 {
6504     return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
6505 }
6506 
CreateImageVideoKeyEnum(napi_env env)6507 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
6508 {
6509     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
6510 }
6511 
CreatePhotoKeysEnum(napi_env env)6512 napi_value MediaLibraryNapi::CreatePhotoKeysEnum(napi_env env)
6513 {
6514     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sPhotoKeysEnumRef_);
6515 }
6516 
CreateAlbumKeyEnum(napi_env env)6517 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
6518 {
6519     return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
6520 }
6521 
CreateImageFileTypeEnum(napi_env env)6522 napi_value MediaLibraryNapi::CreateImageFileTypeEnum(napi_env env)
6523 {
6524     const int32_t startIdx = 1;
6525     return CreateNumberEnumProperty(env, imageFileTypeEnum, sImageFileTypeEnumEnumRef_, startIdx);
6526 }
6527 
CreateAlbumTypeEnum(napi_env env)6528 napi_value MediaLibraryNapi::CreateAlbumTypeEnum(napi_env env)
6529 {
6530     napi_value result = nullptr;
6531     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
6532 
6533     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
6534     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
6535     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SMART", PhotoAlbumType::SMART), JS_INNER_FAIL);
6536     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE", PhotoAlbumType::SOURCE), JS_INNER_FAIL);
6537 
6538     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
6539     return result;
6540 }
6541 
CreateAlbumSubTypeEnum(napi_env env)6542 napi_value MediaLibraryNapi::CreateAlbumSubTypeEnum(napi_env env)
6543 {
6544     napi_value result = nullptr;
6545     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
6546 
6547     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
6548         JS_INNER_FAIL);
6549     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE_GENERIC", PhotoAlbumSubType::SOURCE_GENERIC),
6550         JS_INNER_FAIL);
6551     for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
6552         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
6553             PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
6554     }
6555     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "CLASSIFY", PhotoAlbumSubType::CLASSIFY),
6556         JS_INNER_FAIL);
6557     for (size_t i = 0; i < analysisAlbumSubType.size(); i++) {
6558         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, analysisAlbumSubType[i],
6559             PhotoAlbumSubType::GEOGRAPHY_LOCATION + i), JS_INNER_FAIL);
6560     }
6561     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
6562 
6563     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
6564     return result;
6565 }
6566 
CreateAnalysisTypeEnum(napi_env env)6567 napi_value MediaLibraryNapi::CreateAnalysisTypeEnum(napi_env env)
6568 {
6569     struct AnalysisProperty property[] = {
6570         { "ANALYSIS_AESTHETICS_SCORE", AnalysisType::ANALYSIS_AESTHETICS_SCORE },
6571         { "ANALYSIS_LABEL", AnalysisType::ANALYSIS_LABEL },
6572         { "ANALYSIS_VIDEO_LABEL", AnalysisType::ANALYSIS_VIDEO_LABEL },
6573         { "ANALYSIS_OCR", AnalysisType::ANALYSIS_OCR },
6574         { "ANALYSIS_FACE", AnalysisType::ANALYSIS_FACE },
6575         { "ANALYSIS_OBJECT", AnalysisType::ANALYSIS_OBJECT },
6576         { "ANALYSIS_RECOMMENDATION", AnalysisType::ANALYSIS_RECOMMENDATION },
6577         { "ANALYSIS_SEGMENTATION", AnalysisType::ANALYSIS_SEGMENTATION },
6578         { "ANALYSIS_COMPOSITION", AnalysisType::ANALYSIS_COMPOSITION },
6579         { "ANALYSIS_SALIENCY", AnalysisType::ANALYSIS_SALIENCY },
6580         { "ANALYSIS_DETAIL_ADDRESS", AnalysisType::ANALYSIS_DETAIL_ADDRESS },
6581         { "ANALYSIS_HUMAN_FACE_TAG", AnalysisType::ANALYSIS_HUMAN_FACE_TAG },
6582         { "ANALYSIS_HEAD_POSITION", AnalysisType::ANALYSIS_HEAD_POSITION },
6583         { "ANALYSIS_BONE_POSE", AnalysisType::ANALYSIS_BONE_POSE },
6584         { "ANALYSIS_MULTI_CROP", AnalysisType::ANALYSIS_MULTI_CROP },
6585     };
6586 
6587     napi_value result = nullptr;
6588     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
6589 
6590     for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
6591         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
6592             JS_INNER_FAIL);
6593     }
6594 
6595     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAnalysisType_), JS_INNER_FAIL);
6596     return result;
6597 }
6598 
CreateHighlightAlbumInfoTypeEnum(napi_env env)6599 napi_value MediaLibraryNapi::CreateHighlightAlbumInfoTypeEnum(napi_env env)
6600 {
6601     struct AnalysisProperty property[] = {
6602         { "COVER_INFO", HighlightAlbumInfoType::COVER_INFO },
6603         { "PLAY_INFO", HighlightAlbumInfoType::PLAY_INFO },
6604     };
6605 
6606     napi_value result = nullptr;
6607     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
6608 
6609     for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
6610         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
6611             JS_INNER_FAIL);
6612     }
6613 
6614     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sHighlightUserActionType_), JS_INNER_FAIL);
6615     return result;
6616 }
6617 
CreateHighlightUserActionTypeEnum(napi_env env)6618 napi_value MediaLibraryNapi::CreateHighlightUserActionTypeEnum(napi_env env)
6619 {
6620     struct AnalysisProperty property[] = {
6621         { "INSERTED_PIC_COUNT", HighlightUserActionType::INSERTED_PIC_COUNT },
6622         { "REMOVED_PIC_COUNT", HighlightUserActionType::REMOVED_PIC_COUNT },
6623         { "SHARED_SCREENSHOT_COUNT", HighlightUserActionType::SHARED_SCREENSHOT_COUNT },
6624         { "SHARED_COVER_COUNT", HighlightUserActionType::SHARED_COVER_COUNT },
6625         { "RENAMED_COUNT", HighlightUserActionType::RENAMED_COUNT },
6626         { "CHANGED_COVER_COUNT", HighlightUserActionType::CHANGED_COVER_COUNT },
6627         { "RENDER_VIEWED_TIMES", HighlightUserActionType::RENDER_VIEWED_TIMES },
6628         { "RENDER_VIEWED_DURATION", HighlightUserActionType::RENDER_VIEWED_DURATION },
6629         { "ART_LAYOUT_VIEWED_TIMES", HighlightUserActionType::ART_LAYOUT_VIEWED_TIMES },
6630         { "ART_LAYOUT_VIEWED_DURATION", HighlightUserActionType::ART_LAYOUT_VIEWED_DURATION },
6631     };
6632 
6633     napi_value result = nullptr;
6634     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
6635 
6636     for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
6637         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
6638             JS_INNER_FAIL);
6639     }
6640 
6641     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sHighlightAlbumInfoType_), JS_INNER_FAIL);
6642     return result;
6643 }
6644 
CreateDefaultChangeUriEnum(napi_env env)6645 napi_value MediaLibraryNapi::CreateDefaultChangeUriEnum(napi_env env)
6646 {
6647     return CreateStringEnumProperty(env, DEFAULT_URI_ENUM_PROPERTIES, sDefaultChangeUriRef_);
6648 }
6649 
CreateNotifyTypeEnum(napi_env env)6650 napi_value MediaLibraryNapi::CreateNotifyTypeEnum(napi_env env)
6651 {
6652     return CreateNumberEnumProperty(env, notifyTypeEnum, sNotifyType_);
6653 }
6654 
CreateRequestPhotoTypeEnum(napi_env env)6655 napi_value MediaLibraryNapi::CreateRequestPhotoTypeEnum(napi_env env)
6656 {
6657     return CreateNumberEnumProperty(env, requestPhotoTypeEnum, sRequestPhotoTypeEnumRef_);
6658 }
6659 
CreateDeliveryModeEnum(napi_env env)6660 napi_value MediaLibraryNapi::CreateDeliveryModeEnum(napi_env env)
6661 {
6662     return CreateNumberEnumProperty(env, deliveryModeEnum, sDeliveryModeEnumRef_);
6663 }
6664 
CreateSourceModeEnum(napi_env env)6665 napi_value MediaLibraryNapi::CreateSourceModeEnum(napi_env env)
6666 {
6667     return CreateNumberEnumProperty(env, sourceModeEnum, sSourceModeEnumRef_);
6668 }
6669 
CreateAuthorizationModeEnum(napi_env env)6670 napi_value MediaLibraryNapi::CreateAuthorizationModeEnum(napi_env env)
6671 {
6672     return CreateNumberEnumProperty(env, AuthorizationModeEnum, sAuthorizationModeEnumRef_);
6673 }
6674 
CreateResourceTypeEnum(napi_env env)6675 napi_value MediaLibraryNapi::CreateResourceTypeEnum(napi_env env)
6676 {
6677     const int32_t startIdx = 1;
6678     return CreateNumberEnumProperty(env, resourceTypeEnum, sResourceTypeEnumRef_, startIdx);
6679 }
6680 
CreateMovingPhotoEffectModeEnum(napi_env env)6681 napi_value MediaLibraryNapi::CreateMovingPhotoEffectModeEnum(napi_env env)
6682 {
6683     napi_value result = nullptr;
6684     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
6685     for (size_t i = 0; i < movingPhotoEffectModeEnum.size(); i++) {
6686         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, movingPhotoEffectModeEnum[i], static_cast<int32_t>(i)),
6687             JS_INNER_FAIL);
6688     }
6689     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "IMAGE_ONLY",
6690         static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY)), JS_INNER_FAIL);
6691     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sMovingPhotoEffectModeEnumRef_),
6692         JS_INNER_FAIL);
6693     return result;
6694 }
6695 
CreateCloudEnhancementTaskStageEnum(napi_env env)6696 napi_value MediaLibraryNapi::CreateCloudEnhancementTaskStageEnum(napi_env env)
6697 {
6698     return CreateNumberEnumProperty(env, cloudEnhancementTaskStageEnum, sCloudEnhancementTaskStageEnumRef_, -1);
6699 }
6700 
CreateCloudEnhancementStateEnum(napi_env env)6701 napi_value MediaLibraryNapi::CreateCloudEnhancementStateEnum(napi_env env)
6702 {
6703     return CreateNumberEnumProperty(env, cloudEnhancementStateEnum, sCloudEnhancementStateEnumRef_);
6704 }
6705 
CreateVideoEnhancementTypeEnum(napi_env env)6706 napi_value MediaLibraryNapi::CreateVideoEnhancementTypeEnum(napi_env env)
6707 {
6708     return CreateNumberEnumProperty(env, videoEnhancementTypeEnum, sVideoEnhancementTypeEnumRef_);
6709 }
6710 
ParseArgsCreatePhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6711 static napi_value ParseArgsCreatePhotoAlbum(napi_env env, napi_callback_info info,
6712     unique_ptr<MediaLibraryAsyncContext> &context)
6713 {
6714     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6715         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6716         return nullptr;
6717     }
6718 
6719     constexpr size_t minArgs = ARGS_ONE;
6720     constexpr size_t maxArgs = ARGS_TWO;
6721     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
6722         JS_ERR_PARAMETER_INVALID);
6723 
6724     /* Parse the first argument into albumName */
6725     string albumName;
6726     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], albumName),
6727         JS_ERR_PARAMETER_INVALID);
6728 
6729     if (MediaFileUtils::CheckAlbumName(albumName) < 0) {
6730         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
6731         return nullptr;
6732     }
6733     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, albumName);
6734     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_IS_LOCAL, 1); // local album is 1.
6735 
6736     napi_value result = nullptr;
6737     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6738     return result;
6739 }
6740 
GetExistsPhotoAlbum(const string & albumName,MediaLibraryAsyncContext * context)6741 static void GetExistsPhotoAlbum(const string &albumName, MediaLibraryAsyncContext *context)
6742 {
6743     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6744         UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
6745     Uri uri(queryUri);
6746     DataSharePredicates predicates;
6747     predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
6748     vector<string> columns;
6749     int errCode = 0;
6750     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
6751     auto fetchResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
6752     fetchResult->SetResultNapiType(context->resultNapiType);
6753     context->photoAlbumData = fetchResult->GetFirstObject();
6754 }
6755 
GetPhotoAlbumById(const int32_t id,const string & albumName,MediaLibraryAsyncContext * context)6756 static void GetPhotoAlbumById(const int32_t id, const string &albumName, MediaLibraryAsyncContext *context)
6757 {
6758     auto photoAlbum = make_unique<PhotoAlbum>();
6759     photoAlbum->SetAlbumId(id);
6760     photoAlbum->SetPhotoAlbumType(USER);
6761     photoAlbum->SetPhotoAlbumSubType(USER_GENERIC);
6762     photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(id));
6763     photoAlbum->SetAlbumName(albumName);
6764     photoAlbum->SetResultNapiType(context->resultNapiType);
6765     context->photoAlbumData = move(photoAlbum);
6766 }
6767 
JSCreatePhotoAlbumExecute(napi_env env,void * data)6768 static void JSCreatePhotoAlbumExecute(napi_env env, void *data)
6769 {
6770     MediaLibraryTracer tracer;
6771     tracer.Start("JSCreatePhotoAlbumExecute");
6772 
6773     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6774     string createAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6775         UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
6776     Uri createPhotoAlbumUri(createAlbumUri);
6777     auto ret = UserFileClient::Insert(createPhotoAlbumUri, context->valuesBucket);
6778 
6779     bool isValid = false;
6780     string albumName = context->valuesBucket.Get(PhotoAlbumColumns::ALBUM_NAME, isValid);
6781     if (!isValid) {
6782         context->SaveError(-EINVAL);
6783         return;
6784     }
6785     if (ret == -1) {
6786         // The album is already existed
6787         context->SaveError(-EEXIST);
6788         GetExistsPhotoAlbum(albumName, context);
6789         return;
6790     }
6791     if (ret < 0) {
6792         context->SaveError(ret);
6793         return;
6794     }
6795     GetPhotoAlbumById(ret, albumName, context);
6796 }
6797 
GetPhotoAlbumCreateResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)6798 static void GetPhotoAlbumCreateResult(napi_env env, MediaLibraryAsyncContext *context,
6799     unique_ptr<JSAsyncContextOutput> &jsContext)
6800 {
6801     if (context->photoAlbumData == nullptr) {
6802         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6803         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
6804             "Obtain photo album asset failed");
6805         return;
6806     }
6807     napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
6808     if (jsPhotoAlbum == nullptr) {
6809         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6810         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
6811             "Failed to create js object for PhotoAlbum");
6812         return;
6813     }
6814     jsContext->data = jsPhotoAlbum;
6815     jsContext->status = true;
6816     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6817 }
6818 
HandleExistsError(napi_env env,MediaLibraryAsyncContext * context,napi_value & error)6819 static void HandleExistsError(napi_env env, MediaLibraryAsyncContext *context, napi_value &error)
6820 {
6821     if (context->photoAlbumData == nullptr) {
6822         MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_INVALID_OUTPUT,
6823             "Obtain photo album asset failed");
6824         return;
6825     }
6826     napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
6827     if (jsPhotoAlbum == nullptr) {
6828         MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_MEM_ALLOCATION,
6829             "Failed to create js object for PhotoAlbum");
6830         return;
6831     }
6832     MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, JS_ERR_FILE_EXIST, "Album has existed");
6833     napi_value propertyName;
6834     CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &propertyName), JS_INNER_FAIL);
6835     CHECK_ARGS_RET_VOID(env, napi_set_property(env, error, propertyName, jsPhotoAlbum), JS_INNER_FAIL);
6836 }
6837 
JSCreatePhotoAlbumCompleteCallback(napi_env env,napi_status status,void * data)6838 static void JSCreatePhotoAlbumCompleteCallback(napi_env env, napi_status status, void *data)
6839 {
6840     MediaLibraryTracer tracer;
6841     tracer.Start("JSCreatePhotoAlbumCompleteCallback");
6842 
6843     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6844     auto jsContext = make_unique<JSAsyncContextOutput>();
6845     jsContext->status = false;
6846     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6847     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6848     if (context->error == ERR_DEFAULT) {
6849         GetPhotoAlbumCreateResult(env, context, jsContext);
6850     } else if (context->error == JS_ERR_FILE_EXIST) {
6851         HandleExistsError(env, context, jsContext->error);
6852     } else {
6853         context->HandleError(env, jsContext->error);
6854     }
6855 
6856     tracer.Finish();
6857     if (context->work != nullptr) {
6858         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6859                                                    context->work, *jsContext);
6860     }
6861     delete context;
6862 }
6863 
CreatePhotoAlbum(napi_env env,napi_callback_info info)6864 napi_value MediaLibraryNapi::CreatePhotoAlbum(napi_env env, napi_callback_info info)
6865 {
6866     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6867     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6868     CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
6869 
6870     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
6871         JSCreatePhotoAlbumCompleteCallback);
6872 }
6873 
PhotoAccessCreatePhotoAlbum(napi_env env,napi_callback_info info)6874 napi_value MediaLibraryNapi::PhotoAccessCreatePhotoAlbum(napi_env env, napi_callback_info info)
6875 {
6876     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6877     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
6878     CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
6879 
6880     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
6881         JSCreatePhotoAlbumCompleteCallback);
6882 }
6883 
ParseArgsDeletePhotoAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6884 static napi_value ParseArgsDeletePhotoAlbums(napi_env env, napi_callback_info info,
6885     unique_ptr<MediaLibraryAsyncContext> &context)
6886 {
6887     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6888         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6889         return nullptr;
6890     }
6891 
6892     constexpr size_t minArgs = ARGS_ONE;
6893     constexpr size_t maxArgs = ARGS_TWO;
6894     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
6895         JS_ERR_PARAMETER_INVALID);
6896 
6897     /* Parse the first argument into delete album id array */
6898     vector<string> deleteIds;
6899     uint32_t len = 0;
6900     CHECK_ARGS(env, napi_get_array_length(env, context->argv[PARAM0], &len), JS_INNER_FAIL);
6901     for (uint32_t i = 0; i < len; i++) {
6902         napi_value album = nullptr;
6903         CHECK_ARGS(env, napi_get_element(env, context->argv[PARAM0], i, &album), JS_INNER_FAIL);
6904         if (album == nullptr) {
6905             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
6906             return nullptr;
6907         }
6908         PhotoAlbumNapi *obj = nullptr;
6909         CHECK_ARGS(env, napi_unwrap(env, album, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
6910         if (obj == nullptr) {
6911             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
6912             return nullptr;
6913         }
6914         if (!PhotoAlbum::IsUserPhotoAlbum(obj->GetPhotoAlbumType(), obj->GetPhotoAlbumSubType())) {
6915             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
6916             return nullptr;
6917         }
6918         deleteIds.push_back(to_string(obj->GetAlbumId()));
6919     }
6920     if (deleteIds.empty()) {
6921         napi_value result = nullptr;
6922         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6923         return result;
6924     }
6925     context->predicates.In(PhotoAlbumColumns::ALBUM_ID, deleteIds);
6926 
6927     napi_value result = nullptr;
6928     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6929     return result;
6930 }
6931 
JSDeletePhotoAlbumsExecute(napi_env env,void * data)6932 static void JSDeletePhotoAlbumsExecute(napi_env env, void *data)
6933 {
6934     MediaLibraryTracer tracer;
6935     tracer.Start("JSDeletePhotoAlbumsExecute");
6936 
6937     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6938 
6939     if (context->predicates.GetOperationList().empty()) {
6940         return;
6941     }
6942     string deleteAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
6943         UFM_DELETE_PHOTO_ALBUM : PAH_DELETE_PHOTO_ALBUM;
6944     Uri uri(deleteAlbumUri);
6945     int ret = UserFileClient::Delete(uri, context->predicates);
6946     if (ret < 0) {
6947         context->SaveError(ret);
6948     } else {
6949         context->retVal = ret;
6950     }
6951 }
6952 
JSDeletePhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)6953 static void JSDeletePhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
6954 {
6955     MediaLibraryTracer tracer;
6956     tracer.Start("JSDeletePhotoAlbumsCompleteCallback");
6957 
6958     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
6959     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
6960 
6961     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
6962     jsContext->status = false;
6963 
6964     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6965     if (context->error != ERR_DEFAULT) {
6966         context->HandleError(env, jsContext->error);
6967         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6968     } else {
6969         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
6970         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6971         jsContext->status = true;
6972     }
6973 
6974     tracer.Finish();
6975     if (context->work != nullptr) {
6976         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6977                                                    context->work, *jsContext);
6978     }
6979     delete context;
6980 }
6981 
DeletePhotoAlbums(napi_env env,napi_callback_info info)6982 napi_value MediaLibraryNapi::DeletePhotoAlbums(napi_env env, napi_callback_info info)
6983 {
6984     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6985     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
6986     CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
6987 
6988     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
6989         JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
6990 }
6991 
PhotoAccessDeletePhotoAlbums(napi_env env,napi_callback_info info)6992 napi_value MediaLibraryNapi::PhotoAccessDeletePhotoAlbums(napi_env env, napi_callback_info info)
6993 {
6994     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6995     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
6996     CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
6997 
6998     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
6999         JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
7000 }
7001 
GetAlbumFetchOption(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)7002 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
7003 {
7004     if (context->argc < (ARGS_ONE + hasCallback)) {
7005         NAPI_ERR_LOG("No arguments to parse");
7006         return nullptr;
7007     }
7008 
7009     // The index of fetchOption should always be the last arg besides callback
7010     napi_value fetchOption = context->argv[context->argc - 1 - hasCallback];
7011     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT, context), JS_INNER_FAIL);
7012     if (!context->uri.empty()) {
7013         if (context->uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != std::string::npos) {
7014             context->isAnalysisAlbum = 1; // 1:is an analysis album
7015         }
7016     }
7017     napi_value result = nullptr;
7018     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7019     return result;
7020 }
7021 
ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> & context,const int32_t albumSubType)7022 static bool ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> &context, const int32_t albumSubType)
7023 {
7024     if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
7025         context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
7026         context->fetchColumn.insert(context->fetchColumn.end(),
7027             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
7028             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
7029         MediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
7030         return false;
7031     } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
7032         context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
7033         context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
7034         string onClause = PhotoAlbumColumns::ALBUM_NAME  + " = " + CITY_ID;
7035         context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
7036         context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
7037     }
7038     return true;
7039 }
7040 
ParseAlbumTypes(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context)7041 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context)
7042 {
7043     if (context->argc < ARGS_TWO) {
7044         NAPI_ERR_LOG("No arguments to parse");
7045         return nullptr;
7046     }
7047 
7048     /* Parse the first argument to photo album type */
7049     int32_t albumType;
7050     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
7051     if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
7052         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7053         return nullptr;
7054     }
7055     context->isAnalysisAlbum = (albumType == PhotoAlbumType::SMART) ? 1 : 0;
7056 
7057     /* Parse the second argument to photo album subType */
7058     int32_t albumSubType;
7059     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
7060     if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
7061         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7062         return nullptr;
7063     }
7064 
7065     if (!ParseLocationAlbumTypes(context, albumSubType)) {
7066         napi_value result = nullptr;
7067         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7068         return result;
7069     }
7070 
7071     context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
7072     if (albumSubType != ANY) {
7073         context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
7074     }
7075     if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
7076         context->predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
7077     }
7078     if (albumSubType == PhotoAlbumSubType::HIGHLIGHT || albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
7079         context->isHighlightAlbum = albumSubType;
7080         vector<string> onClause = {
7081             ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
7082             HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
7083         };
7084         context->predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
7085         context->predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
7086     }
7087 
7088     napi_value result = nullptr;
7089     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7090     return result;
7091 }
7092 
RestrictAlbumSubtypeOptions(unique_ptr<MediaLibraryAsyncContext> & context)7093 static void RestrictAlbumSubtypeOptions(unique_ptr<MediaLibraryAsyncContext> &context)
7094 {
7095     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7096         context->predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
7097             to_string(PhotoAlbumSubType::USER_GENERIC),
7098             to_string(PhotoAlbumSubType::FAVORITE),
7099             to_string(PhotoAlbumSubType::VIDEO),
7100             to_string(PhotoAlbumSubType::IMAGE),
7101             to_string(PhotoAlbumSubType::CLOUD_ENHANCEMENT),
7102         }));
7103     } else {
7104         context->predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
7105     }
7106 }
7107 
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7108 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
7109     unique_ptr<MediaLibraryAsyncContext> &context)
7110 {
7111     constexpr size_t minArgs = ARGS_ZERO;
7112     constexpr size_t maxArgs = ARGS_FOUR;
7113     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
7114         JS_ERR_PARAMETER_INVALID);
7115 
7116     bool hasCallback = false;
7117     CHECK_ARGS(env, MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
7118         JS_ERR_PARAMETER_INVALID);
7119     if (context->argc == ARGS_THREE) {
7120         napi_valuetype valueType = napi_undefined;
7121         if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
7122             (valueType == napi_undefined || valueType == napi_null)) {
7123             context->argc -= 1;
7124         }
7125     }
7126     switch (context->argc - hasCallback) {
7127         case ARGS_ZERO:
7128             break;
7129         case ARGS_ONE:
7130             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
7131             break;
7132         case ARGS_TWO:
7133             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
7134             break;
7135         case ARGS_THREE:
7136             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
7137             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
7138             break;
7139         default:
7140             return nullptr;
7141     }
7142     RestrictAlbumSubtypeOptions(context);
7143     if (context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
7144         context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
7145         CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
7146         if (!context->isAnalysisAlbum) {
7147             context->fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
7148             context->fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
7149         }
7150         if (context->isHighlightAlbum) {
7151             context->fetchColumn.erase(std::remove(context->fetchColumn.begin(), context->fetchColumn.end(),
7152                 PhotoAlbumColumns::ALBUM_ID), context->fetchColumn.end());
7153             context->fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
7154             PhotoAlbumColumns::ALBUM_ID);
7155         }
7156     }
7157     napi_value result = nullptr;
7158     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7159     return result;
7160 }
7161 
GetPhotoAlbums(napi_env env,napi_callback_info info)7162 napi_value MediaLibraryNapi::GetPhotoAlbums(napi_env env, napi_callback_info info)
7163 {
7164     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7165     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7166     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
7167 
7168     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
7169         JSGetPhotoAlbumsCompleteCallback);
7170 }
7171 
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)7172 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
7173 {
7174     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7175     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7176     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
7177 
7178     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
7179         JSGetPhotoAlbumsCompleteCallback);
7180 }
7181 
PhotoAccessGetPhotoAlbumsSync(napi_env env,napi_callback_info info)7182 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsSync(napi_env env, napi_callback_info info)
7183 {
7184     MediaLibraryTracer tracer;
7185     tracer.Start("PhotoAccessGetPhotoAlbumsSync");
7186 
7187     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7188     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7189     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
7190     return JSGetPhotoAlbumsExecuteSync(env, *asyncContext);
7191 }
7192 
CreatePositionTypeEnum(napi_env env)7193 napi_value MediaLibraryNapi::CreatePositionTypeEnum(napi_env env)
7194 {
7195     const int32_t startIdx = 1;
7196     return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
7197 }
7198 
CreatePhotoSubTypeEnum(napi_env env)7199 napi_value MediaLibraryNapi::CreatePhotoSubTypeEnum(napi_env env)
7200 {
7201     return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
7202 }
7203 
CreatePhotoPermissionTypeEnum(napi_env env)7204 napi_value MediaLibraryNapi::CreatePhotoPermissionTypeEnum(napi_env env)
7205 {
7206     return CreateNumberEnumProperty(env, photoPermissionTypeEnum, sPhotoPermissionType_);
7207 }
7208 
CreateHideSensitiveTypeEnum(napi_env env)7209 napi_value MediaLibraryNapi::CreateHideSensitiveTypeEnum(napi_env env)
7210 {
7211     return CreateNumberEnumProperty(env, hideSensitiveTypeEnum, sHideSensitiveType_);
7212 }
7213 
CreateDynamicRangeTypeEnum(napi_env env)7214 napi_value MediaLibraryNapi::CreateDynamicRangeTypeEnum(napi_env env)
7215 {
7216     return CreateNumberEnumProperty(env, dynamicRangeTypeEnum, sDynamicRangeType_);
7217 }
7218 
PhotoAccessCreateAssetExecute(napi_env env,void * data)7219 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
7220 {
7221     MediaLibraryTracer tracer;
7222     tracer.Start("JSCreateAssetExecute");
7223 
7224     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7225     if (!CheckDisplayNameParams(context)) {
7226         context->error = JS_E_DISPLAYNAME;
7227         return;
7228     }
7229     if ((context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) && (!CheckRelativePathParams(context))) {
7230         context->error = JS_E_RELATIVEPATH;
7231         return;
7232     }
7233 
7234     string uri;
7235     GetCreateUri(context, uri);
7236     Uri createFileUri(uri);
7237     string outUri;
7238     int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri);
7239     if (index < 0) {
7240         context->SaveError(index);
7241         NAPI_ERR_LOG("InsertExt fail, index: %{public}d.", index);
7242     } else {
7243         if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
7244             if (context->isCreateByComponent) {
7245                 context->uri = outUri;
7246             } else {
7247                 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
7248             }
7249         } else {
7250 #ifdef MEDIALIBRARY_COMPATIBILITY
7251             SetFileAssetByIdV9(index, "", context);
7252 #else
7253             getFileAssetById(index, "", context);
7254 #endif
7255         }
7256     }
7257 }
7258 
PhotoAccessGrantPhotoUriPermissionExecute(napi_env env,void * data)7259 static void PhotoAccessGrantPhotoUriPermissionExecute(napi_env env, void *data)
7260 {
7261     MediaLibraryTracer tracer;
7262     tracer.Start("PhotoAccessGrantPhotoUriPermissionExecute");
7263 
7264     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7265     if (context == nullptr) {
7266         NAPI_ERR_LOG("Async context is null");
7267         return;
7268     }
7269 
7270     string uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_APP_URI_PERMISSIONOPRN + "/" + OPRN_CREATE;
7271     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7272     Uri createUri(uri);
7273 
7274     int result = UserFileClient::Insert(createUri, context->valuesBucket);
7275     if (result < 0) {
7276         context->SaveError(result);
7277         NAPI_ERR_LOG("Insert fail, result: %{public}d.", result);
7278     } else {
7279         context->retVal = result;
7280     }
7281 }
7282 
PhotoAccessGrantPhotoUrisPermissionExecute(napi_env env,void * data)7283 static void PhotoAccessGrantPhotoUrisPermissionExecute(napi_env env, void *data)
7284 {
7285     MediaLibraryTracer tracer;
7286     tracer.Start("PhotoAccessGrantPhotoUrisPermissionExecute");
7287 
7288     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7289     if (context == nullptr) {
7290         NAPI_ERR_LOG("Async context is null");
7291         return;
7292     }
7293 
7294     string uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_APP_URI_PERMISSIONOPRN + "/" + OPRN_CREATE;
7295     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7296     Uri createUri(uri);
7297 
7298     int result = UserFileClient::BatchInsert(createUri, context->valuesBucketArray);
7299     if (result < 0) {
7300         context->SaveError(result);
7301         NAPI_ERR_LOG("BatchInsert fail, result: %{public}d.", result);
7302     } else {
7303         context->retVal = result;
7304     }
7305 }
7306 
PhotoAccessCancelPhotoUriPermissionExecute(napi_env env,void * data)7307 static void PhotoAccessCancelPhotoUriPermissionExecute(napi_env env, void *data)
7308 {
7309     MediaLibraryTracer tracer;
7310     tracer.Start("PhotoAccessCancelPhotoUriPermissionExecute");
7311 
7312     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7313     if (context == nullptr) {
7314         NAPI_ERR_LOG("Async context is null");
7315         return;
7316     }
7317 
7318     string uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_APP_URI_PERMISSIONOPRN + "/" + OPRN_DELETE;
7319     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7320     Uri deleteUri(uri);
7321 
7322     int result = UserFileClient::Delete(deleteUri, context->predicates);
7323     if (result < 0) {
7324         context->SaveError(result);
7325         NAPI_ERR_LOG("delete fail, result: %{public}d.", result);
7326     } else {
7327         context->retVal = result;
7328     }
7329 }
7330 
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)7331 napi_value MediaLibraryNapi::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
7332 {
7333     MediaLibraryTracer tracer;
7334     tracer.Start("PhotoAccessHelperCreatePhotoAsset");
7335 
7336     NAPI_INFO_LOG("enter");
7337 
7338     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7339     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7340     asyncContext->assetType = TYPE_PHOTO;
7341     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
7342 
7343     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
7344         PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
7345 }
7346 
PhotoAccessGrantPhotoUriPermission(napi_env env,napi_callback_info info)7347 napi_value MediaLibraryNapi::PhotoAccessGrantPhotoUriPermission(napi_env env, napi_callback_info info)
7348 {
7349     MediaLibraryTracer tracer;
7350     tracer.Start("PhotoAccessGrantPhotoUriPermission");
7351 
7352     NAPI_INFO_LOG("enter");
7353 
7354     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7355     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7356     asyncContext->assetType = TYPE_PHOTO;
7357     NAPI_ASSERT(env, ParseArgsGrantPhotoUriPermission(env, info, asyncContext), "Failed to parse js args");
7358 
7359     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUriPermission",
7360         PhotoAccessGrantPhotoUriPermissionExecute, JSPhotoUriPermissionCallback);
7361 }
7362 
PhotoAccessGrantPhotoUrisPermission(napi_env env,napi_callback_info info)7363 napi_value MediaLibraryNapi::PhotoAccessGrantPhotoUrisPermission(napi_env env, napi_callback_info info)
7364 {
7365     MediaLibraryTracer tracer;
7366     tracer.Start("PhotoAccessGrantPhotoUrisPermission");
7367 
7368     NAPI_INFO_LOG("enter");
7369 
7370     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7371     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7372     asyncContext->assetType = TYPE_PHOTO;
7373     NAPI_ASSERT(env, ParseArgsGrantPhotoUrisPermission(env, info, asyncContext), "Failed to parse js args");
7374 
7375     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUrisPermission",
7376         PhotoAccessGrantPhotoUrisPermissionExecute, JSPhotoUriPermissionCallback);
7377 }
7378 
PhotoAccessCancelPhotoUriPermission(napi_env env,napi_callback_info info)7379 napi_value MediaLibraryNapi::PhotoAccessCancelPhotoUriPermission(napi_env env, napi_callback_info info)
7380 {
7381     MediaLibraryTracer tracer;
7382     tracer.Start("PhotoAccessCancelPhotoUriPermission");
7383 
7384     NAPI_INFO_LOG("enter");
7385 
7386     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7387     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7388     asyncContext->assetType = TYPE_PHOTO;
7389     NAPI_ASSERT(env, ParseArgsCancelPhotoUriPermission(env, info, asyncContext), "Failed to parse js args");
7390 
7391     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessCancelPhotoUriPermission",
7392         PhotoAccessCancelPhotoUriPermissionExecute, JSPhotoUriPermissionCallback);
7393 }
7394 
PhotoAccessAgentCreateAssetsExecute(napi_env env,void * data)7395 static void PhotoAccessAgentCreateAssetsExecute(napi_env env, void *data)
7396 {
7397     MediaLibraryTracer tracer;
7398     tracer.Start("JSCreateAssetExecute");
7399 
7400     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7401     if (context == nullptr) {
7402         NAPI_ERR_LOG("Async context is null");
7403         return;
7404     }
7405 
7406     string uri;
7407     GetCreateUri(context, uri);
7408     Uri createFileUri(uri);
7409     for (const auto& valuesBucket : context->valuesBucketArray) {
7410         string outUri;
7411         int index = UserFileClient::InsertExt(createFileUri, valuesBucket, outUri);
7412         if (index < 0) {
7413             if (index == E_PERMISSION_DENIED) {
7414                 context->error = OHOS_PERMISSION_DENIED_CODE;
7415                 NAPI_ERR_LOG("PERMISSION_DENIED, index: %{public}d.", index);
7416                 return;
7417             }
7418 
7419             if (index == E_HAS_DB_ERROR) {
7420                 index = OHOS_INVALID_PARAM_CODE;
7421             }
7422             context->uriArray.push_back(to_string(index));
7423             bool isValid = false;
7424             string title = valuesBucket.Get(MediaColumn::MEDIA_TITLE, isValid);
7425             NAPI_ERR_LOG("InsertExt fail, index: %{public}d title: %{public}s.", index, title.c_str());
7426         } else {
7427             context->uriArray.push_back(move(outUri));
7428         }
7429     }
7430 }
7431 
ParseArgsCreateAgentCreateAssetsWithMode(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7432 static napi_value ParseArgsCreateAgentCreateAssetsWithMode(napi_env env, napi_callback_info info,
7433     unique_ptr<MediaLibraryAsyncContext> &context)
7434 {
7435     /* Parse the arguments */
7436     BundleInfo bundleInfo;
7437     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO],
7438         bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
7439     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
7440         bundleInfo.packageName) == napi_ok, "Failed to get appName");
7441     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_TWO],
7442         bundleInfo.appId) == napi_ok, "Failed to get appId");
7443 
7444     napi_value result = nullptr;
7445     NAPI_CALL(env, napi_get_boolean(env, true, &result));
7446 
7447     vector<napi_value> napiValues;
7448     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_FIVE], napiValues));
7449     if (napiValues.empty()) {
7450         return result;
7451     }
7452 
7453     for (const auto& napiValue : napiValues) {
7454         CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context) == napi_ok,
7455             "Parse asset create config failed");
7456     }
7457 
7458     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
7459         == napi_ok, "Failed to get callback");
7460     return result;
7461 }
7462 
ParseArgsAgentCreateAssetsWithMode(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7463 static napi_value ParseArgsAgentCreateAssetsWithMode(napi_env env, napi_callback_info info,
7464     unique_ptr<MediaLibraryAsyncContext> &context)
7465 {
7466     constexpr size_t minArgs = ARGS_SIX;
7467     constexpr size_t maxArgs = ARGS_SIX;
7468     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
7469         napi_ok, "Failed to get object info");
7470 
7471     context->isCreateByComponent = false;
7472     context->isCreateByAgent = true;
7473     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7474         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7475         return nullptr;
7476     }
7477 
7478     return ParseArgsCreateAgentCreateAssetsWithMode(env, info, context);
7479 }
7480 
PhotoAccessHelperAgentCreateAssetsWithMode(napi_env env,napi_callback_info info)7481 napi_value MediaLibraryNapi::PhotoAccessHelperAgentCreateAssetsWithMode(napi_env env, napi_callback_info info)
7482 {
7483     MediaLibraryTracer tracer;
7484     tracer.Start("PhotoAccessHelperAgentCreateAssetsWithMode");
7485 
7486     NAPI_INFO_LOG("enter");
7487     int32_t authorizationMode = -1;
7488     int32_t tokenId = -1;
7489     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7490     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7491     asyncContext->assetType = TYPE_PHOTO;
7492     NAPI_ASSERT(env, ParseArgsAgentCreateAssetsWithMode(env, info, asyncContext), "Failed to parse js args");
7493     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[ARGS_THREE], tokenId));
7494     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[ARGS_FOUR], authorizationMode));
7495     CHECK_COND_WITH_MESSAGE(env, authorizationMode == SaveType::SHORT_IMAGE_PERM, "authorizationMode is error");
7496 
7497     int ret = Security::AccessToken::AccessTokenKit::GrantPermissionForSpecifiedTime(
7498         tokenId, PERM_SHORT_TERM_WRITE_IMAGEVIDEO, THREE_HUNDERD_S);
7499     if (ret != E_SUCCESS) {
7500         NapiError::ThrowError(env, OHOS_PERMISSION_DENIED_CODE, "This app have no short permission");
7501         return nullptr;
7502     }
7503 
7504     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssetsWithMode",
7505         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
7506 }
7507 
PhotoAccessHelperAgentCreateAssets(napi_env env,napi_callback_info info)7508 napi_value MediaLibraryNapi::PhotoAccessHelperAgentCreateAssets(napi_env env, napi_callback_info info)
7509 {
7510     MediaLibraryTracer tracer;
7511     tracer.Start("PhotoAccessHelperAgentCreateAssets");
7512 
7513     NAPI_INFO_LOG("enter");
7514     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7515     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7516     asyncContext->assetType = TYPE_PHOTO;
7517     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7518         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7519         return nullptr;
7520     }
7521     NAPI_ASSERT(env, ParseArgsAgentCreateAssets(env, info, asyncContext), "Failed to parse js args");
7522 
7523     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssets",
7524         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
7525 }
7526 
CreateAssetsHasPermission(napi_env env,napi_callback_info info)7527 napi_value MediaLibraryNapi::CreateAssetsHasPermission(napi_env env, napi_callback_info info)
7528 {
7529     MediaLibraryTracer tracer;
7530     tracer.Start("PhotoAccessHelperAgentCreateAssets");
7531 
7532     NAPI_INFO_LOG("enter");
7533     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7534     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7535     asyncContext->assetType = TYPE_PHOTO;
7536     NAPI_ASSERT(env, ParseArgsAgentCreateAssets(env, info, asyncContext), "Failed to parse js args");
7537 
7538     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssets",
7539         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
7540 }
7541 
PhotoAccessHelperOnCallback(napi_env env,napi_callback_info info)7542 napi_value MediaLibraryNapi::PhotoAccessHelperOnCallback(napi_env env, napi_callback_info info)
7543 {
7544     MediaLibraryTracer tracer;
7545     tracer.Start("PhotoAccessHelperOnCallback");
7546     napi_value undefinedResult = nullptr;
7547     napi_get_undefined(env, &undefinedResult);
7548     size_t argc = ARGS_THREE;
7549     napi_value argv[ARGS_THREE] = {nullptr};
7550     napi_value thisVar = nullptr;
7551     GET_JS_ARGS(env, info, argc, argv, thisVar);
7552     if (argc == ARGS_TWO) {
7553         return JSOnCallback(env, info);
7554     }
7555     NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
7556     MediaLibraryNapi *obj = nullptr;
7557     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
7558     if (status == napi_ok && obj != nullptr) {
7559         napi_valuetype valueType = napi_undefined;
7560         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
7561             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
7562             napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
7563             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7564             return undefinedResult;
7565         }
7566         char buffer[ARG_BUF_SIZE];
7567         size_t res = 0;
7568         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
7569             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7570             return undefinedResult;
7571         }
7572         string uri = string(buffer);
7573         bool isDerived = false;
7574         if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
7575             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7576             return undefinedResult;
7577         }
7578         const int32_t refCount = 1;
7579         napi_ref cbOnRef = nullptr;
7580         napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
7581         tracer.Start("RegisterNotifyChange");
7582         if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
7583             obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
7584         } else {
7585             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7586             napi_delete_reference(env, cbOnRef);
7587             return undefinedResult;
7588         }
7589         tracer.Finish();
7590     }
7591     return undefinedResult;
7592 }
7593 
PhotoAccessHelperOffCallback(napi_env env,napi_callback_info info)7594 napi_value MediaLibraryNapi::PhotoAccessHelperOffCallback(napi_env env, napi_callback_info info)
7595 {
7596     MediaLibraryTracer tracer;
7597     tracer.Start("PhotoAccessHelperOffCallback");
7598     napi_value undefinedResult = nullptr;
7599     napi_get_undefined(env, &undefinedResult);
7600 
7601     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7602     napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
7603     MediaLibraryNapi *obj = nullptr;
7604     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
7605     if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
7606         return undefinedResult;
7607     }
7608     size_t res = 0;
7609     char buffer[ARG_BUF_SIZE];
7610     if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
7611         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7612         return undefinedResult;
7613     }
7614 
7615     string uri = string(buffer);
7616     napi_valuetype valueType = napi_undefined;
7617     if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
7618         if (asyncContext->argc == ARGS_TWO) {
7619             if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
7620                 return undefinedResult;
7621             }
7622             const int32_t refCount = 1;
7623             napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
7624         }
7625         obj->UnregisterChange(env, uri, *g_listObj);
7626         return undefinedResult;
7627     }
7628     napi_ref cbOffRef = nullptr;
7629     if (asyncContext->argc == ARGS_TWO) {
7630         if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
7631             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7632             return undefinedResult;
7633         }
7634         const int32_t refCount = 1;
7635         napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
7636     }
7637     tracer.Start("UnRegisterNotifyChange");
7638     obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
7639     return undefinedResult;
7640 }
7641 
ParseArgsPHAccessHelperTrash(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7642 napi_value ParseArgsPHAccessHelperTrash(napi_env env, napi_callback_info info,
7643     unique_ptr<MediaLibraryAsyncContext> &context)
7644 {
7645     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7646         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7647         return nullptr;
7648     }
7649 
7650     vector<string> uris;
7651     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringArrayCallback(env, info, context, uris),
7652         JS_ERR_PARAMETER_INVALID);
7653     if (uris.empty()) {
7654         NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
7655         return nullptr;
7656     }
7657     for (const auto &uri : uris) {
7658         if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
7659             NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
7660             return nullptr;
7661         }
7662     }
7663     context->uris = uris;
7664 
7665     napi_value result = nullptr;
7666     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7667     return result;
7668 }
7669 
PhotoAccessHelperTrashExecute(napi_env env,void * data)7670 static void PhotoAccessHelperTrashExecute(napi_env env, void *data)
7671 {
7672     MediaLibraryTracer tracer;
7673     tracer.Start("PhotoAccessHelperTrashExecute");
7674 
7675     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7676     string trashUri = PAH_TRASH_PHOTO;
7677     MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7678     Uri updateAssetUri(trashUri);
7679     DataSharePredicates predicates;
7680     predicates.In(MediaColumn::MEDIA_ID, context->uris);
7681     DataShareValuesBucket valuesBucket;
7682     valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
7683     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
7684     if (changedRows < 0) {
7685         context->SaveError(changedRows);
7686         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
7687     }
7688 }
7689 
PhotoAccessHelperTrashAsset(napi_env env,napi_callback_info info)7690 napi_value MediaLibraryNapi::PhotoAccessHelperTrashAsset(napi_env env, napi_callback_info info)
7691 {
7692     napi_value ret = nullptr;
7693     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7694     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
7695     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7696     CHECK_NULLPTR_RET(ParseArgsPHAccessHelperTrash(env, info, asyncContext));
7697     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperTrashAsset",
7698         PhotoAccessHelperTrashExecute, JSTrashAssetCompleteCallback);
7699 }
7700 
ParseArgsSetHidden(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7701 napi_value ParseArgsSetHidden(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
7702 {
7703     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7704         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7705         return nullptr;
7706     }
7707     napi_value result = nullptr;
7708     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7709 
7710     constexpr size_t minArgs = ARGS_ONE;
7711     constexpr size_t maxArgs = ARGS_THREE;
7712     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
7713         JS_ERR_PARAMETER_INVALID);
7714 
7715     /* Parse the first argument */
7716     vector<napi_value> napiValues;
7717     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM0], napiValues));
7718     if (napiValues.empty()) {
7719         return result;
7720     }
7721     napi_valuetype valueType = napi_undefined;
7722     vector<string> uris;
7723     CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_ERR_PARAMETER_INVALID);
7724     if (valueType == napi_string) {
7725         // The input should be an array of asset uri.
7726         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetStringArray(env, napiValues, uris));
7727     } else if (valueType == napi_object) {
7728         // The input should be an array of asset object.
7729         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uris));
7730     }
7731     if (uris.empty()) {
7732         return result;
7733     }
7734     bool hiddenState = false;
7735     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[PARAM1], hiddenState),
7736         JS_ERR_PARAMETER_INVALID);
7737     context->predicates.In(MediaColumn::MEDIA_ID, uris);
7738     context->valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, static_cast<int32_t>(hiddenState));
7739     return result;
7740 }
7741 
SetHiddenExecute(napi_env env,void * data)7742 static void SetHiddenExecute(napi_env env, void *data)
7743 {
7744     MediaLibraryTracer tracer;
7745     tracer.Start("SetHiddenExecute");
7746 
7747     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7748     string hideUri = PAH_HIDE_PHOTOS;
7749     MediaLibraryNapiUtils::UriAppendKeyValue(hideUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7750     Uri uri(hideUri);
7751     int32_t changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
7752     if (changedRows < 0) {
7753         context->SaveError(changedRows);
7754         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
7755     }
7756 }
7757 
SetHiddenCompleteCallback(napi_env env,napi_status status,void * data)7758 static void SetHiddenCompleteCallback(napi_env env, napi_status status, void *data)
7759 {
7760     MediaLibraryTracer tracer;
7761     tracer.Start("SetHiddenCompleteCallback");
7762 
7763     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7764     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7765     jsContext->status = false;
7766     if (context->error == ERR_DEFAULT) {
7767         jsContext->status = true;
7768         napi_get_undefined(env, &jsContext->error);
7769         napi_get_undefined(env, &jsContext->data);
7770     } else {
7771         napi_get_undefined(env, &jsContext->data);
7772         context->HandleError(env, jsContext->error);
7773     }
7774     if (context->work != nullptr) {
7775         tracer.Finish();
7776         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7777             context->work, *jsContext);
7778     }
7779 
7780     delete context;
7781 }
7782 
SetHidden(napi_env env,napi_callback_info info)7783 napi_value MediaLibraryNapi::SetHidden(napi_env env, napi_callback_info info)
7784 {
7785     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
7786     CHECK_NULLPTR_RET(ParseArgsSetHidden(env, info, asyncContext));
7787     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "SetHidden",
7788         SetHiddenExecute, SetHiddenCompleteCallback);
7789 }
7790 
ParseHiddenPhotosDisplayMode(napi_env env,const unique_ptr<MediaLibraryAsyncContext> & context,const int32_t fetchMode)7791 napi_value ParseHiddenPhotosDisplayMode(napi_env env,
7792     const unique_ptr<MediaLibraryAsyncContext> &context, const int32_t fetchMode)
7793 {
7794     switch (fetchMode) {
7795         case ASSETS_MODE:
7796             context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::HIDDEN);
7797             break;
7798         case ALBUMS_MODE:
7799             context->predicates.EqualTo(PhotoAlbumColumns::CONTAINS_HIDDEN, to_string(1));
7800             break;
7801         default:
7802             NapiError::ThrowError(
7803                 env, OHOS_INVALID_PARAM_CODE, "Invalid fetch mode: " + to_string(fetchMode));
7804             return nullptr;
7805     }
7806     napi_value result = nullptr;
7807     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7808     return result;
7809 }
7810 
ParseArgsGetHiddenAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7811 napi_value ParseArgsGetHiddenAlbums(napi_env env, napi_callback_info info,
7812     unique_ptr<MediaLibraryAsyncContext> &context)
7813 {
7814     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7815         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7816         return nullptr;
7817     }
7818     napi_value result = nullptr;
7819     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7820 
7821     constexpr size_t minArgs = ARGS_ONE;
7822     constexpr size_t maxArgs = ARGS_THREE;
7823     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
7824         OHOS_INVALID_PARAM_CODE);
7825 
7826     bool hasCallback = false;
7827     CHECK_ARGS(env, MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
7828         OHOS_INVALID_PARAM_CODE);
7829     if (context->argc == ARGS_THREE) {
7830         napi_valuetype valueType = napi_undefined;
7831         if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
7832             (valueType == napi_undefined || valueType == napi_null)) {
7833             context->argc -= 1;
7834         }
7835     }
7836     int32_t fetchMode = 0;
7837     switch (context->argc - hasCallback) {
7838         case ARGS_ONE:
7839             CHECK_ARGS(
7840                 env, MediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode), OHOS_INVALID_PARAM_CODE);
7841             break;
7842         case ARGS_TWO:
7843             CHECK_ARGS(
7844                 env, MediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode), OHOS_INVALID_PARAM_CODE);
7845             CHECK_ARGS(
7846                 env, MediaLibraryNapiUtils::GetFetchOption(
7847                     env, context->argv[PARAM1], ALBUM_FETCH_OPT, context), OHOS_INVALID_PARAM_CODE);
7848             break;
7849         default:
7850             NapiError::ThrowError(
7851                 env, OHOS_INVALID_PARAM_CODE, "Invalid parameter count: " + to_string(context->argc));
7852             return nullptr;
7853     }
7854     CHECK_NULLPTR_RET(ParseHiddenPhotosDisplayMode(env, context, fetchMode));
7855     CHECK_NULLPTR_RET(AddDefaultPhotoAlbumColumns(env, context->fetchColumn));
7856     context->hiddenAlbumFetchMode = fetchMode;
7857     if (fetchMode == HiddenPhotosDisplayMode::ASSETS_MODE) {
7858         return result;
7859     }
7860     context->hiddenOnly = true;
7861     context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COUNT);
7862     context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COVER);
7863     return result;
7864 }
7865 
PahGetHiddenAlbums(napi_env env,napi_callback_info info)7866 napi_value MediaLibraryNapi::PahGetHiddenAlbums(napi_env env, napi_callback_info info)
7867 {
7868     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
7869     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7870     CHECK_NULLPTR_RET(ParseArgsGetHiddenAlbums(env, info, asyncContext));
7871     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetHiddenAlbums",
7872         JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
7873 }
7874 
JSApplyChanges(napi_env env,napi_callback_info info)7875 napi_value MediaLibraryNapi::JSApplyChanges(napi_env env, napi_callback_info info)
7876 {
7877     size_t argc = ARGS_TWO;
7878     napi_value argv[ARGS_TWO] = { 0 };
7879     napi_value thisVar = nullptr;
7880     napi_valuetype valueType;
7881     MediaLibraryNapi* mediaLibraryNapi;
7882     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
7883     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&mediaLibraryNapi)), JS_INNER_FAIL);
7884     CHECK_COND_WITH_MESSAGE(env, mediaLibraryNapi != nullptr, "Failed to get object info");
7885 
7886     CHECK_COND_WITH_MESSAGE(env, argc >= ARGS_ONE && argc <= ARGS_TWO, "Number of args is invalid");
7887     CHECK_ARGS(env, napi_typeof(env, argv[PARAM0], &valueType), JS_INNER_FAIL);
7888     CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
7889 
7890     MediaChangeRequestNapi* obj;
7891     CHECK_ARGS(env, napi_unwrap(env, argv[PARAM0], reinterpret_cast<void**>(&obj)), JS_INNER_FAIL);
7892     CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "MediaChangeRequestNapi object is null");
7893     return obj->ApplyChanges(env, info);
7894 }
7895 
initRequest(OHOS::AAFwk::Want & request,shared_ptr<DeleteCallback> & callback,napi_env env,napi_value args[],size_t argsLen)7896 static napi_value initRequest(OHOS::AAFwk::Want &request, shared_ptr<DeleteCallback> &callback,
7897                               napi_env env, napi_value args[], size_t argsLen)
7898 {
7899     if (argsLen < ARGS_THREE) {
7900         return nullptr;
7901     }
7902     napi_value result = nullptr;
7903     napi_create_object(env, &result);
7904     request.SetElementName(DELETE_UI_PACKAGE_NAME, DELETE_UI_EXT_ABILITY_NAME);
7905     request.SetParam(DELETE_UI_EXTENSION_TYPE, DELETE_UI_REQUEST_TYPE);
7906 
7907     size_t nameRes = 0;
7908     char nameBuffer[ARG_BUF_SIZE];
7909     if (napi_get_value_string_utf8(env, args[ARGS_ONE], nameBuffer, ARG_BUF_SIZE, &nameRes) != napi_ok) {
7910         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7911         return nullptr;
7912     }
7913     string appName = string(nameBuffer);
7914     request.SetParam(DELETE_UI_APPNAME, appName);
7915 
7916     vector<string> uris;
7917     uint32_t len = 0;
7918     CHECK_ARGS(env, napi_get_array_length(env, args[ARGS_TWO], &len), JS_ERR_PARAMETER_INVALID);
7919     char uriBuffer[ARG_BUF_SIZE];
7920     for (uint32_t i = 0; i < len; i++) {
7921         napi_value uri = nullptr;
7922         CHECK_ARGS(env, napi_get_element(env, args[ARGS_TWO], i, &uri), JS_ERR_PARAMETER_INVALID);
7923         if (uri == nullptr) {
7924             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
7925             return nullptr;
7926         }
7927         size_t uriRes = 0;
7928         CHECK_ARGS(env, napi_get_value_string_utf8(env, uri, uriBuffer, ARG_BUF_SIZE, &uriRes),
7929                    JS_ERR_PARAMETER_INVALID);
7930         uris.push_back(string(uriBuffer));
7931     }
7932     request.SetParam(DELETE_UI_URIS, uris);
7933     callback->SetUris(uris);
7934     callback->SetFunc(args[ARGS_THREE]);
7935     return result;
7936 }
7937 
CreateDeleteRequest(napi_env env,napi_callback_info info)7938 napi_value MediaLibraryNapi::CreateDeleteRequest(napi_env env, napi_callback_info info)
7939 {
7940     size_t argc = ARGS_FOUR;
7941     napi_value args[ARGS_FOUR] = {nullptr};
7942     napi_value thisVar = nullptr;
7943     napi_value result = nullptr;
7944     napi_create_object(env, &result);
7945     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
7946     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
7947     NAPI_ASSERT(env, context != nullptr, "context == nullptr");
7948 
7949     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
7950         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
7951     NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
7952 
7953     auto uiContent = abilityContext->GetUIContent();
7954     NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
7955 
7956     auto callback = std::make_shared<DeleteCallback>(env, uiContent);
7957     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
7958         ([callback](auto arg) { callback->OnRelease(arg); }),
7959         ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
7960         ([callback](auto arg) { callback->OnReceive(arg); }),
7961         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
7962     };
7963     OHOS::Ace::ModalUIExtensionConfig config;
7964     config.isProhibitBack = true;
7965     OHOS::AAFwk::Want request;
7966     napi_value initRequestResult = initRequest(request, callback, env, args, sizeof(args));
7967     NAPI_ASSERT(env, initRequestResult != nullptr, "initRequest fail");
7968 
7969     int32_t sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
7970     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
7971 
7972     callback->SetSessionId(sessionId);
7973     return result;
7974 }
7975 
ParseString(const napi_env & env,const napi_value & value,std::string & result)7976 static bool ParseString(const napi_env &env, const napi_value &value, std::string &result)
7977 {
7978     size_t size = 0;
7979 
7980     CHECK_COND_RET(napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok, false,
7981         "Failed to get string length.");
7982 
7983     result.reserve(size + 1);
7984     result.resize(size);
7985 
7986     CHECK_COND_RET(napi_get_value_string_utf8(env, value, result.data(), size + 1, &size) == napi_ok, false,
7987         "Failed to get string value.");
7988 
7989     return true;
7990 }
7991 
ParseAndSetFileUriArray(const napi_env & env,OHOS::AAFwk::Want & want,const napi_value & value)7992 static bool ParseAndSetFileUriArray(const napi_env &env, OHOS::AAFwk::Want &want, const napi_value &value)
7993 {
7994     uint32_t len = 0;
7995     CHECK_COND_RET(napi_get_array_length(env, value, &len) == napi_ok, false, "Failed to get array length.");
7996     if (len > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
7997         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Array size over 100.");
7998         return false;
7999     }
8000 
8001     vector<string> srcFileUris;
8002     for (uint32_t i = 0; i < len; ++i) {
8003         napi_value element = nullptr;
8004         CHECK_COND_RET(napi_get_element(env, value, i, &element) == napi_ok, false, "Failed to get array element.");
8005         if (element == nullptr) {
8006             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get array element.");
8007             return false;
8008         }
8009 
8010         string srcFileUri;
8011         if (!ParseString(env, element, srcFileUri)) {
8012             return false;
8013         }
8014 
8015         srcFileUris.emplace_back(srcFileUri);
8016     }
8017 
8018     want.SetParam(CONFIRM_BOX_SRC_FILE_URIS, srcFileUris);
8019 
8020     return true;
8021 }
8022 
IsNeedParseProperty(const napi_env & env,const napi_value & value,const string & key,napi_value & property,napi_valuetype & needType)8023 static bool IsNeedParseProperty(const napi_env &env, const napi_value &value, const string &key, napi_value &property,
8024     napi_valuetype &needType)
8025 {
8026     bool hasProp = false;
8027     napi_valuetype valueType = napi_undefined;
8028 
8029     CHECK_COND_RET(napi_has_named_property(env, value, key.c_str(), &hasProp) == napi_ok, false,
8030         "Failed to check named property.");
8031     if (hasProp) {
8032         CHECK_COND_RET(napi_get_named_property(env, value, key.c_str(), &property) == napi_ok, false,
8033             "Failed to get named property.");
8034         CHECK_COND_RET(napi_typeof(env, property, &valueType) == napi_ok, false, "Failed to get value type.");
8035 
8036         return ((valueType != napi_undefined) && (valueType != napi_null) && (valueType == needType));
8037     }
8038 
8039     return hasProp;
8040 }
8041 
ParseConfigObject(const napi_env & env,const napi_value & value,PhotoCreationConfig & config)8042 static bool ParseConfigObject(const napi_env &env, const napi_value &value, PhotoCreationConfig &config)
8043 {
8044     napi_value property = nullptr;
8045     napi_valuetype type = napi_undefined;
8046 
8047     // title: optional
8048     type = napi_string;
8049     if (IsNeedParseProperty(env, value, TITLE, property, type)) {
8050         NAPI_INFO_LOG("With title.");
8051         if (!ParseString(env, property, config.title)) {
8052             return false;
8053         }
8054     }
8055 
8056     // fileNameExtension: mandatory
8057     CHECK_COND_RET(IsNeedParseProperty(env, value, EXTENSION, property, type), false, "Lack param fileNameExtension.");
8058     if (!ParseString(env, property, config.fileNameExtension)) {
8059         return false;
8060     }
8061 
8062     // photoType: mandatory
8063     type = napi_number;
8064     CHECK_COND_RET(IsNeedParseProperty(env, value, PHOTO_TYPE, property, type), false, "Lack param photoType.");
8065     CHECK_COND_RET(napi_get_value_int32(env, property, &(config.photoType)) == napi_ok, false,
8066         "Failed to get number type.");
8067     CHECK_COND_RET(((config.photoType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) || (
8068         (config.photoType) == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO))), false,
8069         "Param photoType is not valid.");
8070 
8071     // subtype: optional
8072     if (IsNeedParseProperty(env, value, PHOTO_SUB_TYPE, property, type)) {
8073         NAPI_INFO_LOG("With subtype.");
8074         CHECK_COND_RET(napi_get_value_int32(env, property, &(config.subtype)) == napi_ok, false,
8075             "Failed to get number type.");
8076         CHECK_COND_RET(((config.subtype == static_cast<int32_t>(PhotoSubType::DEFAULT)) || (
8077             (config.subtype) == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO))), false,
8078             "Param subtype is not valid.");
8079     }
8080 
8081     return true;
8082 }
8083 
ParseAndSetConfigArray(const napi_env & env,OHOS::AAFwk::Want & want,const napi_value & value)8084 static bool ParseAndSetConfigArray(const napi_env &env, OHOS::AAFwk::Want &want, const napi_value &value)
8085 {
8086     uint32_t len = 0;
8087     CHECK_COND_RET(napi_get_array_length(env, value, &len) == napi_ok, false, "Failed to get array length.");
8088     if (len > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
8089         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Array size over 100.");
8090         return false;
8091     }
8092 
8093     vector<string> titleList;
8094     vector<string> extensionList;
8095     vector<int32_t> photoTypeList;
8096     vector<int32_t> photoSubTypeList;
8097 
8098     for (uint32_t i = 0; i < len; ++i) {
8099         napi_value element = nullptr;
8100         CHECK_COND_RET(napi_get_element(env, value, i, &element) == napi_ok, false, "Failed to get array element.");
8101         if (element == nullptr) {
8102             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get array element.");
8103             return false;
8104         }
8105 
8106         PhotoCreationConfig config;
8107         if (!ParseConfigObject(env, element, config)) {
8108             return false;
8109         }
8110 
8111         titleList.emplace_back(config.title);
8112         extensionList.emplace_back(config.fileNameExtension);
8113         photoTypeList.emplace_back(config.photoType);
8114         photoSubTypeList.emplace_back(config.subtype);
8115     }
8116 
8117     // separate Array<PhotoCreationConfig> into Array<string> + Array<string> + Array<number> + Array<number>
8118     want.SetParam(CONFIRM_BOX_TITLE_ARRAY, titleList);
8119     want.SetParam(CONFIRM_BOX_EXTENSION_ARRAY, extensionList);
8120     want.SetParam(CONFIRM_BOX_PHOTO_TYPE_ARRAY, photoTypeList);
8121     want.SetParam(CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY, photoSubTypeList);
8122 
8123     return true;
8124 }
8125 
InitConfirmRequest(OHOS::AAFwk::Want & want,shared_ptr<ConfirmCallback> & callback,napi_env env,napi_value args[],size_t argsLen)8126 static bool InitConfirmRequest(OHOS::AAFwk::Want &want, shared_ptr<ConfirmCallback> &callback,
8127                                napi_env env, napi_value args[], size_t argsLen)
8128 {
8129     if (argsLen < ARGS_SEVEN) {
8130         return false;
8131     }
8132 
8133     want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
8134     want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
8135     want.AddFlags(Want::FLAG_AUTH_READ_URI_PERMISSION);
8136 
8137     // second param: Array<string>
8138     if (!ParseAndSetFileUriArray(env, want, args[PARAM1])) {
8139         return false;
8140     }
8141 
8142     // third param: Array<PhotoCreationConfig>
8143     if (!ParseAndSetConfigArray(env, want, args[PARAM2])) {
8144         return false;
8145     }
8146 
8147     // fourth param: string
8148     string bundleName;
8149     if (!ParseString(env, args[PARAM3], bundleName)) {
8150         return false;
8151     }
8152     want.SetParam(CONFIRM_BOX_BUNDLE_NAME, bundleName);
8153 
8154     // fifth param: string
8155     string appName;
8156     if (!ParseString(env, args[PARAM4], appName)) {
8157         return false;
8158     }
8159     want.SetParam(CONFIRM_BOX_APP_NAME, appName);
8160 
8161     // sixth param: string
8162     string appId;
8163     if (!ParseString(env, args[PARAM5], appId)) {
8164         return false;
8165     }
8166     want.SetParam(CONFIRM_BOX_APP_ID, appId);
8167 
8168     // seventh param: function
8169     callback->SetFunc(args[PARAM6]);
8170 
8171     return true;
8172 }
8173 
ShowAssetsCreationDialog(napi_env env,napi_callback_info info)8174 napi_value MediaLibraryNapi::ShowAssetsCreationDialog(napi_env env, napi_callback_info info)
8175 {
8176     size_t argc = ARGS_SEVEN;
8177     napi_value args[ARGS_SEVEN] = {nullptr};
8178     napi_value thisVar = nullptr;
8179     napi_value result = nullptr;
8180     napi_create_object(env, &result);
8181     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), OHOS_INVALID_PARAM_CODE);
8182 
8183     // first param: context, check whether context is abilityContext from stage mode
8184     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
8185     NAPI_ASSERT(env, context != nullptr, "Context is null.");
8186 
8187     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
8188         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
8189     NAPI_ASSERT(env, abilityContext != nullptr, "AbilityContext is null.");
8190 
8191     // get uiContent from abilityContext, this api should be called after loadContent, otherwise uiContent is nullptr
8192     auto uiContent = abilityContext->GetUIContent();
8193     NAPI_ASSERT(env, uiContent != nullptr, "UiContent is null.");
8194 
8195     // set want
8196     OHOS::AAFwk::Want want;
8197     auto callback = std::make_shared<ConfirmCallback>(env, uiContent);
8198     NAPI_ASSERT(env, InitConfirmRequest(want, callback, env, args, sizeof(args)), "Parse input fail.");
8199 
8200     // regist callback and config
8201     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
8202         [callback](int32_t releaseCode) {
8203             callback->OnRelease(releaseCode);
8204         },
8205         [callback](int32_t resultCode, const AAFwk::Want &result) {
8206             callback->OnResult(resultCode, result);
8207         },
8208         [callback](const AAFwk::WantParams &receive) {
8209             callback->OnReceive(receive);
8210         },
8211         [callback](int32_t code, const std::string &name, const std::string &message) {
8212             callback->OnError(code, name, name);
8213         },
8214     };
8215     OHOS::Ace::ModalUIExtensionConfig config;
8216     config.isProhibitBack = true;
8217 
8218     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
8219     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
8220 
8221     NAPI_INFO_LOG("SessionId is %{public}d.", sessionId);
8222 
8223     callback->SetSessionId(sessionId);
8224     return result;
8225 }
8226 
CheckShortTermPermission(napi_env env,napi_callback_info info)8227 napi_value MediaLibraryNapi::CheckShortTermPermission(napi_env env, napi_callback_info info)
8228 {
8229     AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
8230     int res = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_SHORT_TERM_WRITE_IMAGEVIDEO);
8231     napi_value result = nullptr;
8232     CHECK_ARGS(env, napi_get_boolean(env, res == PermissionState::PERMISSION_GRANTED, &result), JS_INNER_FAIL);
8233     return result;
8234 }
8235 
InitShortTermRequest(OHOS::AAFwk::Want & want,shared_ptr<ShortTermCallback> & callback,napi_env env,napi_value args[],size_t argsLen)8236 static bool InitShortTermRequest(OHOS::AAFwk::Want &want, shared_ptr<ShortTermCallback> &callback,
8237                                  napi_env env, napi_value args[], size_t argsLen)
8238 {
8239     if (argsLen < ARGS_SIX) {
8240         return false;
8241     }
8242 
8243     want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
8244     want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
8245 
8246     if (args[PARAM1] == nullptr) {
8247         return false;
8248     }
8249 
8250     PhotoCreationConfig config;
8251     napi_value element = args[PARAM1];
8252     if (!ParseConfigObject(env, element, config)) {
8253         return false;
8254     }
8255     want.SetParam(SHORT_TERM_TAG, true);
8256     want.SetParam(SHORT_TERM_TITLE, config.title);
8257     want.SetParam(SHORT_TERM_EXTENSION, config.fileNameExtension);
8258     want.SetParam(SHORT_TERM_PHOTO_TYPE, config.photoType);
8259     want.SetParam(SHORT_TERM_PHOTO_SUB_TYPE, config.subtype);
8260 
8261     string bundleName;
8262     if (!ParseString(env, args[PARAM2], bundleName)) {
8263         return false;
8264     }
8265     want.SetParam(CONFIRM_BOX_BUNDLE_NAME, bundleName);
8266 
8267     string appName;
8268     if (!ParseString(env, args[PARAM3], appName)) {
8269         return false;
8270     }
8271     want.SetParam(CONFIRM_BOX_APP_NAME, appName);
8272 
8273     string appId;
8274     if (!ParseString(env, args[PARAM4], appId)) {
8275         return false;
8276     }
8277     want.SetParam(CONFIRM_BOX_APP_ID, appId);
8278 
8279     callback->SetFunc(args[PARAM5]);
8280     return true;
8281 }
8282 
CreateAssetWithShortTermPermission(napi_env env,napi_callback_info info)8283 napi_value MediaLibraryNapi::CreateAssetWithShortTermPermission(napi_env env, napi_callback_info info)
8284 {
8285     NAPI_INFO_LOG("CreateAssetWithShortTermPermission enter");
8286     size_t argc = ARGS_SIX;
8287     napi_value args[ARGS_SIX] = {nullptr};
8288     napi_value thisVar = nullptr;
8289     napi_value result = nullptr;
8290     napi_create_object(env, &result);
8291     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
8292     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
8293     NAPI_ASSERT(env, context != nullptr, "context == nullptr");
8294 
8295     shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
8296         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
8297     NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
8298 
8299     auto uiContent = abilityContext->GetUIContent();
8300     NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
8301 
8302     OHOS::AAFwk::Want want;
8303     shared_ptr<ShortTermCallback> callback = make_shared<ShortTermCallback>(env, uiContent);
8304     NAPI_ASSERT(env, InitShortTermRequest(want, callback, env, args, sizeof(args)), "parse short term param fail");
8305 
8306     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
8307         ([callback](auto arg) { callback->OnRelease(arg); }),
8308         ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
8309         ([callback](auto arg) { callback->OnReceive(arg); }),
8310         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
8311     };
8312     OHOS::Ace::ModalUIExtensionConfig config;
8313     config.isProhibitBack = true;
8314     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
8315     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
8316     callback->SetSessionId(sessionId);
8317     return result;
8318 }
8319 
StartPhotoPickerExecute(napi_env env,void * data)8320 static void StartPhotoPickerExecute(napi_env env, void *data)
8321 {
8322     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8323     while (!context->pickerCallBack->ready) {
8324         std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
8325     }
8326 }
8327 
StartPhotoPickerAsyncCallbackComplete(napi_env env,napi_status status,void * data)8328 static void StartPhotoPickerAsyncCallbackComplete(napi_env env, napi_status status, void *data)
8329 {
8330     NAPI_INFO_LOG("StartPhotoPickerAsyncCallbackComplete start");
8331     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8332     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
8333 
8334     auto jsContext = make_unique<JSAsyncContextOutput>();
8335     jsContext->status = false;
8336     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
8337     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_ERR_PARAMETER_INVALID);
8338     napi_value result = nullptr;
8339     napi_create_object(env, &result);
8340     napi_value resultCode = nullptr;
8341     napi_create_int32(env, context->pickerCallBack->resultCode, &resultCode);
8342     status = napi_set_named_property(env, result, "resultCode", resultCode);
8343     if (status != napi_ok) {
8344         NAPI_ERR_LOG("napi_set_named_property resultCode failed");
8345     }
8346     const vector<string> &uris = context->pickerCallBack->uris;
8347     napi_value jsUris = nullptr;
8348     napi_create_array_with_length(env, uris.size(), &jsUris);
8349     napi_value jsUri = nullptr;
8350     for (size_t i = 0; i < uris.size(); i++) {
8351         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, uris[i].c_str(),
8352             NAPI_AUTO_LENGTH, &jsUri), JS_INNER_FAIL);
8353         if ((jsUri == nullptr) || (napi_set_element(env, jsUris, i, jsUri) != napi_ok)) {
8354             NAPI_ERR_LOG("failed to set uri array");
8355             break;
8356         }
8357     }
8358     if (napi_set_named_property(env, result, "uris", jsUris) != napi_ok) {
8359         NAPI_ERR_LOG("napi_set_named_property uris failed");
8360     }
8361     napi_value isOrigin = nullptr;
8362     napi_get_boolean(env, context->pickerCallBack->isOrigin, &isOrigin);
8363     status = napi_set_named_property(env, result, "isOrigin", isOrigin);
8364     if (status != napi_ok) {
8365         NAPI_ERR_LOG("napi_set_named_property isOrigin failed");
8366     }
8367     if (result != nullptr) {
8368         jsContext->data = result;
8369         jsContext->status = true;
8370     } else {
8371         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
8372             "failed to create js object");
8373     }
8374     if (context->work != nullptr) {
8375         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
8376             context->work, *jsContext);
8377     }
8378     delete context;
8379 }
8380 
GetSubWindowUIContent(napi_env env,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)8381 Ace::UIContent *GetSubWindowUIContent(napi_env env, unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
8382 {
8383     bool present = false;
8384     napi_status status = napi_has_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &present);
8385     if (status != napi_ok || !present) {
8386         return nullptr;
8387     }
8388     napi_value paramValue;
8389     status = napi_get_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &paramValue);
8390     CHECK_COND_RET(status == napi_ok, nullptr, "failed to get named property of parameters");
8391     present = false;
8392     status = napi_has_named_property(env, paramValue, "subWindowName", &present);
8393     if (status != napi_ok || !present) {
8394         return nullptr;
8395     }
8396     napi_value subWindowName;
8397     status = napi_get_named_property(env, paramValue, "subWindowName", &subWindowName);
8398     CHECK_COND_RET(status == napi_ok, nullptr, "failed to get named property of subWindowName");
8399     char buffer[ARG_BUF_SIZE];
8400     size_t res = 0;
8401     status = napi_get_value_string_utf8(env, subWindowName, buffer, ARG_BUF_SIZE, &res);
8402     if (status != napi_ok) {
8403         NAPI_ERR_LOG("failed to get the value of subWindow name");
8404         return nullptr;
8405     }
8406     auto currentWindow = Rosen::Window::Find(string(buffer));
8407     if (currentWindow == nullptr) {
8408         NAPI_ERR_LOG("GetSubWindowUIContent failed to find context by subWindow name");
8409         return nullptr;
8410     }
8411     return currentWindow->GetUIContent();
8412 }
8413 
GetUIContent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)8414 Ace::UIContent *GetUIContent(napi_env env, napi_callback_info info,
8415     unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
8416 {
8417     NAPI_INFO_LOG("GetUIContent start");
8418     Ace::UIContent *uiContent = GetSubWindowUIContent(env, AsyncContext);
8419     if (uiContent != nullptr) {
8420         NAPI_INFO_LOG("GetSubWindowUIContent success");
8421         return uiContent;
8422     }
8423 
8424     bool isStageMode = false;
8425     napi_status status = AbilityRuntime::IsStageContext(env, AsyncContext->argv[ARGS_ZERO], isStageMode);
8426     if (status != napi_ok || !isStageMode) {
8427         NAPI_ERR_LOG("is not StageMode context");
8428         return nullptr;
8429     }
8430     auto context = AbilityRuntime::GetStageModeContext(env, AsyncContext->argv[ARGS_ZERO]);
8431     if (context == nullptr) {
8432         NAPI_ERR_LOG("Failed to get native stage context instance");
8433         return nullptr;
8434     }
8435     auto abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
8436     if (abilityContext == nullptr) {
8437         auto uiExtensionContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
8438         if (uiExtensionContext == nullptr) {
8439             NAPI_ERR_LOG("Fail to convert to abilityContext or uiExtensionContext");
8440             return nullptr;
8441         }
8442         return uiExtensionContext->GetUIContent();
8443     }
8444     return abilityContext->GetUIContent();
8445 }
8446 
StartPickerExtension(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)8447 static napi_value StartPickerExtension(napi_env env, napi_callback_info info,
8448     unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
8449 {
8450     NAPI_INFO_LOG("StartPickerExtension start");
8451     Ace::UIContent *uiContent = GetUIContent(env, info, AsyncContext);
8452     if (uiContent == nullptr) {
8453         NAPI_ERR_LOG("get uiContent failed");
8454         return nullptr;
8455     }
8456     AAFwk::Want request;
8457     AppExecFwk::UnwrapWant(env, AsyncContext->argv[ARGS_ONE], request);
8458     std::string targetType = "photoPicker";
8459     request.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
8460     AsyncContext->pickerCallBack = make_shared<PickerCallBack>();
8461     auto callback = std::make_shared<ModalUICallback>(uiContent, AsyncContext->pickerCallBack.get());
8462     Ace::ModalUIExtensionCallbacks extensionCallback = {
8463         ([callback](auto arg) { callback->OnRelease(arg); }),
8464         ([callback](auto arg1, auto arg2) { callback->OnResultForModal(arg1, arg2); }),
8465         ([callback](auto arg) { callback->OnReceive(arg); }),
8466         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
8467         std::bind(&ModalUICallback::OnDestroy, callback),
8468     };
8469     Ace::ModalUIExtensionConfig config;
8470     config.isProhibitBack = true;
8471     int sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
8472     if (sessionId == 0) {
8473         NAPI_ERR_LOG("create modalUIExtension failed");
8474         return nullptr;
8475     }
8476     callback->SetSessionId(sessionId);
8477     napi_value result = nullptr;
8478     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8479     return result;
8480 }
8481 
8482 template <class AsyncContext>
AsyncContextSetStaticObjectInfo(napi_env env,napi_callback_info info,AsyncContext & asyncContext,const size_t minArgs,const size_t maxArgs)8483 static napi_status AsyncContextSetStaticObjectInfo(napi_env env, napi_callback_info info,
8484     AsyncContext &asyncContext, const size_t minArgs, const size_t maxArgs)
8485 {
8486     NAPI_INFO_LOG("AsyncContextSetStaticObjectInfo start");
8487     napi_value thisVar = nullptr;
8488     asyncContext->argc = maxArgs;
8489     CHECK_STATUS_RET(napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]), &thisVar,
8490         nullptr), "Failed to get cb info");
8491     CHECK_COND_RET(((asyncContext->argc >= minArgs) && (asyncContext->argc <= maxArgs)), napi_invalid_arg,
8492         "Number of args is invalid");
8493     if (minArgs > 0) {
8494         CHECK_COND_RET(asyncContext->argv[ARGS_ZERO] != nullptr, napi_invalid_arg, "Argument list is empty");
8495     }
8496     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamCallback(env, asyncContext), "Failed to get callback param!");
8497     return napi_ok;
8498 }
8499 
ParseArgsStartPhotoPicker(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8500 static napi_value ParseArgsStartPhotoPicker(napi_env env, napi_callback_info info,
8501     unique_ptr<MediaLibraryAsyncContext> &context)
8502 {
8503     NAPI_INFO_LOG("ParseArgsStartPhotoPicker start");
8504     constexpr size_t minArgs = ARGS_TWO;
8505     constexpr size_t maxArgs = ARGS_THREE;
8506     CHECK_ARGS(env, AsyncContextSetStaticObjectInfo(env, info, context, minArgs, maxArgs),
8507         JS_ERR_PARAMETER_INVALID);
8508     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, context));
8509     CHECK_NULLPTR_RET(StartPickerExtension(env, info, context));
8510     napi_value result = nullptr;
8511     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8512     return result;
8513 }
8514 
StartPhotoPicker(napi_env env,napi_callback_info info)8515 napi_value MediaLibraryNapi::StartPhotoPicker(napi_env env, napi_callback_info info)
8516 {
8517     NAPI_INFO_LOG("StartPhotoPicker start");
8518     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8519     auto pickerCallBack = make_shared<PickerCallBack>();
8520     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8521     ParseArgsStartPhotoPicker(env, info, asyncContext);
8522 
8523     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "StrartPhotoPicker",
8524         StartPhotoPickerExecute, StartPhotoPickerAsyncCallbackComplete);
8525 }
8526 } // namespace Media
8527 } // namespace OHOS
8528