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