• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "MediaLibraryNapi"
17 #define ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE "ability.want.params.uiExtensionTargetType"
18 
19 #include "media_library_napi.h"
20 
21 #include <fcntl.h>
22 #include <functional>
23 #include <sys/sendfile.h>
24 
25 #include "access_token.h"
26 #include "accesstoken_kit.h"
27 #include "ability_context.h"
28 #include "album_order_napi.h"
29 #include "confirm_callback.h"
30 #include "context.h"
31 #include "default_album_name_callback.h"
32 #include "directory_ex.h"
33 #include "file_ex.h"
34 #include "hitrace_meter.h"
35 #include "ipc_skeleton.h"
36 #include "location_column.h"
37 #include "locale_config.h"
38 #include "media_device_column.h"
39 #include "media_directory_type_column.h"
40 #include "media_file_asset_columns.h"
41 #include "media_change_request_napi.h"
42 #include "media_column.h"
43 #include "media_app_uri_permission_column.h"
44 #include "media_app_uri_sensitive_column.h"
45 #include "media_file_uri.h"
46 #include "media_file_utils.h"
47 #include "media_smart_album_column.h"
48 #include "media_smart_map_column.h"
49 #include "medialibrary_client_errno.h"
50 #include "medialibrary_data_manager.h"
51 #include "medialibrary_db_const.h"
52 #include "medialibrary_errno.h"
53 #include "medialibrary_napi_enum_comm.h"
54 #include "medialibrary_napi_log.h"
55 #include "medialibrary_peer_info.h"
56 #include "medialibrary_tracer.h"
57 #include "modal_ui_callback.h"
58 #include "modal_ui_extension_config.h"
59 #include "napi_base_context.h"
60 #include "napi_common_want.h"
61 #include "photo_album_column.h"
62 #include "photo_album_napi.h"
63 #include "result_set_utils.h"
64 #include "safe_map.h"
65 #include "search_column.h"
66 #include "short_term_callback.h"
67 #include "request_photo_uris_read_permission_callback.h"
68 #include "smart_album_napi.h"
69 #include "story_album_column.h"
70 #include "string_ex.h"
71 #include "string_wrapper.h"
72 #include "userfile_client.h"
73 #include "uv.h"
74 #include "vision_total_column.h"
75 #include "file_asset_napi.h"
76 #include "form_map.h"
77 #include "media_facard_photos_column.h"
78 #include "rdb_utils.h"
79 #ifdef HAS_ACE_ENGINE_PART
80 #include "ui_content.h"
81 #endif
82 #include "ui_extension_context.h"
83 #include "want.h"
84 #include "js_native_api.h"
85 #include "js_native_api_types.h"
86 #include "delete_callback.h"
87 #include "window.h"
88 #include "permission_utils.h"
89 #include "userfilemgr_uri.h"
90 #include "user_photography_info_column.h"
91 #include "foreground_analysis_meta.h"
92 #include "smart_album_column.h"
93 #include "album_operation_uri.h"
94 #include "data_secondary_directory_uri.h"
95 #include "user_define_ipc_client.h"
96 #include "form_info_vo.h"
97 #include "medialibrary_business_code.h"
98 #include "create_asset_vo.h"
99 #include "create_album_vo.h"
100 #include "delete_albums_vo.h"
101 #include "trash_photos_vo.h"
102 #include "file_uri.h"
103 #include "grant_photo_uri_permission_vo.h"
104 #include "grant_photo_uris_permission_vo.h"
105 #include "cancel_photo_uri_permission_vo.h"
106 #include "start_thumbnail_creation_task_vo.h"
107 #include "stop_thumbnail_creation_task_vo.h"
108 #include "get_index_construct_progress_vo.h"
109 #include "get_assets_vo.h"
110 #include "query_albums_vo.h"
111 #include "get_albums_by_ids_vo.h"
112 #include "start_asset_analysis_vo.h"
113 #include "get_photo_index_vo.h"
114 #include "query_result_vo.h"
115 #include "get_analysis_process_vo.h"
116 #include "get_photo_album_object_vo.h"
117 #include "set_photo_album_order_vo.h"
118 #include "result_set_napi.h"
119 
120 #include "parcel.h"
121 #include "medialibrary_notify_utils.h"
122 #include "qos.h"
123 #include "vision_ocr_column.h"
124 #include "vision_video_label_column.h"
125 #include "vision_label_column.h"
126 #include "vision_image_face_column.h"
127 
128 using namespace std;
129 using namespace OHOS::AppExecFwk;
130 using namespace OHOS::NativeRdb;
131 using namespace OHOS::DataShare;
132 using namespace OHOS::Security::AccessToken;
133 
134 namespace OHOS {
135 namespace Media {
136 using ChangeType = AAFwk::ChangeInfo::ChangeType;
137 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
138 const int32_t SECOND_ENUM = 2;
139 const int32_t THIRD_ENUM = 3;
140 const int32_t FORMID_MAX_LEN = 19;
141 const int32_t SLEEP_TIME = 10;
142 const int64_t MAX_INT64 = 9223372036854775807;
143 const int32_t MAX_QUERY_LIMIT = 150;
144 const int32_t MAX_CREATE_ASSET_LIMIT = 500;
145 const int32_t MAX_QUERY_ALBUM_LIMIT = 500;
146 const int32_t MAX_LEN_LIMIT = 9999;
147 constexpr uint32_t CONFIRM_BOX_ARRAY_MAX_LENGTH = 100;
148 const string DATE_FUNCTION = "DATE(";
149 const size_t MAX_SET_ORDER_ARRAY_SIZE = 1000;
150 
151 static const std::unordered_map<int32_t, std::string> NEED_COMPATIBLE_COLUMN_MAP = {
152     {ANALYSIS_LABEL, FEATURE},
153     {ANALYSIS_FACE, FEATURES},
154     {ANALYSIS_VIDEO_LABEL, VIDEO_PART_FEATURE},
155     {ANALYSIS_OCR, OCR_TEXT_MSG}
156 };
157 
158 mutex MediaLibraryNapi::sUserFileClientMutex_;
159 mutex MediaLibraryNapi::sOnOffMutex_;
160 string ChangeListenerNapi::trashAlbumUri_;
161 static SafeMap<int32_t, std::shared_ptr<ThumbnailBatchGenerateObserver>> thumbnailGenerateObserverMap;
162 static SafeMap<int32_t, std::shared_ptr<ThumbnailGenerateHandler>> thumbnailGenerateHandlerMap;
163 static std::atomic<int32_t> requestIdCounter_ = 0;
164 static std::atomic<int32_t> requestIdCallback_ = 0;
165 static map<string, ListenerType> ListenerTypeMaps = {
166     {"audioChange", AUDIO_LISTENER},
167     {"videoChange", VIDEO_LISTENER},
168     {"imageChange", IMAGE_LISTENER},
169     {"fileChange", FILE_LISTENER},
170     {"albumChange", ALBUM_LISTENER},
171     {"deviceChange", DEVICE_LISTENER},
172     {"remoteFileChange", REMOTEFILE_LISTENER}
173 };
174 
175 const std::string SUBTYPE = "subType";
176 const std::string PAH_SUBTYPE = "subtype";
177 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
178 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
179     { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
180     { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
181     { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
182 
183 };
184 
185 const std::string TITLE = "title";
186 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
187     { TITLE, MediaColumn::MEDIA_TITLE }
188 };
189 
190 const std::map<int32_t, std::string> FOREGROUND_ANALYSIS_ASSETS_MAP = {
191     { ANALYSIS_SEARCH_INDEX, PAH_QUERY_ANA_FOREGROUND }
192 };
193 
194 const std::string EXTENSION = "fileNameExtension";
195 const std::string PHOTO_TYPE = "photoType";
196 const std::string PHOTO_SUB_TYPE = "subtype";
197 const std::string SHORT_TERM_TAG = "shortTerm";
198 const std::string SHORT_TERM_TITLE = "title";
199 const std::string SHORT_TERM_EXTENSION = "extension";
200 const std::string SHORT_TERM_PHOTO_TYPE = "photoType";
201 const std::string SHORT_TERM_PHOTO_SUB_TYPE = "photoSubType";
202 const std::string CONFIRM_BOX_PACKAGE_NAME = "com.ohos.photos";
203 const std::string CONFIRM_BOX_EXT_ABILITY_NAME = "SaveUIExtensionAbility";
204 const std::string CONFIRM_BOX_EXT_DEFAULT_ALBUM_NAME_ABILITY_NAME = "DefaultAlbumNameUIExtensionAbility";
205 const std::string CONFIRM_BOX_EXTENSION_TYPE = "ability.want.params.uiExtensionType";
206 const std::string CONFIRM_BOX_REQUEST_TYPE = "sysDialog/common";
207 const std::string CONFIRM_BOX_SRC_FILE_URIS = "ability.params.stream";
208 const std::string CONFIRM_BOX_TITLE_ARRAY = "titleArray";
209 const std::string CONFIRM_BOX_EXTENSION_ARRAY = "extensionArray";
210 const std::string CONFIRM_BOX_PHOTO_TYPE_ARRAY = "photoTypeArray";
211 const std::string CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY = "photoSubTypeArray";
212 const std::string CONFIRM_BOX_BUNDLE_NAME = "bundleName";
213 const std::string CONFIRM_BOX_APP_NAME = "appName";
214 const std::string CONFIRM_BOX_APP_ID = "appId";
215 const std::string TARGET_PAGE = "targetPage";
216 const std::string TOKEN_ID = "tokenId";
217 
218 const std::string LANGUAGE_ZH = "zh-Hans";
219 const std::string LANGUAGE_EN = "en-Latn-US";
220 const std::string LANGUAGE_ZH_TR = "zh-Hant";
221 
222 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
223 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
224 thread_local napi_ref MediaLibraryNapi::sKeyFrameThumbnailTypeRef_ = nullptr;
225 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
226 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
227 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
228 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
229 thread_local napi_ref MediaLibraryNapi::sDeliveryModeEnumRef_ = nullptr;
230 thread_local napi_ref MediaLibraryNapi::sSourceModeEnumRef_ = nullptr;
231 thread_local napi_ref MediaLibraryNapi::sCompatibleModeEnumRef_ = nullptr;
232 thread_local napi_ref MediaLibraryNapi::sPositionTypeEnumRef_ = nullptr;
233 thread_local napi_ref MediaLibraryNapi::sPhotoSubType_ = nullptr;
234 thread_local napi_ref MediaLibraryNapi::sPhotoPermissionType_ = nullptr;
235 thread_local napi_ref MediaLibraryNapi::sHideSensitiveType_ = nullptr;
236 thread_local napi_ref MediaLibraryNapi::sDynamicRangeType_ = nullptr;
237 thread_local napi_ref MediaLibraryNapi::sHiddenPhotosDisplayModeEnumRef_ = nullptr;
238 thread_local napi_ref MediaLibraryNapi::sAuthorizationModeEnumRef_ = nullptr;
239 using CompleteCallback = napi_async_complete_callback;
240 using Context = MediaLibraryAsyncContext* ;
241 
242 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
243 thread_local napi_ref MediaLibraryNapi::photoAccessHelperConstructor_ = nullptr;
244 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
245 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
246 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
247 thread_local napi_ref MediaLibraryNapi::sPhotoKeysEnumRef_ = nullptr;
248 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
249 thread_local napi_ref MediaLibraryNapi::sAlbumType_ = nullptr;
250 thread_local napi_ref MediaLibraryNapi::sAlbumSubType_ = nullptr;
251 thread_local napi_ref MediaLibraryNapi::sNotifyType_ = nullptr;
252 thread_local napi_ref MediaLibraryNapi::sDefaultChangeUriRef_ = nullptr;
253 thread_local napi_ref MediaLibraryNapi::sAnalysisType_ = nullptr;
254 thread_local napi_ref MediaLibraryNapi::sRequestPhotoTypeEnumRef_ = nullptr;
255 thread_local napi_ref MediaLibraryNapi::sResourceTypeEnumRef_ = nullptr;
256 thread_local napi_ref MediaLibraryNapi::sHighlightAlbumInfoType_ = nullptr;
257 thread_local napi_ref MediaLibraryNapi::sHighlightUserActionType_ = nullptr;
258 thread_local napi_ref MediaLibraryNapi::sMovingPhotoEffectModeEnumRef_ = nullptr;
259 thread_local napi_ref MediaLibraryNapi::sImageFileTypeEnumEnumRef_ = nullptr;
260 thread_local napi_ref MediaLibraryNapi::sCloudEnhancementTaskStageEnumRef_ = nullptr;
261 thread_local napi_ref MediaLibraryNapi::sCloudEnhancementStateEnumRef_ = nullptr;
262 thread_local napi_ref MediaLibraryNapi::sSupportedWatermarkTypeEnumRef_ = nullptr;
263 thread_local napi_ref MediaLibraryNapi::sVideoEnhancementTypeEnumRef_ = nullptr;
264 thread_local napi_ref MediaLibraryNapi::sCloudMediaDownloadTypeEnumRef_ = nullptr;
265 thread_local napi_ref MediaLibraryNapi::sCloudMediaRetainTypeEnumRef_ = nullptr;
266 thread_local napi_ref MediaLibraryNapi::sCloudMediaAssetTaskStatusEnumRef_ = nullptr;
267 thread_local napi_ref MediaLibraryNapi::sCloudMediaTaskPauseCauseEnumRef_ = nullptr;
268 thread_local napi_ref MediaLibraryNapi::sNotifyChangeTypeEnumRef_ = nullptr;
269 thread_local napi_ref MediaLibraryNapi::sThumbnailChangeStatusEnumRef_ = nullptr;
270 thread_local napi_ref MediaLibraryNapi::sStrongAssociationTypeEnumRef_ = nullptr;
271 
272 constexpr int32_t DEFAULT_REFCOUNT = 1;
273 constexpr int32_t DEFAULT_ALBUM_COUNT = 1;
MediaLibraryNapi()274 MediaLibraryNapi::MediaLibraryNapi()
275     : env_(nullptr) {}
276 
277 MediaLibraryNapi::~MediaLibraryNapi() = default;
278 
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)279 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
280 {
281     MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
282     if (mediaLibrary != nullptr) {
283         delete mediaLibrary;
284         mediaLibrary = nullptr;
285     }
286 }
287 
Init(napi_env env,napi_value exports)288 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
289 {
290     napi_property_descriptor media_library_properties[] = {
291         DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
292         DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
293         DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
294         DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
295         DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
296         DECLARE_NAPI_FUNCTION("on", JSOnCallback),
297         DECLARE_NAPI_FUNCTION("off", JSOffCallback),
298         DECLARE_NAPI_FUNCTION("release", JSRelease),
299         DECLARE_NAPI_FUNCTION("getSmartAlbum", JSGetSmartAlbums),
300         DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
301         DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
302         DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
303         DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
304         DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
305         DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
306         DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
307     };
308     napi_property_descriptor static_prop[] = {
309         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
310         DECLARE_NAPI_STATIC_FUNCTION("getMediaLibraryAsync", GetMediaLibraryNewInstanceAsync),
311         DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
312         DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
313         DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
314         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
315     };
316     napi_value ctorObj;
317     napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
318         MediaLibraryNapiConstructor, nullptr,
319         sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
320         media_library_properties, &ctorObj);
321     if (status == napi_ok) {
322         int32_t refCount = 1;
323         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
324             status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
325             if (status == napi_ok && napi_define_properties(env, exports,
326                 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
327                 return exports;
328             }
329         }
330     }
331     return nullptr;
332 }
333 
UserFileMgrInit(napi_env env,napi_value exports)334 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
335 {
336     NapiClassInfo info = {
337         USERFILE_MGR_NAPI_CLASS_NAME,
338         &userFileMgrConstructor_,
339         MediaLibraryNapiConstructor,
340         {
341             DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
342             DECLARE_NAPI_FUNCTION("getAudioAssets", JSGetAudioAssets),
343             DECLARE_NAPI_FUNCTION("getPhotoAlbums", JSGetPhotoAlbums),
344             DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreatePhotoAsset),
345             DECLARE_NAPI_FUNCTION("createAudioAsset", UserFileMgrCreateAudioAsset),
346             DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
347             DECLARE_NAPI_FUNCTION("on", UserFileMgrOnCallback),
348             DECLARE_NAPI_FUNCTION("off", UserFileMgrOffCallback),
349             DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
350             DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
351             DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
352             DECLARE_NAPI_FUNCTION("release", JSRelease),
353             DECLARE_NAPI_FUNCTION("createAlbum", CreatePhotoAlbum),
354             DECLARE_NAPI_FUNCTION("deleteAlbums", DeletePhotoAlbums),
355             DECLARE_NAPI_FUNCTION("getAlbums", GetPhotoAlbums),
356             DECLARE_NAPI_FUNCTION("getPhotoIndex", JSGetPhotoIndex), DECLARE_NAPI_FUNCTION("setHidden", SetHidden),
357         }
358     };
359     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
360 
361     const vector<napi_property_descriptor> staticProps = {
362         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
363         DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgrAsync", GetUserFileMgrAsync),
364         DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
365         DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
366         DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
367         DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
368         DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
369         DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
370         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
371         DECLARE_NAPI_PROPERTY("AlbumSubType", CreateAlbumSubTypeEnum(env)),
372         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
373         DECLARE_NAPI_PROPERTY("PhotoSubType", CreatePhotoSubTypeEnum(env)),
374         DECLARE_NAPI_PROPERTY("ThumbnailType", CreateKeyFrameThumbnailTypeEnum(env)),
375         DECLARE_NAPI_PROPERTY("PhotoPermissionType", CreatePhotoPermissionTypeEnum(env)),
376         DECLARE_NAPI_PROPERTY("HideSensitiveType", CreateHideSensitiveTypeEnum(env)),
377         DECLARE_NAPI_PROPERTY("DynamicRangeType", CreateDynamicRangeTypeEnum(env)),
378         DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
379         DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env)),
380         DECLARE_NAPI_PROPERTY("HiddenPhotosDisplayMode", CreateHiddenPhotosDisplayModeEnum(env)),
381         DECLARE_NAPI_PROPERTY("RequestPhotoType", CreateRequestPhotoTypeEnum(env))
382     };
383     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
384     return exports;
385 }
386 
PhotoAccessHelperInit(napi_env env,napi_value exports)387 napi_value MediaLibraryNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
388 {
389     NapiClassInfo info = { PHOTOACCESSHELPER_NAPI_CLASS_NAME, &photoAccessHelperConstructor_,
390         MediaLibraryNapiConstructor,
391         {
392             DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
393             DECLARE_NAPI_FUNCTION("getBurstAssets", PhotoAccessGetBurstAssets),
394             DECLARE_WRITABLE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
395             DECLARE_NAPI_FUNCTION("registerChange", PhotoAccessHelperOnCallback),
396             DECLARE_NAPI_FUNCTION("unRegisterChange", PhotoAccessHelperOffCallback),
397             DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperTrashAsset),
398             DECLARE_NAPI_FUNCTION("release", JSRelease),
399             DECLARE_NAPI_FUNCTION("createAlbum", PhotoAccessCreatePhotoAlbum),
400             DECLARE_NAPI_FUNCTION("deleteAlbums", PhotoAccessDeletePhotoAlbums),
401             DECLARE_NAPI_FUNCTION("getAlbums", PahGetAlbums),
402             DECLARE_NAPI_FUNCTION("getAlbumsByIds", PhotoAccessGetPhotoAlbumsByIds),
403             DECLARE_NAPI_FUNCTION("getPhotoIndex", PhotoAccessGetPhotoIndex),
404             DECLARE_NAPI_FUNCTION("getIndexConstructProgress", PhotoAccessGetIndexConstructProgress),
405             DECLARE_NAPI_FUNCTION("setHidden", SetHidden),
406             DECLARE_NAPI_FUNCTION("getHiddenAlbums", PahGetHiddenAlbums),
407             DECLARE_WRITABLE_NAPI_FUNCTION("applyChanges", JSApplyChanges),
408             DECLARE_NAPI_FUNCTION("saveFormInfo", PhotoAccessSaveFormInfo),
409             DECLARE_NAPI_FUNCTION("saveGalleryFormInfo", PhotoAccessSaveGalleryFormInfo),
410             DECLARE_NAPI_FUNCTION("removeFormInfo", PhotoAccessRemoveFormInfo),
411             DECLARE_NAPI_FUNCTION("removeGalleryFormInfo", PhotoAccessRemoveGalleryFormInfo),
412             DECLARE_NAPI_FUNCTION("updateGalleryFormInfo", PhotoAccessUpdateGalleryFormInfo),
413             DECLARE_NAPI_FUNCTION("getAssetsSync", PhotoAccessGetPhotoAssetsSync),
414             DECLARE_NAPI_FUNCTION("getAlbumsSync", PhotoAccessGetPhotoAlbumsSync),
415             DECLARE_NAPI_FUNCTION("getFileAssetsInfo", PhotoAccessGetFileAssetsInfo),
416             DECLARE_NAPI_FUNCTION("startCreateThumbnailTask", PhotoAccessStartCreateThumbnailTask),
417             DECLARE_NAPI_FUNCTION("stopCreateThumbnailTask", PhotoAccessStopCreateThumbnailTask),
418             DECLARE_NAPI_FUNCTION("startThumbnailCreationTask", PhotoAccessStartCreateThumbnailTask),
419             DECLARE_NAPI_FUNCTION("stopThumbnailCreationTask", PhotoAccessStopCreateThumbnailTask),
420             DECLARE_NAPI_FUNCTION("createAssetsForApp", PhotoAccessHelperAgentCreateAssets),
421             DECLARE_NAPI_FUNCTION("createAssetsHasPermission", CreateAssetsHasPermission),
422             DECLARE_NAPI_FUNCTION("grantPhotoUriPermission", PhotoAccessGrantPhotoUriPermission),
423             DECLARE_NAPI_FUNCTION("grantPhotoUrisPermission", PhotoAccessGrantPhotoUrisPermission),
424             DECLARE_NAPI_FUNCTION("cancelPhotoUriPermission", PhotoAccessCancelPhotoUriPermission),
425             DECLARE_NAPI_FUNCTION("createAssetsForAppWithMode", PhotoAccessHelperAgentCreateAssetsWithMode),
426             DECLARE_NAPI_FUNCTION("getDataAnalysisProgress", PhotoAccessHelperGetDataAnalysisProgress),
427             DECLARE_NAPI_FUNCTION("getSharedPhotoAssets", PhotoAccessGetSharedPhotoAssets),
428             DECLARE_NAPI_FUNCTION("getSupportedPhotoFormats", PhotoAccessGetSupportedPhotoFormats),
429             DECLARE_NAPI_FUNCTION("setForceHideSensitiveType", PhotoAccessHelperSetForceHideSensitiveType),
430             DECLARE_NAPI_FUNCTION("getAnalysisData", PhotoAccessHelperGetAnalysisData),
431             DECLARE_NAPI_FUNCTION("createAssetsForAppWithAlbum", CreateAssetsForAppWithAlbum),
432             DECLARE_NAPI_FUNCTION("startAssetAnalysis", PhotoAccessStartAssetAnalysis),
433             DECLARE_NAPI_FUNCTION("query", PhotoAccessQuery),
434             DECLARE_NAPI_FUNCTION("on", PhotoAccessRegisterCallback),
435             DECLARE_NAPI_FUNCTION("off", PhotoAccessUnregisterCallback),
436             DECLARE_NAPI_FUNCTION("getPhotoAlbums", PhotoAccessGetPhotoAlbumsWithoutSubtype),
437             DECLARE_NAPI_FUNCTION("getPhotoAlbumOrder", PhotoAccessGetPhotoAlbumOrder),
438             DECLARE_NAPI_FUNCTION("setPhotoAlbumOrder", PhotoAccessSetPhotoAlbumOrder),
439         }
440     };
441     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
442 
443     const vector<napi_property_descriptor> staticProps = {
444         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
445         DECLARE_NAPI_STATIC_FUNCTION("startPhotoPicker", StartPhotoPicker),
446         DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelperAsync", GetPhotoAccessHelperAsync),
447         DECLARE_NAPI_STATIC_FUNCTION("createDeleteRequest", CreateDeleteRequest),
448         DECLARE_NAPI_STATIC_FUNCTION("showAssetsCreationDialog", ShowAssetsCreationDialog),
449         DECLARE_NAPI_STATIC_FUNCTION("checkShortTermPermission", CheckShortTermPermission),
450         DECLARE_NAPI_STATIC_FUNCTION("createAssetWithShortTermPermission", CreateAssetWithShortTermPermission),
451         DECLARE_NAPI_PROPERTY("ThumbnailType", CreateKeyFrameThumbnailTypeEnum(env)),
452         DECLARE_NAPI_STATIC_FUNCTION("requestPhotoUrisReadPermission", RequestPhotoUrisReadPermission),
453         DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
454         DECLARE_NAPI_PROPERTY("AlbumKeys", CreateAlbumKeyEnum(env)),
455         DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
456         DECLARE_NAPI_PROPERTY("PhotoKeys", CreatePhotoKeysEnum(env)),
457         DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
458         DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
459         DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
460         DECLARE_NAPI_PROPERTY("PhotoPermissionType", CreatePhotoPermissionTypeEnum(env)),
461         DECLARE_NAPI_PROPERTY("HideSensitiveType", CreateHideSensitiveTypeEnum(env)),
462         DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
463         DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env)),
464         DECLARE_NAPI_PROPERTY("HiddenPhotosDisplayMode", CreateHiddenPhotosDisplayModeEnum(env)),
465         DECLARE_NAPI_PROPERTY("AnalysisType", CreateAnalysisTypeEnum(env)),
466         DECLARE_NAPI_PROPERTY("RequestPhotoType", CreateRequestPhotoTypeEnum(env)),
467         DECLARE_NAPI_PROPERTY("ResourceType", CreateResourceTypeEnum(env)),
468         DECLARE_NAPI_PROPERTY("DeliveryMode", CreateDeliveryModeEnum(env)),
469         DECLARE_NAPI_PROPERTY("SourceMode", CreateSourceModeEnum(env)),
470         DECLARE_NAPI_PROPERTY("CompatibleMode", CreateCompatibleModeEnum(env)),
471         DECLARE_NAPI_PROPERTY("HighlightAlbumInfoType", CreateHighlightAlbumInfoTypeEnum(env)),
472         DECLARE_NAPI_PROPERTY("HighlightUserActionType", CreateHighlightUserActionTypeEnum(env)),
473         DECLARE_NAPI_PROPERTY("MovingPhotoEffectMode", CreateMovingPhotoEffectModeEnum(env)),
474         DECLARE_NAPI_PROPERTY("ImageFileType", CreateImageFileTypeEnum(env)),
475         DECLARE_NAPI_PROPERTY("CloudEnhancementTaskStage", CreateCloudEnhancementTaskStageEnum(env)),
476         DECLARE_NAPI_PROPERTY("CloudEnhancementState", CreateCloudEnhancementStateEnum(env)),
477         DECLARE_NAPI_PROPERTY("AuthorizationMode", CreateAuthorizationModeEnum(env)),
478         DECLARE_NAPI_PROPERTY("WatermarkType", CreateSupportedWatermarkTypeEnum(env)),
479         DECLARE_NAPI_PROPERTY("VideoEnhancementType", CreateVideoEnhancementTypeEnum(env)),
480         DECLARE_NAPI_PROPERTY("CloudMediaDownloadType", CreateCloudMediaDownloadTypeEnum(env)),
481         DECLARE_NAPI_PROPERTY("CloudMediaRetainType", CreateCloudMediaRetainTypeEnum(env)),
482         DECLARE_NAPI_PROPERTY("CloudMediaAssetTaskStatus", CreateCloudMediaAssetTaskStatusEnum(env)),
483         DECLARE_NAPI_PROPERTY("CloudMediaTaskPauseCause", CreateCloudMediaTaskPauseCauseEnum(env)),
484         DECLARE_NAPI_STATIC_FUNCTION("getPhotoPickerComponentDefaultAlbumName",
485             GetPhotoPickerComponentDefaultAlbumName),
486         DECLARE_NAPI_PROPERTY("NotifyChangeType", CreateNotifyChangeTypeEnum(env)),
487         DECLARE_NAPI_PROPERTY("ThumbnailChangeStatus", CreateThumbnailChangeStatusEnum(env)),
488         DECLARE_NAPI_PROPERTY("StrongAssociationType", CreateStrongAssociationTypeEnum(env)),
489     };
490     MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
491     return exports;
492 }
493 
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)494 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
495 {
496     isAsync = false;
497     size_t argc = ARGS_TWO;
498     napi_value argv[ARGS_TWO] = {0};
499     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
500     if (status != napi_ok) {
501         NAPI_ERR_LOG("Error while obtaining js environment information");
502         return status;
503     }
504 
505     if (argc == ARGS_ONE) {
506         return napi_ok;
507     } else if (argc == ARGS_TWO) {
508         napi_valuetype valueType = napi_undefined;
509         status = napi_typeof(env, argv[ARGS_ONE], &valueType);
510         if (status != napi_ok) {
511             NAPI_ERR_LOG("Error while obtaining js environment information");
512             return status;
513         }
514         if (valueType == napi_number) {
515             return napi_ok;
516         }
517         if (valueType == napi_boolean) {
518             isAsync = true;
519         }
520         status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
521         return status;
522     } else {
523         NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
524         return napi_invalid_arg;
525     }
526 }
527 
ParseUserIdFormCbInfo(napi_env env,napi_callback_info info)528 static int32_t ParseUserIdFormCbInfo(napi_env env, napi_callback_info info)
529 {
530     size_t argc = ARGS_TWO;
531     napi_value argv[ARGS_TWO] = {0};
532     napi_status status;
533     int userId = -1;
534     status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
535     if (status == napi_ok) {
536         napi_valuetype valueType = napi_undefined;
537         status = napi_typeof(env, argv[ARGS_ONE], &valueType);
538         if (status == napi_ok && valueType == napi_number) {
539             napi_get_value_int32(env, argv[ARGS_ONE], &userId);
540         }
541     }
542     return userId;
543 }
544 
SetUserIdFromObjectInfo(unique_ptr<MediaLibraryAsyncContext> & asyncContext)545 static void SetUserIdFromObjectInfo(unique_ptr<MediaLibraryAsyncContext> &asyncContext)
546 {
547     if (asyncContext == nullptr || asyncContext->objectInfo == nullptr) {
548         NAPI_ERR_LOG("objectInfo is nullptr");
549         return;
550     }
551     asyncContext->userId = asyncContext->objectInfo->GetUserId();
552 }
553 
554 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)555 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
556 {
557     napi_status status;
558     napi_value result = nullptr;
559     napi_value thisVar = nullptr;
560     MediaLibraryTracer tracer;
561     tracer.Start("MediaLibraryNapiConstructor");
562     int32_t userId = ParseUserIdFormCbInfo(env, info);
563     UserFileClient::SetUserId(userId);
564 
565     NAPI_CALL(env, napi_get_undefined(env, &result));
566     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
567     if (status != napi_ok || thisVar == nullptr) {
568         NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
569         return result;
570     }
571     unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
572     if (obj == nullptr) {
573         return result;
574     }
575     obj->env_ = env;
576     obj->SetUserId(userId);
577     // Initialize the ChangeListener object
578     if (g_listObj == nullptr) {
579         g_listObj = make_unique<ChangeListenerNapi>(env);
580     }
581     bool isAsync = false;
582     NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
583     if (!isAsync) {
584         unique_lock<mutex> helperLock(sUserFileClientMutex_);
585         if (!UserFileClient::IsValid(obj->GetUserId())) {
586             UserFileClient::Init(env, info, obj->GetUserId());
587             if (!UserFileClient::IsValid(obj->GetUserId())) {
588                 NAPI_ERR_LOG("UserFileClient creation failed");
589                 helperLock.unlock();
590                 return result;
591             }
592         }
593         helperLock.unlock();
594     }
595     status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
596                        MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
597     if (status == napi_ok) {
598         obj.release();
599         return thisVar;
600     } else {
601         NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
602     }
603     return result;
604 }
605 
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid,const int32_t userId=-1)606 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid, const int32_t userId = -1)
607 {
608     napi_value propertyNames;
609     uint32_t propertyLength;
610     napi_valuetype valueType = napi_undefined;
611     NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
612     if (valueType != napi_object) {
613         return false;
614     }
615 
616     NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
617     NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
618     if (propertyLength == 0) {
619         return false;
620     }
621     if (checkIsValid && (!UserFileClient::IsValid(userId))) {
622         NAPI_ERR_LOG("UserFileClient is not valid");
623         return false;
624     }
625     return true;
626 }
627 
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)628 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
629     bool isAsync = false)
630 {
631     constexpr size_t ARG_CONTEXT = 1;
632     size_t argc = ARG_CONTEXT;
633     napi_value argv[ARGS_TWO] = {0};
634 
635     napi_value thisVar = nullptr;
636     napi_value ctor = nullptr;
637     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
638     NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
639     if (isAsync) {
640         argc = ARGS_TWO;
641         NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
642         argv[ARGS_ONE] = argv[ARG_CONTEXT];
643     }
644     int32_t userId = -1;
645     if (argc > 1 && !isAsync) {
646         argc = ARGS_TWO;
647         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
648         NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
649         napi_valuetype valueType = napi_undefined;
650         napi_typeof(env, argv[ARGS_ONE], &valueType);
651         if (valueType == napi_number) {
652             NAPI_CALL(env, napi_get_value_int32(env, argv[ARGS_ONE], &userId));
653             if (userId != -1 && !MediaLibraryNapiUtils::IsSystemApp()) {
654                 NAPI_ERR_LOG("CreateNewInstance failed, target is not system app");
655                 return nullptr;
656             }
657             UserFileClient::SetUserId(userId);
658             NAPI_INFO_LOG("CreateNewInstance for other user is %{public}d", userId);
659         }
660     }
661 
662     napi_value result = nullptr;
663     NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
664     if (!CheckWhetherInitSuccess(env, result, !isAsync, userId)) {
665         NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
666         NAPI_CALL(env, napi_get_undefined(env, &result));
667     }
668     return result;
669 }
670 
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)671 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
672 {
673     MediaLibraryTracer tracer;
674     tracer.Start("getMediaLibrary");
675 
676     napi_value result = nullptr;
677     napi_value ctor;
678     size_t argc = ARGS_ONE;
679     napi_value argv[ARGS_ONE] = {0};
680     napi_value thisVar = nullptr;
681     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
682     napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
683     if (status == napi_ok) {
684         status = napi_new_instance(env, ctor, argc, argv, &result);
685         if (status == napi_ok) {
686             if (CheckWhetherInitSuccess(env, result, true)) {
687                 return result;
688             } else {
689                 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
690             }
691         } else {
692             NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
693         }
694     } else {
695         NAPI_ERR_LOG("status = %{public}d", status);
696     }
697 
698     napi_get_undefined(env, &result);
699     return result;
700 }
701 
GetMediaLibraryAsyncExecute(napi_env env,void * data)702 static void GetMediaLibraryAsyncExecute(napi_env env, void *data)
703 {
704     MediaLibraryTracer tracer;
705     tracer.Start("GetMediaLibraryAsyncExecute");
706 
707     MediaLibraryInitContext *asyncContext = static_cast<MediaLibraryInitContext *>(data);
708     if (asyncContext == nullptr) {
709         NAPI_ERR_LOG("Async context is null");
710         return;
711     }
712 
713     asyncContext->error = ERR_DEFAULT;
714     unique_lock<mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
715     if (!UserFileClient::IsValid()) {
716         UserFileClient::Init(asyncContext->token_, true);
717         if (!UserFileClient::IsValid()) {
718             NAPI_ERR_LOG("UserFileClient creation failed");
719             asyncContext->error = ERR_INVALID_OUTPUT;
720             helperLock.unlock();
721             return;
722         }
723     }
724     helperLock.unlock();
725 }
726 
GetMediaLibraryAsyncComplete(napi_env env,napi_status status,void * data)727 static void GetMediaLibraryAsyncComplete(napi_env env, napi_status status, void *data)
728 {
729     MediaLibraryInitContext *context = static_cast<MediaLibraryInitContext *>(data);
730     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
731     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
732     jsContext->status = false;
733 
734     napi_value result = nullptr;
735     if (napi_get_reference_value(env, context->resultRef_, &result) != napi_ok) {
736         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
737             "Get result from context ref failed");
738     }
739     napi_valuetype valueType;
740     if (napi_typeof(env, result, &valueType) != napi_ok || valueType != napi_object) {
741         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
742             "Get result type failed " + to_string((int) valueType));
743     }
744 
745     if (context->error == ERR_DEFAULT) {
746         jsContext->data = result;
747         jsContext->status = true;
748         napi_get_undefined(env, &jsContext->error);
749     } else {
750         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
751             "Failed to get MediaLibrary");
752         napi_get_undefined(env, &jsContext->data);
753     }
754 
755     if (context->work != nullptr) {
756         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
757             context->work, *jsContext);
758     }
759     napi_delete_reference(env, context->resultRef_);
760     context->resultRef_ = nullptr;
761     delete context;
762 }
763 
GetMediaLibraryNewInstanceAsync(napi_env env,napi_callback_info info)764 napi_value MediaLibraryNapi::GetMediaLibraryNewInstanceAsync(napi_env env, napi_callback_info info)
765 {
766     MediaLibraryTracer tracer;
767     tracer.Start("getMediaLibraryAsync");
768 
769     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
770     if (asyncContext == nullptr) {
771         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
772         return nullptr;
773     }
774     asyncContext->argc = ARGS_TWO;
775     napi_value thisVar = nullptr;
776     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
777         &thisVar, nullptr));
778 
779     napi_value result = CreateNewInstance(env, info, sConstructor_, true);
780     napi_valuetype valueType;
781     NAPI_CALL(env, napi_typeof(env, result, &valueType));
782     if (valueType == napi_undefined) {
783         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
784         return nullptr;
785     }
786     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
787     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
788 
789     bool isStage = false;
790     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
791     if (isStage) {
792         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
793     } else {
794         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
795     }
796 
797     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
798         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
799 }
800 
GetUserFileMgr(napi_env env,napi_callback_info info)801 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
802 {
803     MediaLibraryTracer tracer;
804     tracer.Start("getUserFileManager");
805 
806     if (!MediaLibraryNapiUtils::IsSystemApp()) {
807         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
808         return nullptr;
809     }
810 
811     return CreateNewInstance(env, info, userFileMgrConstructor_);
812 }
813 
GetUserFileMgrAsync(napi_env env,napi_callback_info info)814 napi_value MediaLibraryNapi::GetUserFileMgrAsync(napi_env env, napi_callback_info info)
815 {
816     MediaLibraryTracer tracer;
817     tracer.Start("getUserFileManagerAsync");
818 
819     if (!MediaLibraryNapiUtils::IsSystemApp()) {
820         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
821         return nullptr;
822     }
823 
824     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
825     if (asyncContext == nullptr) {
826         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
827         return nullptr;
828     }
829     asyncContext->argc = ARGS_TWO;
830     napi_value thisVar = nullptr;
831     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
832         &thisVar, nullptr));
833 
834     napi_value result = CreateNewInstance(env, info, userFileMgrConstructor_, true);
835     napi_valuetype valueType;
836     NAPI_CALL(env, napi_typeof(env, result, &valueType));
837     if (valueType == napi_undefined) {
838         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
839         return nullptr;
840     }
841     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
842     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
843 
844     bool isStage = false;
845     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
846     if (isStage) {
847         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
848     } else {
849         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
850     }
851 
852     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
853         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
854 }
855 
GetPhotoAccessHelper(napi_env env,napi_callback_info info)856 napi_value MediaLibraryNapi::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
857 {
858     MediaLibraryTracer tracer;
859     tracer.Start("GetPhotoAccessHelper");
860 
861     return CreateNewInstance(env, info, photoAccessHelperConstructor_);
862 }
863 
GetPhotoAccessHelperAsync(napi_env env,napi_callback_info info)864 napi_value MediaLibraryNapi::GetPhotoAccessHelperAsync(napi_env env, napi_callback_info info)
865 {
866     MediaLibraryTracer tracer;
867     tracer.Start("GetPhotoAccessHelperAsync");
868 
869     unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
870     if (asyncContext == nullptr) {
871         NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
872         return nullptr;
873     }
874     asyncContext->argc = ARGS_TWO;
875     napi_value thisVar = nullptr;
876     NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
877         &thisVar, nullptr));
878 
879     napi_value result = CreateNewInstance(env, info, photoAccessHelperConstructor_, true);
880     napi_valuetype valueType;
881     NAPI_CALL(env, napi_typeof(env, result, &valueType));
882     if (valueType == napi_undefined) {
883         NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
884         return nullptr;
885     }
886     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
887     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
888 
889     bool isStage = false;
890     NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
891     if (isStage) {
892         asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
893     } else {
894         asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
895     }
896 
897     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAccessHelperAsync",
898         GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
899 }
900 
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)901 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
902     const string &name, int32_t enumValue)
903 {
904     napi_value enumNapiValue;
905     napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
906     if (status == napi_ok) {
907         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
908     }
909     return status;
910 }
911 
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)912 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
913 {
914     napi_value result = nullptr;
915     NAPI_CALL(env, napi_create_object(env, &result));
916     for (size_t i = 0; i < properties.size(); i++) {
917         NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], static_cast<int32_t>(i) + offset));
918     }
919     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
920     return result;
921 }
922 
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)923 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
924     const string &name, string enumValue)
925 {
926     napi_value enumNapiValue;
927     napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
928     if (status == napi_ok) {
929         status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
930     }
931     return status;
932 }
933 
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)934 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
935 {
936     napi_value result = nullptr;
937     NAPI_CALL(env, napi_create_object(env, &result));
938     for (unsigned int i = 0; i < properties.size(); i++) {
939         NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
940     }
941     NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
942     return result;
943 }
944 
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)945 static void DealWithCommonParam(napi_env env, napi_value arg,
946     const MediaLibraryAsyncContext &context, bool &err, bool &present)
947 {
948     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
949     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
950 
951     string propertyName = "selections";
952     string tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
953     if (!tmp.empty()) {
954         asyncContext->selection = tmp;
955     }
956 
957     propertyName = "order";
958     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
959     if (!tmp.empty()) {
960         asyncContext->order = tmp;
961     }
962 
963     propertyName = "uri";
964     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
965     if (!tmp.empty()) {
966         asyncContext->uri = tmp;
967     }
968 
969     propertyName = "networkId";
970     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
971     if (!tmp.empty()) {
972         asyncContext->networkId = tmp;
973     }
974 
975     propertyName = "extendArgs";
976     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
977     if (!tmp.empty()) {
978         asyncContext->extendArgs = tmp;
979     }
980 }
981 
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)982 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
983 {
984     MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
985     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
986     napi_value property = nullptr;
987     napi_value stringItem = nullptr;
988     bool present = false;
989     DealWithCommonParam(env, arg, context, err, present);
990     napi_has_named_property(env, arg, "selectionArgs", &present);
991     if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
992         uint32_t len = 0;
993         napi_get_array_length(env, property, &len);
994         char buffer[PATH_MAX];
995         for (size_t i = 0; i < len; i++) {
996             napi_get_element(env, property, i, &stringItem);
997             size_t res = 0;
998             napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
999             asyncContext->selectionArgs.push_back(string(buffer));
1000             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
1001         }
1002     } else {
1003         NAPI_ERR_LOG("Could not get the string argument!");
1004         err = true;
1005     }
1006 }
1007 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1008 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
1009     MediaLibraryAsyncContext &asyncContext)
1010 {
1011     bool err = false;
1012     const int32_t refCount = 1;
1013     auto context = &asyncContext;
1014 
1015     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1016     for (size_t i = PARAM0; i < argc; i++) {
1017         napi_valuetype valueType = napi_undefined;
1018         napi_typeof(env, argv[i], &valueType);
1019 
1020         if (i == PARAM0 && valueType == napi_object) {
1021             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
1022         } else if (i == PARAM0 && valueType == napi_function) {
1023             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1024             break;
1025         } else if (i == PARAM1 && valueType == napi_function) {
1026             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1027             break;
1028         } else {
1029             NAPI_ASSERT(env, false, "type mismatch");
1030         }
1031         if (err) {
1032             NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
1033             NAPI_ASSERT(env, false, "type mismatch");
1034         }
1035     }
1036 
1037     // Return true napi_value if params are successfully obtained
1038     napi_value result;
1039     napi_get_boolean(env, true, &result);
1040     return result;
1041 }
1042 
GetPublicDirectoryExecute(napi_env env,void * data)1043 static void GetPublicDirectoryExecute(napi_env env, void *data)
1044 {
1045     MediaLibraryTracer tracer;
1046     tracer.Start("GetPublicDirectoryExecute");
1047 
1048     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1049     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1050 
1051     vector<string> selectionArgs;
1052     vector<string> columns;
1053     DataSharePredicates predicates;
1054     selectionArgs.push_back(to_string(context->dirType));
1055     predicates.SetWhereClause(DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
1056     predicates.SetWhereArgs(selectionArgs);
1057     string queryUri = MEDIALIBRARY_DIRECTORY_URI;
1058     Uri uri(queryUri);
1059     int errCode = 0;
1060     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode,
1061         context->userId);
1062     if (resultSet != nullptr) {
1063         auto count = 0;
1064         auto ret = resultSet->GetRowCount(count);
1065         if (ret != NativeRdb::E_OK) {
1066             NAPI_ERR_LOG("get rdbstore failed");
1067             context->error = JS_INNER_FAIL;
1068             return;
1069         }
1070         if (count == 0) {
1071             NAPI_ERR_LOG("Query for get publicDirectory form db failed");
1072             context->error = JS_INNER_FAIL;
1073             return;
1074         }
1075         NAPI_INFO_LOG("Query for get publicDirectory count = %{private}d", count);
1076         if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
1077             context->directoryRelativePath = get<string>(
1078                 ResultSetUtils::GetValFromColumn(DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
1079         }
1080         if (context->dirType == DirType::DIR_DOCUMENTS) {
1081             context->directoryRelativePath = DOC_DIR_VALUES;
1082         } else if (context->dirType == DirType::DIR_DOWNLOAD) {
1083             context->directoryRelativePath = DOWNLOAD_DIR_VALUES;
1084         }
1085         return;
1086     } else {
1087         context->SaveError(errCode);
1088         NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
1089     }
1090 }
1091 
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)1092 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
1093 {
1094     MediaLibraryTracer tracer;
1095     tracer.Start("GetPublicDirectoryCallbackComplete");
1096 
1097     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1098     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1099     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1100     jsContext->status = false;
1101     if (context->error == ERR_DEFAULT) {
1102         napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
1103         jsContext->status = true;
1104         napi_get_undefined(env, &jsContext->error);
1105     } else {
1106         context->HandleError(env, jsContext->error);
1107         napi_get_undefined(env, &jsContext->data);
1108     }
1109 
1110     tracer.Finish();
1111     if (context->work != nullptr) {
1112         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1113                                                    context->work, *jsContext);
1114     }
1115 
1116     delete context;
1117 }
1118 
JSGetPublicDirectory(napi_env env,napi_callback_info info)1119 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
1120 {
1121     napi_status status;
1122     napi_value result = nullptr;
1123     size_t argc = ARGS_TWO;
1124     napi_value argv[ARGS_TWO] = {0};
1125     napi_value thisVar = nullptr;
1126     const int32_t refCount = 1;
1127 
1128     MediaLibraryTracer tracer;
1129     tracer.Start("JSGetPublicDirectory");
1130 
1131     GET_JS_ARGS(env, info, argc, argv, thisVar);
1132     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1133     napi_get_undefined(env, &result);
1134 
1135     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1136     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1137     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1138         for (size_t i = PARAM0; i < argc; i++) {
1139             napi_valuetype valueType = napi_undefined;
1140             napi_typeof(env, argv[i], &valueType);
1141 
1142             if (i == PARAM0 && valueType == napi_number) {
1143                 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
1144             } else if (i == PARAM1 && valueType == napi_function) {
1145                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
1146                 break;
1147             } else {
1148                 NAPI_ASSERT(env, false, "type mismatch");
1149             }
1150         }
1151 
1152         SetUserIdFromObjectInfo(asyncContext);
1153         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
1154             GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
1155     }
1156 
1157     return result;
1158 }
1159 
1160 #ifdef MEDIALIBRARY_COMPATIBILITY
GetVirtualIdFromApi10Uri(const string & uri)1161 static string GetVirtualIdFromApi10Uri(const string &uri)
1162 {
1163     string fileId = MediaFileUtils::GetIdFromUri(uri);
1164     if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1165         return fileId;
1166     }
1167     int32_t id;
1168     if (!StrToInt(fileId, id)) {
1169         NAPI_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1170         return fileId;
1171     }
1172     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
1173         return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE));
1174     } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
1175         return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO));
1176     } else {
1177         return fileId;
1178     }
1179 }
1180 #endif
1181 
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)1182 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
1183 {
1184     if (!context->uri.empty()) {
1185         NAPI_ERR_LOG("context->uri is = %{private}s", context->uri.c_str());
1186         context->networkId = MediaFileUtils::GetNetworkIdFromUri(context->uri);
1187 #ifdef MEDIALIBRARY_COMPATIBILITY
1188         string fileId = GetVirtualIdFromApi10Uri(context->uri);
1189 #else
1190         string fileId = MediaFileUtils::::GetIdFromUri(context->uri);
1191 #endif
1192         if (!fileId.empty()) {
1193             string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
1194 #ifdef MEDIALIBRARY_COMPATIBILITY
1195             context->selection = idPrefix;
1196             context->selectionArgs.clear();
1197             context->selectionArgs.emplace_back(fileId);
1198 #else
1199             MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
1200             context->selectionArgs.emplace_back(fileId);
1201 #endif
1202         }
1203     }
1204 
1205 #ifdef MEDIALIBRARY_COMPATIBILITY
1206     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, MediaColumn::ASSETS_QUERY_FILTER);
1207     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs, MEDIA_DATA_DB_RELATIVE_PATH,
1208         MEDIA_DATA_DB_RELATIVE_PATH, ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH);
1209 #else
1210     string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
1211     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
1212     context->selectionArgs.emplace_back("0");
1213 #endif
1214     string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
1215     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
1216     context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
1217 }
1218 
LogMedialibraryAPI(const string & saveUri)1219 static void LogMedialibraryAPI(const string& saveUri)
1220 {
1221     string logMedialibraryAPI = MEDIALIBRARY_DATA_URI + "/" + MISC_OPERATION + "/" + "log_medialibrary_api";
1222     Uri logUri(logMedialibraryAPI);
1223     DataShare::DataShareValuesBucket valuesBucket;
1224     string result;
1225     valuesBucket.Put("saveUri", saveUri);
1226     UserFileClient::InsertExt(logUri, valuesBucket, result);
1227 }
1228 
GetFileAssetsExecute(napi_env env,void * data)1229 static void GetFileAssetsExecute(napi_env env, void *data)
1230 {
1231     MediaLibraryTracer tracer;
1232     tracer.Start("GetFileAssetsExecute");
1233 
1234     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1235     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1236 
1237     GetFileAssetUpdateSelections(context);
1238     context->fetchColumn = FILE_ASSET_COLUMNS;
1239     if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
1240         string group(" GROUP BY (");
1241         group += context->extendArgs + " )";
1242         context->selection += group;
1243         context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
1244     }
1245     MediaLibraryNapiUtils::FixSpecialDateType(context->selection);
1246     context->predicates.SetWhereClause(context->selection);
1247     context->predicates.SetWhereArgs(context->selectionArgs);
1248     context->predicates.SetOrder(context->order);
1249 
1250     LogMedialibraryAPI("");
1251 
1252     string queryUri = MEDIALIBRARY_DATA_URI;
1253     if (!context->networkId.empty()) {
1254         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1255     }
1256     Uri uri(queryUri);
1257     int errCode = 0;
1258     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
1259         context->predicates, context->fetchColumn, errCode, context->userId);
1260     if (resultSet != nullptr) {
1261         // Create FetchResult object using the contents of resultSet
1262         context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1263         context->fetchFileResult->SetNetworkId(context->networkId);
1264         return;
1265     } else {
1266         context->SaveError(errCode);
1267         NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
1268     }
1269 }
1270 
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1271 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
1272     unique_ptr<JSAsyncContextOutput> &jsContext)
1273 {
1274     // Create FetchResult object using the contents of resultSet
1275     if (context->fetchFileResult == nullptr) {
1276         NAPI_ERR_LOG("No fetch file result found!");
1277         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1278             "Failed to obtain Fetch File Result");
1279         return;
1280     }
1281     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
1282     if (fileResult == nullptr) {
1283         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1284             "Failed to create js object for Fetch File Result");
1285     } else {
1286         jsContext->data = fileResult;
1287         jsContext->status = true;
1288         napi_get_undefined(env, &jsContext->error);
1289     }
1290 }
1291 
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1292 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1293 {
1294     MediaLibraryTracer tracer;
1295     tracer.Start("GetFileAssetsAsyncCallbackComplete");
1296 
1297     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1298     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1299 
1300     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1301     jsContext->status = false;
1302     napi_get_undefined(env, &jsContext->data);
1303 
1304     if (context->error != ERR_DEFAULT) {
1305         context->HandleError(env, jsContext->error);
1306     } else {
1307         GetNapiFileResult(env, context, jsContext);
1308     }
1309 
1310     tracer.Finish();
1311     if (context->work != nullptr) {
1312         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1313                                                    context->work, *jsContext);
1314     }
1315     delete context;
1316 }
1317 
JSGetFileAssets(napi_env env,napi_callback_info info)1318 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
1319 {
1320     napi_status status;
1321     napi_value result = nullptr;
1322     size_t argc = ARGS_TWO;
1323     napi_value argv[ARGS_TWO] = {0};
1324     napi_value thisVar = nullptr;
1325 
1326     MediaLibraryTracer tracer;
1327     tracer.Start("JSGetFileAssets");
1328 
1329     GET_JS_ARGS(env, info, argc, argv, thisVar);
1330     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1331     napi_get_undefined(env, &result);
1332 
1333     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1334     asyncContext->mediaTypes.clear();
1335     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1336     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1337     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1338         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1339         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1340 
1341         SetUserIdFromObjectInfo(asyncContext);
1342         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
1343             GetFileAssetsAsyncCallbackComplete);
1344     }
1345 
1346     return result;
1347 }
1348 
1349 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatSetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1350 static void CompatSetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1351 {
1352     MediaLibraryTracer tracer;
1353     tracer.Start("CompatSetAlbumCoverUri");
1354     DataSharePredicates predicates;
1355     int err;
1356     if (album->GetAlbumType() == PhotoAlbumType::USER) {
1357         err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates, false);
1358     } else {
1359         err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates, false);
1360     }
1361     if (err < 0) {
1362         NAPI_WARN_LOG("Failed to set cover uri for album subtype: %{public}d", album->GetAlbumSubType());
1363         return;
1364     }
1365     predicates.OrderByDesc(MediaColumn::MEDIA_DATE_ADDED);
1366     predicates.Limit(1, 0);
1367 
1368     Uri uri(URI_QUERY_PHOTO_MAP);
1369     vector<string> columns;
1370     columns.assign(MediaColumn::DEFAULT_FETCH_COLUMNS.begin(), MediaColumn::DEFAULT_FETCH_COLUMNS.end());
1371     auto resultSet = UserFileClient::Query(uri, predicates, columns, err, context->userId);
1372     if (resultSet == nullptr) {
1373         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", err);
1374         context->SaveError(err);
1375         return;
1376     }
1377     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1378     if (fetchResult->GetCount() == 0) {
1379         return;
1380     }
1381     auto fileAsset = fetchResult->GetFirstObject();
1382     if (fileAsset == nullptr) {
1383         NAPI_WARN_LOG("Failed to get cover asset!");
1384         return;
1385     }
1386     album->SetCoverUri(fileAsset->GetUri());
1387 }
1388 
SetCompatAlbumName(AlbumAsset * albumData)1389 static void SetCompatAlbumName(AlbumAsset *albumData)
1390 {
1391     string albumName;
1392     switch (albumData->GetAlbumSubType()) {
1393         case PhotoAlbumSubType::CAMERA:
1394             albumName = CAMERA_ALBUM_NAME;
1395             break;
1396         case PhotoAlbumSubType::SCREENSHOT:
1397             albumName = SCREEN_SHOT_ALBUM_NAME;
1398             break;
1399         default:
1400             NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
1401     }
1402     albumData->SetAlbumName(albumName);
1403 }
1404 
CompatSetAlbumCount(unique_ptr<AlbumAsset> & album)1405 static void CompatSetAlbumCount(unique_ptr<AlbumAsset> &album)
1406 {
1407     MediaLibraryTracer tracer;
1408     tracer.Start("CompatSetAlbumCount");
1409     DataSharePredicates predicates;
1410     int err;
1411     if (album->GetAlbumType() == PhotoAlbumType::USER) {
1412         err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates, false);
1413     } else {
1414         err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates, false);
1415     }
1416     if (err < 0) {
1417         NAPI_WARN_LOG("Failed to set count for album subtype: %{public}d", album->GetAlbumSubType());
1418         album->SetCount(0);
1419         return;
1420     }
1421 
1422     Uri uri(URI_QUERY_PHOTO_MAP);
1423     vector<string> columns;
1424     auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1425     if (resultSet == nullptr) {
1426         NAPI_WARN_LOG("Query for assets failed! errorCode is = %{public}d", err);
1427         album->SetCount(0);
1428         return;
1429     }
1430     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1431     int32_t count = fetchResult->GetCount();
1432     album->SetCount(count);
1433 }
1434 #else
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1435 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1436 {
1437     MediaLibraryTracer tracer;
1438     tracer.Start("SetAlbumCoverUri");
1439     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1440     DataShare::DataSharePredicates predicates;
1441     predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
1442     predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
1443     predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
1444     vector<string> columns;
1445     string queryUri = MEDIALIBRARY_DATA_URI;
1446     if (!context->networkId.empty()) {
1447         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1448         NAPI_DEBUG_LOG("querycoverUri is = %{private}s", queryUri.c_str());
1449     }
1450     Uri uri(queryUri);
1451     int errCode = 0;
1452     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
1453         uri, predicates, columns, errCode);
1454     if (resultSet == nullptr) {
1455         NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
1456         return;
1457     }
1458     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1459     fetchFileResult->SetNetworkId(context->networkId);
1460     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1461     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
1462     string coverUri = fileAsset->GetUri();
1463     album->SetCoverUri(coverUri);
1464     NAPI_DEBUG_LOG("coverUri is = %{private}s", album->GetCoverUri().c_str());
1465 }
1466 #endif
1467 
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)1468 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1469     const string &networkId)
1470 {
1471 #ifdef MEDIALIBRARY_COMPATIBILITY
1472     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
1473         TYPE_INT32)));
1474     albumData->SetAlbumType(static_cast<PhotoAlbumType>(
1475         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
1476     albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
1477         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
1478     SetCompatAlbumName(albumData);
1479 #else
1480     // Get album id index and value
1481     albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
1482         TYPE_INT32)));
1483 
1484     // Get album title index and value
1485     albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
1486         TYPE_STRING)));
1487 #endif
1488 
1489     // Get album asset count index and value
1490     albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
1491     MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
1492         MEDIA_API_VERSION_DEFAULT);
1493     albumData->SetAlbumUri(fileUri.ToString());
1494     // Get album relativePath index and value
1495     albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
1496         resultSet, TYPE_STRING)));
1497     albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
1498         resultSet, TYPE_INT64)));
1499 }
1500 
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)1501 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
1502 {
1503     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1504         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1505         context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
1506         context->fetchAlbumResult->SetNetworkId(context->networkId);
1507         context->fetchAlbumResult->SetResultNapiType(context->resultNapiType);
1508         return;
1509     }
1510 
1511     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1512         unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
1513         if (albumData != nullptr) {
1514             SetAlbumData(albumData.get(), resultSet, context->networkId);
1515 #ifdef MEDIALIBRARY_COMPATIBILITY
1516             CompatSetAlbumCoverUri(context, albumData);
1517             CompatSetAlbumCount(albumData);
1518 #else
1519             SetAlbumCoverUri(context, albumData);
1520 #endif
1521             context->albumNativeArray.push_back(move(albumData));
1522         } else {
1523             context->SaveError(E_NO_MEMORY);
1524         }
1525     }
1526 }
1527 
1528 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)1529 static void ReplaceAlbumName(const string &arg, string &argInstead)
1530 {
1531     if (arg == CAMERA_ALBUM_NAME) {
1532         argInstead = to_string(PhotoAlbumSubType::CAMERA);
1533     } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
1534         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1535     } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
1536         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1537     } else {
1538         argInstead = arg;
1539     }
1540 }
1541 
DoReplaceRelativePath(const string & arg,string & argInstead)1542 static bool DoReplaceRelativePath(const string &arg, string &argInstead)
1543 {
1544     if (arg == CAMERA_PATH) {
1545         argInstead = to_string(PhotoAlbumSubType::CAMERA);
1546     } else if (arg == SCREEN_SHOT_PATH) {
1547         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1548     } else if (arg == SCREEN_RECORD_PATH) {
1549         argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1550     } else if (arg.empty()) {
1551         argInstead = arg;
1552         return false;
1553     } else {
1554         argInstead = arg;
1555     }
1556     return true;
1557 }
1558 
ReplaceRelativePath(string & selection,size_t pos,const string & keyInstead,const string & arg,string & argInstead)1559 static inline void ReplaceRelativePath(string &selection, size_t pos, const string &keyInstead, const string &arg,
1560     string &argInstead)
1561 {
1562     bool shouldReplace = DoReplaceRelativePath(arg, argInstead);
1563     if (shouldReplace) {
1564         selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), keyInstead);
1565     }
1566 }
1567 
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead,const int32_t mode)1568 void MediaLibraryNapi::ReplaceSelection(string &selection, vector<string> &selectionArgs,
1569     const string &key, const string &keyInstead, const int32_t mode)
1570 {
1571     for (size_t pos = 0; pos != string::npos;) {
1572         pos = selection.find(key, pos);
1573         if (pos == string::npos) {
1574             break;
1575         }
1576 
1577         size_t argPos = selection.find('?', pos);
1578         if (argPos == string::npos) {
1579             break;
1580         }
1581         size_t argIndex = 0;
1582         for (size_t i = 0; i < argPos; i++) {
1583             if (selection[i] == '?') {
1584                 argIndex++;
1585             }
1586         }
1587         if (argIndex > selectionArgs.size() - 1) {
1588             NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
1589                 selection.c_str());
1590             break;
1591         }
1592         const string &arg = selectionArgs[argIndex];
1593         string argInstead = arg;
1594         if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
1595             if (mode == ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH) {
1596                 argInstead = MediaFileUtils::AddDocsToRelativePath(arg);
1597             } else {
1598                 ReplaceRelativePath(selection, pos, keyInstead, arg, argInstead);
1599             }
1600         } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
1601             ReplaceAlbumName(arg, argInstead);
1602             selection.replace(pos, key.length(), keyInstead);
1603         } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
1604             selection.replace(pos, key.length(), keyInstead);
1605         }
1606         selectionArgs[argIndex] = argInstead;
1607         argPos = selection.find('?', pos);
1608         if (argPos == string::npos) {
1609             break;
1610         }
1611         pos = argPos + 1;
1612     }
1613 }
1614 
UpdateCompatSelection(MediaLibraryAsyncContext * context)1615 static void UpdateCompatSelection(MediaLibraryAsyncContext *context)
1616 {
1617     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1618         MEDIA_DATA_DB_BUCKET_ID, PhotoAlbumColumns::ALBUM_ID);
1619     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1620         MEDIA_DATA_DB_BUCKET_NAME, PhotoAlbumColumns::ALBUM_SUBTYPE);
1621     MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1622         MEDIA_DATA_DB_RELATIVE_PATH, PhotoAlbumColumns::ALBUM_SUBTYPE);
1623     static const string COMPAT_QUERY_FILTER = PhotoAlbumColumns::ALBUM_SUBTYPE + " IN (" +
1624         to_string(PhotoAlbumSubType::SCREENSHOT) + "," +
1625         to_string(PhotoAlbumSubType::CAMERA) + ")";
1626     if (!context->selection.empty()) {
1627         context->selection = COMPAT_QUERY_FILTER + " AND " + context->selection;
1628     } else {
1629         context->selection = COMPAT_QUERY_FILTER;
1630     }
1631 }
1632 #endif
1633 
GetResultDataExecute(napi_env env,void * data)1634 static void GetResultDataExecute(napi_env env, void *data)
1635 {
1636     MediaLibraryTracer tracer;
1637     tracer.Start("GetResultDataExecute");
1638 
1639     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1640 
1641 #ifdef MEDIALIBRARY_COMPATIBILITY
1642     UpdateCompatSelection(context);
1643 #else
1644     MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
1645 #endif
1646     context->predicates.SetWhereClause(context->selection);
1647     context->predicates.SetWhereArgs(context->selectionArgs);
1648     if (!context->order.empty()) {
1649         context->predicates.SetOrder(context->order);
1650     }
1651 
1652 #ifdef MEDIALIBRARY_COMPATIBILITY
1653     vector<string> columns;
1654     const set<string> &defaultFetchCols = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
1655     columns.assign(defaultFetchCols.begin(), defaultFetchCols.end());
1656     columns.push_back(PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
1657 #else
1658     vector<string> columns;
1659 #endif
1660     string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1661     if (!context->networkId.empty()) {
1662         queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
1663             MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1664         NAPI_DEBUG_LOG("queryAlbumUri is = %{private}s", queryUri.c_str());
1665     }
1666     Uri uri(queryUri);
1667     int errCode = 0;
1668     shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode,
1669         context->userId);
1670 
1671     if (resultSet == nullptr) {
1672         NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr, errCode is %{public}d", errCode);
1673         context->SaveError(errCode);
1674         return;
1675     }
1676 
1677     GetAlbumResult(context, resultSet);
1678 }
1679 
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1680 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1681     unique_ptr<JSAsyncContextOutput> &jsContext)
1682 {
1683     if (context->albumNativeArray.empty()) {
1684         napi_value albumNoArray = nullptr;
1685         napi_create_array(env, &albumNoArray);
1686         jsContext->status = true;
1687         napi_get_undefined(env, &jsContext->error);
1688         jsContext->data = albumNoArray;
1689     } else {
1690         napi_value albumArray = nullptr;
1691         napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
1692         for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
1693             napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
1694             napi_set_element(env, albumArray, i, albumNapiObj);
1695         }
1696         jsContext->status = true;
1697         napi_get_undefined(env, &jsContext->error);
1698         jsContext->data = albumArray;
1699     }
1700 }
1701 
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1702 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1703     unique_ptr<JSAsyncContextOutput> &jsContext)
1704 {
1705     if (context->fetchAlbumResult->GetCount() < 0) {
1706         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1707             "find no data by options");
1708     } else {
1709         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
1710         if (fileResult == nullptr) {
1711             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1712                 "Failed to create js object for Fetch Album Result");
1713         } else {
1714             jsContext->data = fileResult;
1715             jsContext->status = true;
1716             napi_get_undefined(env, &jsContext->error);
1717         }
1718     }
1719 }
1720 
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1721 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1722     unique_ptr<JSAsyncContextOutput> &jsContext)
1723 {
1724     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1725         MediaLibAlbumsAsyncResult(env, context, jsContext);
1726     } else {
1727         UserFileMgrAlbumsAsyncResult(env, context, jsContext);
1728     }
1729 }
1730 
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1731 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1732 {
1733     MediaLibraryTracer tracer;
1734     tracer.Start("AlbumsAsyncCallbackComplete");
1735 
1736     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1737     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1738     jsContext->status = false;
1739     napi_get_undefined(env, &jsContext->error);
1740     if (context->error != ERR_DEFAULT) {
1741         napi_get_undefined(env, &jsContext->data);
1742         context->HandleError(env, jsContext->error);
1743     } else {
1744         AlbumsAsyncResult(env, context, jsContext);
1745     }
1746 
1747     tracer.Finish();
1748     if (context->work != nullptr) {
1749         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1750                                                    context->work, *jsContext);
1751     }
1752     delete context;
1753 }
1754 
JSGetAlbums(napi_env env,napi_callback_info info)1755 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
1756 {
1757     napi_status status;
1758     napi_value result = nullptr;
1759     size_t argc = ARGS_TWO;
1760     napi_value argv[ARGS_TWO] = {0};
1761     napi_value thisVar = nullptr;
1762 
1763     MediaLibraryTracer tracer;
1764     tracer.Start("JSGetAlbums");
1765 
1766     GET_JS_ARGS(env, info, argc, argv, thisVar);
1767     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1768     napi_get_undefined(env, &result);
1769 
1770     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1771     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1772     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1773         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1774         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1775 
1776         SetUserIdFromObjectInfo(asyncContext);
1777         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
1778             AlbumsAsyncCallbackComplete);
1779     }
1780 
1781     return result;
1782 }
1783 
1784 #ifndef MEDIALIBRARY_COMPATIBILITY
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1785 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1786 {
1787     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1788     vector<string> columns;
1789     DataShare::DataSharePredicates predicates;
1790 
1791     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1792     predicates.SetWhereArgs({ to_string(id) });
1793 
1794     string queryUri = MEDIALIBRARY_DATA_URI;
1795     Uri uri(queryUri);
1796     int errCode = 0;
1797     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
1798     CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
1799 
1800     // Create FetchResult object using the contents of resultSet
1801     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1802     CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1803     context->fetchFileResult->SetNetworkId(networkId);
1804     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1805         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1806         context->fetchFileResult->SetResultNapiType(context->resultNapiType);
1807     }
1808     if (context->fetchFileResult->GetCount() < 1) {
1809         NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1810         return;
1811     }
1812     unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1813     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1814     context->fileAsset = move(fileAsset);
1815 }
1816 #endif
1817 
1818 #ifdef MEDIALIBRARY_COMPATIBILITY
SetFileAssetByIdV9(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1819 static void SetFileAssetByIdV9(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1820 {
1821     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1822     bool isValid = false;
1823     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1824     if (!isValid) {
1825         NAPI_ERR_LOG("get title is invalid");
1826         return;
1827     }
1828     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1829     if (!isValid) {
1830         NAPI_ERR_LOG("get relativePath is invalid");
1831         return;
1832     }
1833     unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1834     fileAsset->SetId(id);
1835     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1836     string uri;
1837     if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
1838         MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1839         uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(MediaType::MEDIA_TYPE_FILE,
1840             to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1841         relativePath = MediaFileUtils::RemoveDocsFromRelativePath(relativePath);
1842     } else {
1843         uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(mediaType,
1844             to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1845     }
1846     fileAsset->SetUri(uri);
1847     fileAsset->SetMediaType(mediaType);
1848     fileAsset->SetDisplayName(displayName);
1849     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1850     fileAsset->SetResultNapiType(ResultNapiType::TYPE_MEDIALIBRARY);
1851     fileAsset->SetRelativePath(relativePath);
1852     context->fileAsset = move(fileAsset);
1853 }
1854 #endif
1855 
SetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1856 static void SetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1857                                 MediaLibraryAsyncContext *context)
1858 {
1859     bool isValid = false;
1860     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1861     if (!isValid) {
1862         NAPI_ERR_LOG("getting title is invalid");
1863         return;
1864     }
1865     unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1866     fileAsset->SetId(id);
1867     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1868     fileAsset->SetUri(uri);
1869     fileAsset->SetMediaType(mediaType);
1870     fileAsset->SetDisplayName(displayName);
1871     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1872     fileAsset->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1873     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1874     fileAsset->SetUserId(context->userId);
1875     context->fileAsset = move(fileAsset);
1876 }
1877 
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1878 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1879                                            MediaLibraryAsyncContext *context)
1880 {
1881     bool isValid = false;
1882     string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1883     if (!isValid) {
1884         NAPI_ERR_LOG("getting title is invalid");
1885         return;
1886     }
1887     auto fileAsset = make_unique<FileAsset>();
1888     fileAsset->SetId(id);
1889     MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1890     fileAsset->SetUri(uri);
1891     fileAsset->SetMediaType(mediaType);
1892     fileAsset->SetDisplayName(displayName);
1893     fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1894     fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1895     fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1896     fileAsset->SetUserId(context->userId);
1897     context->fileAsset = move(fileAsset);
1898 }
1899 
JSCreateUriArrayInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1900 static void JSCreateUriArrayInCallback(napi_env env, MediaLibraryAsyncContext *context,
1901     unique_ptr<JSAsyncContextOutput> &jsContext)
1902 {
1903     napi_value jsObject = nullptr;
1904     if (context->uriArray.empty()) {
1905         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1906             "Obtain file asset uri array failed");
1907         napi_get_undefined(env, &jsContext->data);
1908     } else {
1909         napi_status status = napi_create_array(env, &jsObject);
1910         int count = 0;
1911         for (const auto &uri : context->uriArray) {
1912             napi_value uriObject = nullptr;
1913             status = napi_create_string_utf8(env, uri.c_str(), NAPI_AUTO_LENGTH, &uriObject);
1914             if (status != napi_ok || uriObject == nullptr) {
1915                 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1916                 napi_get_undefined(env, &jsContext->data);
1917                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1918                     "System inner fail");
1919                 return;
1920             }
1921 
1922             status = napi_set_element(env, jsObject, count, uriObject);
1923             if (status != napi_ok) {
1924                 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1925                 napi_get_undefined(env, &jsContext->data);
1926                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1927                     "System inner fail");
1928                 return;
1929             }
1930             ++count;
1931         }
1932 
1933         if (status != napi_ok || jsObject == nullptr) {
1934             NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1935             napi_get_undefined(env, &jsContext->data);
1936             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1937                 "System inner fail");
1938         } else {
1939             jsContext->data = jsObject;
1940             napi_get_undefined(env, &jsContext->error);
1941             jsContext->status = true;
1942         }
1943     }
1944 }
1945 
JSCreateUriInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1946 static void JSCreateUriInCallback(napi_env env, MediaLibraryAsyncContext *context,
1947     unique_ptr<JSAsyncContextOutput> &jsContext)
1948 {
1949     napi_value jsObject = nullptr;
1950     if (context->uri.empty()) {
1951         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1952             "Obtain file asset uri failed");
1953         napi_get_undefined(env, &jsContext->data);
1954     } else {
1955         napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1956         if (status != napi_ok || jsObject == nullptr) {
1957             NAPI_ERR_LOG("Failed to get file asset uri napi object");
1958             napi_get_undefined(env, &jsContext->data);
1959             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1960                 "System inner fail");
1961         } else {
1962             jsContext->data = jsObject;
1963             napi_get_undefined(env, &jsContext->error);
1964             jsContext->status = true;
1965         }
1966     }
1967 }
1968 
JSCreateAssetInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1969 static void JSCreateAssetInCallback(napi_env env, MediaLibraryAsyncContext *context,
1970     unique_ptr<JSAsyncContextOutput> &jsContext)
1971 {
1972     napi_value jsFileAsset = nullptr;
1973     if (context->fileAsset == nullptr) {
1974         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1975             "Obtain file asset failed");
1976         napi_get_undefined(env, &jsContext->data);
1977     } else {
1978         context->fileAsset->SetUserId(context->userId);
1979         jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1980         if (jsFileAsset == nullptr) {
1981             NAPI_ERR_LOG("Failed to get file asset napi object");
1982             napi_get_undefined(env, &jsContext->data);
1983             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1984                 "System inner fail");
1985         } else {
1986             NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1987             jsContext->data = jsFileAsset;
1988             napi_get_undefined(env, &jsContext->error);
1989             jsContext->status = true;
1990         }
1991     }
1992 }
1993 
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1994 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1995 {
1996     MediaLibraryTracer tracer;
1997     tracer.Start("JSCreateAssetCompleteCallback");
1998 
1999     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2000     auto jsContext = make_unique<JSAsyncContextOutput>();
2001     jsContext->status = false;
2002 
2003     if (context->error == ERR_DEFAULT) {
2004         if (context->isCreateByAgent) {
2005             JSCreateUriArrayInCallback(env, context, jsContext);
2006         } else if (context->isCreateByComponent) {
2007             JSCreateUriInCallback(env, context, jsContext);
2008         } else {
2009             JSCreateAssetInCallback(env, context, jsContext);
2010         }
2011     } else {
2012         context->HandleError(env, jsContext->error);
2013         napi_get_undefined(env, &jsContext->data);
2014     }
2015 
2016     tracer.Finish();
2017     if (context->work != nullptr) {
2018         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2019                                                    context->work, *jsContext);
2020     }
2021 
2022     NAPI_INFO_LOG("End create asset.");
2023     delete context;
2024 }
2025 
JSPhotoUriPermissionCallback(napi_env env,napi_status status,void * data)2026 static void JSPhotoUriPermissionCallback(napi_env env, napi_status status, void *data)
2027 {
2028     MediaLibraryTracer tracer;
2029     tracer.Start("JSPhotoUriPermissionCallback");
2030 
2031     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2032     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2033 
2034     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2035     jsContext->status = false;
2036 
2037     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2038     if (context->error != ERR_DEFAULT) {
2039         context->HandleError(env, jsContext->error);
2040         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
2041     } else {
2042         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
2043         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2044         jsContext->status = true;
2045     }
2046 
2047     tracer.Finish();
2048     if (context->work != nullptr) {
2049         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2050                                                    context->work, *jsContext);
2051     }
2052     delete context;
2053 }
2054 
CheckDisplayNameParams(MediaLibraryAsyncContext * context)2055 static bool CheckDisplayNameParams(MediaLibraryAsyncContext *context)
2056 {
2057     if (context == nullptr) {
2058         NAPI_ERR_LOG("Async context is null");
2059         return false;
2060     }
2061     if (!context->isCreateByComponent) {
2062         bool isValid = false;
2063         string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
2064         if (!isValid) {
2065             NAPI_ERR_LOG("getting displayName is invalid");
2066             return false;
2067         }
2068         if (displayName.empty()) {
2069             return false;
2070         }
2071     }
2072 
2073     return true;
2074 }
2075 
GetFirstDirName(const string & relativePath)2076 static string GetFirstDirName(const string &relativePath)
2077 {
2078     string firstDirName = "";
2079     if (!relativePath.empty()) {
2080         string::size_type pos = relativePath.find_first_of('/');
2081         if (pos == relativePath.length()) {
2082             return relativePath;
2083         }
2084         firstDirName = relativePath.substr(0, pos + 1);
2085         NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
2086     }
2087     return firstDirName;
2088 }
2089 
IsDirectory(const string & dirName)2090 static bool IsDirectory(const string &dirName)
2091 {
2092     struct stat statInfo {};
2093     if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == E_SUCCESS) {
2094         if (statInfo.st_mode & S_IFDIR) {
2095             return true;
2096         }
2097     }
2098 
2099     return false;
2100 }
2101 
CheckTypeOfType(const string & firstDirName,int32_t fileMediaType)2102 static bool CheckTypeOfType(const string &firstDirName, int32_t fileMediaType)
2103 {
2104     // "CDSA/"
2105     if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
2106         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
2107             return true;
2108         } else {
2109             return false;
2110         }
2111     }
2112     // "Movies/"
2113     if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
2114         if (fileMediaType == MEDIA_TYPE_VIDEO) {
2115             return true;
2116         } else {
2117             return false;
2118         }
2119     }
2120     if (!strcmp(firstDirName.c_str(), directoryEnumValues[SECOND_ENUM].c_str())) {
2121         if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
2122             return true;
2123         } else {
2124             NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
2125             return false;
2126         }
2127     }
2128     if (!strcmp(firstDirName.c_str(), directoryEnumValues[THIRD_ENUM].c_str())) {
2129         if (fileMediaType == MEDIA_TYPE_AUDIO) {
2130             return true;
2131         } else {
2132             return false;
2133         }
2134     }
2135     return true;
2136 }
CheckRelativePathParams(MediaLibraryAsyncContext * context)2137 static bool CheckRelativePathParams(MediaLibraryAsyncContext *context)
2138 {
2139     if (context == nullptr) {
2140         NAPI_ERR_LOG("Async context is null");
2141         return false;
2142     }
2143     bool isValid = false;
2144     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2145     if (!isValid) {
2146         NAPI_DEBUG_LOG("getting relativePath is invalid");
2147         return false;
2148     }
2149     isValid = false;
2150     int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
2151     if (!isValid) {
2152         NAPI_DEBUG_LOG("getting fileMediaType is invalid");
2153         return false;
2154     }
2155     if (relativePath.empty()) {
2156         return false;
2157     }
2158 
2159     if (IsDirectory(relativePath)) {
2160         return true;
2161     }
2162 
2163     string firstDirName = GetFirstDirName(relativePath);
2164     if (!firstDirName.empty() && IsDirectory(firstDirName)) {
2165         return true;
2166     }
2167 
2168     if (!firstDirName.empty()) {
2169         NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
2170         for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
2171             NAPI_DEBUG_LOG("directoryEnumValues%{private}d = %{private}s", i, directoryEnumValues[i].c_str());
2172             if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
2173                 return CheckTypeOfType(firstDirName, fileMediaType);
2174             }
2175             if (!strcmp(firstDirName.c_str(), DOCS_PATH.c_str())) {
2176                 return true;
2177             }
2178         }
2179         NAPI_ERR_LOG("Failed to check relative path, firstDirName = %{private}s", firstDirName.c_str());
2180     }
2181     return false;
2182 }
2183 
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2184 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
2185                                    MediaLibraryAsyncContext &asyncContext)
2186 {
2187     const int32_t refCount = 1;
2188     napi_value result = nullptr;
2189     auto context = &asyncContext;
2190     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2191     int32_t fileMediaType = 0;
2192     size_t res = 0;
2193     char relativePathBuffer[PATH_MAX];
2194     char titleBuffer[PATH_MAX];
2195     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2196 
2197     for (size_t i = PARAM0; i < argc; i++) {
2198         napi_valuetype valueType = napi_undefined;
2199         napi_typeof(env, argv[i], &valueType);
2200         if (i == PARAM0 && valueType == napi_number) {
2201             napi_get_value_int32(env, argv[i], &fileMediaType);
2202         } else if (i == PARAM1 && valueType == napi_string) {
2203             napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
2204             NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
2205         } else if (i == PARAM2 && valueType == napi_string) {
2206             napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
2207             NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
2208         } else if (i == PARAM3 && valueType == napi_function) {
2209             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2210         } else {
2211             NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
2212             return result;
2213     }
2214     }
2215 
2216     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
2217     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
2218     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
2219 
2220     context->assetType = TYPE_DEFAULT;
2221     if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
2222         context->assetType = TYPE_PHOTO;
2223     } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
2224         context->assetType = TYPE_AUDIO;
2225     }
2226 
2227     NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
2228     // Return true napi_value if params are successfully obtained
2229     napi_get_boolean(env, true, &result);
2230     return result;
2231 }
2232 
GetCreateUri(MediaLibraryAsyncContext * context,string & uri)2233 static void GetCreateUri(MediaLibraryAsyncContext *context, string &uri)
2234 {
2235     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
2236         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
2237         switch (context->assetType) {
2238             case TYPE_PHOTO:
2239                 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2240                     uri = (context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO;
2241                 } else {
2242                     uri = (context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT :
2243                         (context->needSystemApp ? PAH_SYS_CREATE_PHOTO : PAH_CREATE_PHOTO);
2244                 }
2245                 break;
2246             case TYPE_AUDIO:
2247                 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
2248                 break;
2249             default:
2250                 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
2251                 return;
2252         }
2253         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2254     } else {
2255 #ifdef MEDIALIBRARY_COMPATIBILITY
2256         bool isValid = false;
2257         string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2258         if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
2259             MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
2260             uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2261             MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
2262             return;
2263         }
2264         switch (context->assetType) {
2265             case TYPE_PHOTO:
2266                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2267                 break;
2268             case TYPE_AUDIO:
2269                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2270                 break;
2271             case TYPE_DEFAULT:
2272                 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2273                 break;
2274             default:
2275                 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
2276                 return;
2277         }
2278         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
2279 #else
2280         uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2281 #endif
2282     }
2283 }
2284 
JSCreateAssetExecute(napi_env env,void * data)2285 static void JSCreateAssetExecute(napi_env env, void *data)
2286 {
2287     MediaLibraryTracer tracer;
2288     tracer.Start("JSCreateAssetExecute");
2289     NAPI_INFO_LOG("JSCreateAssetExecute start");
2290 
2291     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2292     if (!CheckDisplayNameParams(context)) {
2293         context->error = JS_E_DISPLAYNAME;
2294         return;
2295     }
2296     if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathParams(context))) {
2297         context->error = JS_E_RELATIVEPATH;
2298         return;
2299     }
2300     bool isValid = false;
2301     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2302     if (isValid) {
2303         if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
2304             MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
2305             context->valuesBucket.valuesMap.erase(MEDIA_DATA_DB_RELATIVE_PATH);
2306             context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, DOCS_PATH + relativePath);
2307         }
2308     }
2309 
2310     string uri;
2311     GetCreateUri(context, uri);
2312     Uri createFileUri(uri);
2313     string outUri;
2314     int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri,
2315         context->userId);
2316     if (index < 0) {
2317         context->SaveError(index);
2318     } else {
2319         if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2320             if (context->isCreateByComponent) {
2321                 context->uri = outUri;
2322             } else {
2323                 SetFileAssetByIdV10(index, "", outUri, context);
2324             }
2325         } else {
2326 #ifdef MEDIALIBRARY_COMPATIBILITY
2327             SetFileAssetByIdV9(index, "", context);
2328 #else
2329             getFileAssetById(index, "", context);
2330 #endif
2331             LogMedialibraryAPI(context->fileAsset->GetUri());
2332         }
2333     }
2334 }
2335 
JSCreateAsset(napi_env env,napi_callback_info info)2336 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
2337 {
2338     napi_status status;
2339     napi_value result = nullptr;
2340     size_t argc = ARGS_FOUR;
2341     napi_value argv[ARGS_FOUR] = {0};
2342     napi_value thisVar = nullptr;
2343 
2344     MediaLibraryTracer tracer;
2345     tracer.Start("JSCreateAsset");
2346 
2347     GET_JS_ARGS(env, info, argc, argv, thisVar);
2348     NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
2349     napi_get_undefined(env, &result);
2350 
2351     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2352     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2353     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2354     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2355         result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
2356         ASSERT_NULLPTR_CHECK(env, result);
2357 
2358         SetUserIdFromObjectInfo(asyncContext);
2359         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
2360             JSCreateAssetCompleteCallback);
2361     }
2362 
2363     return result;
2364 }
2365 
2366 #ifdef MEDIALIBRARY_COMPATIBILITY
HandleCompatTrashAudio(MediaLibraryAsyncContext * context,const string & deleteId)2367 static void HandleCompatTrashAudio(MediaLibraryAsyncContext *context, const string &deleteId)
2368 {
2369     DataShareValuesBucket valuesBucket;
2370     valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
2371     DataSharePredicates predicates;
2372     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2373     predicates.SetWhereArgs({ deleteId });
2374     Uri uri(URI_DELETE_AUDIO);
2375     int32_t changedRows = UserFileClient::Delete(uri, predicates);
2376     if (changedRows < 0) {
2377         context->SaveError(changedRows);
2378         return;
2379     }
2380     context->retVal = changedRows;
2381 }
2382 
HandleCompatDeletePhoto(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2383 static void HandleCompatDeletePhoto(MediaLibraryAsyncContext *context,
2384     const string &mediaType, const string &deleteId)
2385 {
2386     Uri uri(URI_COMPAT_DELETE_PHOTOS);
2387     DataSharePredicates predicates;
2388     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ deleteId }));
2389     DataShareValuesBucket valuesBucket;
2390     valuesBucket.Put(MediaColumn::MEDIA_ID, deleteId);
2391     int changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2392     if (changedRows < 0) {
2393         context->SaveError(changedRows);
2394         return;
2395     }
2396     context->retVal = changedRows;
2397 }
2398 
HandleCompatDelete(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2399 static inline void HandleCompatDelete(MediaLibraryAsyncContext *context,
2400     const string &mediaType, const string &deleteId)
2401 {
2402     if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE) {
2403         return HandleCompatDeletePhoto(context, mediaType, deleteId);
2404     }
2405     if (mediaType == AUDIO_ASSET_TYPE) {
2406         return HandleCompatTrashAudio(context, deleteId);
2407     }
2408 
2409     NAPI_WARN_LOG("Ignore unsupported media type deletion: %{private}s", mediaType.c_str());
2410 }
2411 #endif
2412 
JSDeleteAssetExecute(napi_env env,void * data)2413 static void JSDeleteAssetExecute(napi_env env, void *data)
2414 {
2415     MediaLibraryTracer tracer;
2416     tracer.Start("JSDeleteAssetExecute");
2417 
2418     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2419     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2420 
2421     string mediaType;
2422     string deleteId;
2423     bool isValid = false;
2424     string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2425     if (!isValid) {
2426         context->error = ERR_INVALID_OUTPUT;
2427         return;
2428     }
2429 #ifdef MEDIALIBRARY_COMPATIBILITY
2430     notifyUri = MediaFileUtils::GetRealUriFromVirtualUri(notifyUri);
2431 #endif
2432     size_t index = notifyUri.rfind('/');
2433     if (index != string::npos) {
2434         deleteId = notifyUri.substr(index + 1);
2435         notifyUri = notifyUri.substr(0, index);
2436         size_t indexType = notifyUri.rfind('/');
2437         if (indexType != string::npos) {
2438             mediaType = notifyUri.substr(indexType + 1);
2439         }
2440     }
2441     if (MediaFileUtils::IsUriV10(mediaType)) {
2442         NAPI_ERR_LOG("Unsupported media type: %{private}s", mediaType.c_str());
2443         context->SaveError(E_INVALID_URI);
2444         return;
2445     }
2446 #ifdef MEDIALIBRARY_COMPATIBILITY
2447     if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE || mediaType == AUDIO_ASSET_TYPE) {
2448         return HandleCompatDelete(context, mediaType, deleteId);
2449     }
2450 #endif
2451     notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
2452     string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET;
2453     Uri deleteAssetUri(deleteUri);
2454     DataSharePredicates predicates;
2455     predicates.EqualTo(MEDIA_DATA_DB_ID, deleteId);
2456     int retVal = UserFileClient::Delete(deleteAssetUri, predicates);
2457     if (retVal < 0) {
2458         context->SaveError(retVal);
2459     } else {
2460         context->retVal = retVal;
2461         Uri deleteNotify(notifyUri);
2462         UserFileClient::NotifyChange(deleteNotify);
2463     }
2464 }
2465 
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)2466 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
2467 {
2468     MediaLibraryTracer tracer;
2469     tracer.Start("JSDeleteAssetCompleteCallback");
2470 
2471     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2472     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2473     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2474     jsContext->status = false;
2475 
2476     if (context->error == ERR_DEFAULT) {
2477         NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
2478         napi_create_int32(env, context->retVal, &jsContext->data);
2479         napi_get_undefined(env, &jsContext->error);
2480         jsContext->status = true;
2481     } else {
2482         context->HandleError(env, jsContext->error);
2483         napi_get_undefined(env, &jsContext->data);
2484     }
2485 
2486     tracer.Finish();
2487     if (context->work != nullptr) {
2488         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2489                                                    context->work, *jsContext);
2490     }
2491 
2492     delete context;
2493 }
2494 
JSTrashAssetExecute(napi_env env,void * data)2495 static void JSTrashAssetExecute(napi_env env, void *data)
2496 {
2497     MediaLibraryTracer tracer;
2498     tracer.Start("JSTrashAssetExecute");
2499 
2500     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2501     string uri = context->uri;
2502     if (uri.empty()) {
2503         context->error = ERR_INVALID_OUTPUT;
2504         return;
2505     }
2506     MediaFileUri::RemoveAllFragment(uri);
2507     string trashId = MediaFileUtils::GetIdFromUri(uri);
2508     string trashUri;
2509     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
2510         trashUri = UFM_UPDATE_PHOTO;
2511     } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
2512         trashUri = UFM_UPDATE_AUDIO;
2513     } else {
2514         context->error = E_VIOLATION_PARAMETERS;
2515         return;
2516     }
2517     MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2518     Uri updateAssetUri(trashUri);
2519     DataSharePredicates predicates;
2520     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2521     predicates.SetWhereArgs({ trashId });
2522     DataShareValuesBucket valuesBucket;
2523     valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
2524     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2525     if (changedRows < 0) {
2526         context->SaveError(changedRows);
2527         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
2528     }
2529 }
2530 
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)2531 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
2532 {
2533     MediaLibraryTracer tracer;
2534     tracer.Start("JSTrashAssetCompleteCallback");
2535 
2536     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2537     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2538     jsContext->status = false;
2539     napi_get_undefined(env, &jsContext->data);
2540     if (context->error == ERR_DEFAULT) {
2541         jsContext->status = true;
2542     } else {
2543         context->HandleError(env, jsContext->error);
2544     }
2545     if (context->work != nullptr) {
2546         tracer.Finish();
2547         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2548             context->work, *jsContext);
2549     }
2550 
2551     delete context;
2552 }
2553 
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2554 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
2555                                    MediaLibraryAsyncContext &asyncContext)
2556 {
2557     const int32_t refCount = 1;
2558     napi_value result = nullptr;
2559     auto context = &asyncContext;
2560     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2561     size_t res = 0;
2562     char buffer[PATH_MAX];
2563 
2564     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2565 
2566     for (size_t i = PARAM0; i < argc; i++) {
2567         napi_valuetype valueType = napi_undefined;
2568         napi_typeof(env, argv[i], &valueType);
2569 
2570         if (i == PARAM0 && valueType == napi_string) {
2571             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2572         } else if (i == PARAM1 && valueType == napi_function) {
2573             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2574             break;
2575         } else {
2576             NAPI_ASSERT(env, false, "type mismatch");
2577         }
2578     }
2579 
2580     context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
2581 
2582     // Return true napi_value if params are successfully obtained
2583     napi_get_boolean(env, true, &result);
2584     return result;
2585 }
2586 
JSDeleteAsset(napi_env env,napi_callback_info info)2587 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
2588 {
2589     napi_status status;
2590     napi_value result = nullptr;
2591     size_t argc = ARGS_TWO;
2592     napi_value argv[ARGS_TWO] = {0};
2593     napi_value thisVar = nullptr;
2594 
2595     MediaLibraryTracer tracer;
2596     tracer.Start("JSDeleteAsset");
2597 
2598     GET_JS_ARGS(env, info, argc, argv, thisVar);
2599     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2600     napi_get_undefined(env, &result);
2601 
2602     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2603     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2604     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2605         result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
2606         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2607 
2608         SetUserIdFromObjectInfo(asyncContext);
2609         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
2610             JSDeleteAssetCompleteCallback);
2611     }
2612 
2613     return result;
2614 }
2615 
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2616 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2617 {
2618     napi_value value;
2619     napi_status status = napi_create_int32(env, intValue, &value);
2620     if (status != napi_ok) {
2621         NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2622         return status;
2623     }
2624     status = napi_set_named_property(env, result, fieldStr, value);
2625     if (status != napi_ok) {
2626         NAPI_ERR_LOG("Set int32 named property error! field: %{public}s, status: %{public}d", fieldStr, status);
2627     }
2628     return status;
2629 }
2630 
SetValueArray(const napi_env & env,const char * fieldStr,const std::list<Uri> listValue,napi_value & result)2631 static napi_status SetValueArray(const napi_env& env,
2632     const char* fieldStr, const std::list<Uri> listValue, napi_value& result)
2633 {
2634     napi_value value = nullptr;
2635     napi_status status = napi_create_array_with_length(env, listValue.size(), &value);
2636     if (status != napi_ok) {
2637         NAPI_ERR_LOG("Create array error! field: %{public}s", fieldStr);
2638         return status;
2639     }
2640     int elementIndex = 0;
2641     for (auto uri : listValue) {
2642         napi_value uriRet = nullptr;
2643         napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &uriRet);
2644         status = napi_set_element(env, value, elementIndex++, uriRet);
2645         if (status != napi_ok) {
2646             NAPI_ERR_LOG("Set lite item failed, error: %d", status);
2647         }
2648     }
2649     status = napi_set_named_property(env, result, fieldStr, value);
2650     if (status != napi_ok) {
2651         NAPI_ERR_LOG("Set array named property error! field: %{public}s", fieldStr);
2652     }
2653 
2654     return status;
2655 }
2656 
SetSharedAssetArray(const napi_env & env,const char * fieldStr,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,napi_value & result,bool isPhoto)2657 napi_status ChangeListenerNapi::SetSharedAssetArray(const napi_env& env, const char* fieldStr,
2658     ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper, napi_value& result, bool isPhoto)
2659 {
2660     MediaLibraryTracer tracer;
2661     tracer.Start("SolveOnChange BuildSharedPhotoAssetsObj");
2662     std::vector<std::string> assetIds;
2663     napi_status status = napi_ok;
2664     napi_value assetResults =  ChangeListenerNapi::BuildSharedPhotoAssetsObj(env, wrapper, isPhoto);
2665     if (assetResults == nullptr) {
2666         NAPI_ERR_LOG("Failed to get assets Result from rdb");
2667         status = napi_invalid_arg;
2668         return status;
2669     }
2670     status = napi_set_named_property(env, result, fieldStr, assetResults);
2671     if (status != napi_ok) {
2672         NAPI_ERR_LOG("set array named property error: %{public}s", fieldStr);
2673     }
2674     return status;
2675 }
2676 
SetSubUris(const napi_env & env,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,napi_value & result)2677 static napi_status SetSubUris(const napi_env& env, ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper,
2678     napi_value& result)
2679 {
2680     MediaLibraryTracer tracer;
2681     tracer.Start("SolveOnChange SetSubUris");
2682     uint32_t len = wrapper->extraUris_.size();
2683     napi_status status = napi_invalid_arg;
2684     napi_value subUriArray = nullptr;
2685     napi_create_array_with_length(env, len, &subUriArray);
2686     int subElementIndex = 0;
2687     for (auto iter = wrapper->extraUris_.begin(); iter != wrapper->extraUris_.end(); iter++) {
2688         string subUri = *iter;
2689         if (subUri.empty()) {
2690             NAPI_ERR_LOG("Failed to read sub uri");
2691             return status;
2692         }
2693         napi_value subUriRet = nullptr;
2694         napi_create_string_utf8(env, subUri.c_str(), NAPI_AUTO_LENGTH, &subUriRet);
2695         napi_set_element(env, subUriArray, subElementIndex++, subUriRet);
2696     }
2697     status = napi_set_named_property(env, result, "extraUris", subUriArray);
2698     if (status != napi_ok) {
2699         NAPI_ERR_LOG("Set subUri named property error!");
2700     }
2701     napi_value photoAssetArray = MediaLibraryNapiUtils::GetSharedPhotoAssets(env, wrapper->extraSharedAssets_, len);
2702     if (photoAssetArray == nullptr) {
2703         NAPI_ERR_LOG("Failed to get sharedPhotoAsset");
2704     }
2705     status = napi_set_named_property(env, result, "sharedExtraPhotoAssets", photoAssetArray);
2706     if (status != napi_ok) {
2707         NAPI_ERR_LOG("Set extraAssets named property error!");
2708     }
2709     return status;
2710 }
2711 
GetTrashAlbumUri()2712 string ChangeListenerNapi::GetTrashAlbumUri()
2713 {
2714     MediaLibraryTracer tracer;
2715     tracer.Start("ChangeListenerNapi::GetTrashAlbumUri");
2716     if (!trashAlbumUri_.empty()) {
2717         return trashAlbumUri_;
2718     }
2719     string queryUri = UFM_QUERY_PHOTO_ALBUM;
2720     Uri uri(queryUri);
2721     int errCode = 0;
2722     DataSharePredicates predicates;
2723     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::TRASH));
2724     vector<string> columns;
2725     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2726     unique_ptr<FetchResult<PhotoAlbum>> albumSet = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
2727     if (albumSet == nullptr) {
2728         return trashAlbumUri_;
2729     }
2730     if (albumSet->GetCount() != 1) {
2731         return trashAlbumUri_;
2732     }
2733     unique_ptr<PhotoAlbum> albumAssetPtr = albumSet->GetFirstObject();
2734     if (albumAssetPtr == nullptr) {
2735         return trashAlbumUri_;
2736     }
2737     return albumSet->GetFirstObject()->GetAlbumUri();
2738 }
2739 
SolveOnChange(napi_env env,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper)2740 napi_value ChangeListenerNapi::SolveOnChange(napi_env env, ChangeListenerNapi::JsOnChangeCallbackWrapper* wrapper)
2741 {
2742     MediaLibraryTracer tracer;
2743     tracer.Start("ChangeListenerNapi::SolveOnChange");
2744     UvChangeMsg* msg = wrapper->msg_;
2745     static napi_value result;
2746     if (msg->changeInfo_.uris_.empty()) {
2747         napi_get_undefined(env, &result);
2748         NAPI_ERR_LOG("changeInfo_.uris_ is empty");
2749         return result;
2750     }
2751     napi_create_object(env, &result);
2752     SetValueArray(env, "uris", msg->changeInfo_.uris_, result);
2753     if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2754         ChangeListenerNapi::SetSharedAssetArray(env, "sharedAlbumAssets", wrapper, result, false);
2755     } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2756         ChangeListenerNapi::SetSharedAssetArray(env, "sharedPhotoAssets", wrapper, result, true);
2757     } else {
2758         NAPI_DEBUG_LOG("other albums notify");
2759     }
2760 
2761     if (msg->changeInfo_.uris_.size() == DEFAULT_ALBUM_COUNT) {
2762         if (msg->changeInfo_.uris_.front().ToString().compare(GetTrashAlbumUri()) == 0) {
2763             if (!MediaLibraryNapiUtils::IsSystemApp()) {
2764                 napi_get_undefined(env, &result);
2765                 NAPI_ERR_LOG("tha app is not system");
2766                 return nullptr;
2767             }
2768         }
2769     }
2770     if (msg->data_ != nullptr && msg->changeInfo_.size_ > 0) {
2771         if ((int)msg->changeInfo_.changeType_ == ChangeType::INSERT) {
2772             SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_ADD_ASSET, result);
2773         } else {
2774             SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, result);
2775         }
2776         napi_status status = SetSubUris(env, wrapper, result);
2777         if (status != napi_ok) {
2778             NAPI_ERR_LOG("Set subArray named property error! field: subUris");
2779         }
2780     } else {
2781         SetValueInt32(env, "type", (int)msg->changeInfo_.changeType_, result);
2782     }
2783     return result;
2784 }
2785 
GetSharedResultSetFromIds(std::vector<string> & Ids,bool isPhoto)2786 std::shared_ptr<NativeRdb::ResultSet> ChangeListenerNapi::GetSharedResultSetFromIds(std::vector<string>& Ids,
2787     bool isPhoto)
2788 {
2789     string queryString = isPhoto ? PAH_QUERY_PHOTO : PAH_QUERY_PHOTO_ALBUM;
2790     MediaLibraryNapiUtils::UriAppendKeyValue(queryString, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2791     Uri queryUri(queryString);
2792     DataShare::DataSharePredicates predicates;
2793     if (isPhoto) {
2794         predicates.In(MediaColumn::MEDIA_ID, Ids);
2795     } else {
2796         predicates.In(PhotoAlbumColumns::ALBUM_ID, Ids);
2797     }
2798     std::vector<std::string> columns = isPhoto ? PHOTO_COLUMN : ALBUM_COLUMN;
2799     return UserFileClient::QueryRdb(queryUri, predicates, columns);
2800 }
2801 
GetIdsFromUris(std::list<Uri> & listValue,std::vector<std::string> & ids,bool isPhoto)2802 void ChangeListenerNapi::GetIdsFromUris(std::list<Uri>& listValue, std::vector<std::string>& ids, bool isPhoto)
2803 {
2804     for (auto& uri : listValue) {
2805         string assetId = isPhoto ? MediaLibraryNapiUtils::GetFileIdFromUriString(uri.ToString()) :
2806             MediaLibraryNapiUtils::GetAlbumIdFromUriString(uri.ToString());
2807         if (assetId == "") {
2808             NAPI_WARN_LOG("Failed to read assetId");
2809             continue;
2810         }
2811         ids.push_back(assetId);
2812     }
2813 }
2814 
GetResultSetFromMsg(UvChangeMsg * msg,JsOnChangeCallbackWrapper * wrapper)2815 void ChangeListenerNapi::GetResultSetFromMsg(UvChangeMsg *msg, JsOnChangeCallbackWrapper* wrapper)
2816 {
2817     std::vector<string> ids = {};
2818     std::shared_ptr<NativeRdb::ResultSet> sharedAssets = nullptr;
2819     if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2820         GetIdsFromUris(msg->changeInfo_.uris_, ids, false);
2821         sharedAssets = GetSharedResultSetFromIds(ids, false);
2822     } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2823         GetIdsFromUris(msg->changeInfo_.uris_, ids, true);
2824         sharedAssets = GetSharedResultSetFromIds(ids, true);
2825     } else {
2826         NAPI_DEBUG_LOG("other albums notify");
2827     }
2828     wrapper->uriSize_ = ids.size();
2829     wrapper->sharedAssets_ = sharedAssets;
2830     shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
2831     std::vector<string> extraIds = {};
2832     if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(msg->data_), msg->changeInfo_.size_)) {
2833         uint32_t len = 0;
2834         if (!parcel->ReadUint32(len)) {
2835             NAPI_ERR_LOG("Failed to read sub uri list length");
2836             return;
2837         }
2838         if (len > MAX_LEN_LIMIT) {
2839             NAPI_ERR_LOG("len exceed the limit.");
2840             return;
2841         }
2842         for (uint32_t i = 0; i < len; i++) {
2843             string subUri = parcel->ReadString();
2844             if (subUri.empty()) {
2845                 NAPI_ERR_LOG("Failed to read sub uri");
2846                 continue;
2847             }
2848             wrapper->extraUris_.push_back(subUri);
2849             string fileId = MediaLibraryNapiUtils::GetFileIdFromUriString(subUri);
2850             if (!fileId.empty()) {
2851                 extraIds.push_back(fileId);
2852             }
2853         }
2854         if (len > MAX_QUERY_LIMIT) {
2855             NAPI_INFO_LOG("subUri length exceed the limit.");
2856             wrapper->extraSharedAssets_ = nullptr;
2857             return;
2858         }
2859         if (extraIds.size() != 0) {
2860             wrapper->extraSharedAssets_ = GetSharedResultSetFromIds(extraIds, true);
2861         }
2862     }
2863 }
2864 
OnChange(MediaChangeListener & listener,const napi_ref cbRef)2865 void ChangeListenerNapi::OnChange(MediaChangeListener &listener, const napi_ref cbRef)
2866 {
2867     UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef, listener.changeInfo, listener.strUri);
2868     if (msg == nullptr) {
2869         return;
2870     }
2871     if (!listener.changeInfo.uris_.empty()) {
2872         if (listener.changeInfo.changeType_ == DataShare::DataShareObserver::ChangeType::OTHER) {
2873             NAPI_ERR_LOG("changeInfo.changeType_ is other");
2874             delete msg;
2875             return;
2876         }
2877         if (msg->changeInfo_.size_ > 0) {
2878             msg->data_ = (uint8_t *)malloc(msg->changeInfo_.size_);
2879             if (msg->data_ == nullptr) {
2880                 NAPI_ERR_LOG("new msg->data failed");
2881                 delete msg;
2882                 return;
2883             }
2884             int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
2885             if (copyRet != 0) {
2886                 NAPI_ERR_LOG("Parcel data copy failed, err = %{public}d", copyRet);
2887             }
2888         }
2889     }
2890     QueryRdbAndNotifyChange(msg);
2891 }
2892 
QueryRdbAndNotifyChange(UvChangeMsg * msg)2893 void ChangeListenerNapi::QueryRdbAndNotifyChange(UvChangeMsg *msg)
2894 {
2895     JsOnChangeCallbackWrapper* wrapper = new (std::nothrow) JsOnChangeCallbackWrapper();
2896     if (wrapper == nullptr) {
2897         NAPI_ERR_LOG("JsOnChangeCallbackWrapper allocation failed");
2898         delete msg;
2899         return;
2900     }
2901     wrapper->msg_ = msg;
2902     MediaLibraryTracer tracer;
2903     tracer.Start("GetResultSetFromMsg");
2904     GetResultSetFromMsg(msg, wrapper);
2905     tracer.Finish();
2906     int ret = 0;
2907     if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2908         ret = ChangeListenerNapi::ParseSharedPhotoAssets(wrapper, false);
2909     } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2910         ret = ChangeListenerNapi::ParseSharedPhotoAssets(wrapper, true);
2911     } else {
2912         NAPI_INFO_LOG("other albums notify");
2913     }
2914     if (ret != 0) {
2915         wrapper->sharedAssetsRowObjVector_.clear();
2916         NAPI_WARN_LOG("Failed to ParseSharedPhotoAssets, ret: %{public}d", ret);
2917     }
2918     std::function<void()> task = [wrapper, this]() {
2919         UvQueueWork(wrapper);
2920     };
2921     ret = napi_send_event(env_, task, napi_eprio_immediate);
2922     if (ret != 0) {
2923         NAPI_ERR_LOG("Failed to execute napi_send_event, ret: %{public}d", ret);
2924         free(msg->data_);
2925         delete msg;
2926         delete wrapper;
2927     }
2928 }
2929 
UvQueueWork(JsOnChangeCallbackWrapper * wrapper)2930 void ChangeListenerNapi::UvQueueWork(JsOnChangeCallbackWrapper* wrapper)
2931 {
2932     if (wrapper == nullptr) {
2933         return;
2934     }
2935     UvChangeMsg* msg = reinterpret_cast<UvChangeMsg *>(wrapper->msg_);
2936     do {
2937         if (msg == nullptr) {
2938             NAPI_ERR_LOG("UvChangeMsg is null");
2939             break;
2940         }
2941         napi_env env = msg->env_;
2942         NapiScopeHandler scopeHandler(env);
2943         if (!scopeHandler.IsValid()) {
2944             NAPI_ERR_LOG("scopeHandler is invalid");
2945             break;
2946         }
2947 
2948         napi_value jsCallback = nullptr;
2949         napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
2950         if (status != napi_ok) {
2951             NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2952             break;
2953         }
2954         napi_value retVal = nullptr;
2955         napi_value result[ARGS_ONE];
2956         result[PARAM0] = ChangeListenerNapi::SolveOnChange(env, wrapper);
2957         if (result[PARAM0] == nullptr) {
2958             NAPI_ERR_LOG("result is nullptr");
2959             break;
2960         }
2961         MediaLibraryTracer tracer;
2962         tracer.Start("ChangeListenerNapi::napi_call_function");
2963         napi_call_function(env, nullptr, jsCallback, ARGS_ONE, result, &retVal);
2964         if (status != napi_ok) {
2965             NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
2966             break;
2967         }
2968     } while (0);
2969     delete msg;
2970     delete wrapper;
2971 }
2972 
ParseSharedPhotoAssets(ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,bool isPhoto)2973 int ChangeListenerNapi::ParseSharedPhotoAssets(ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper, bool isPhoto)
2974 {
2975     MediaLibraryTracer tracer;
2976     std::string traceName = std::string("ParseSharedPhotoAssets to wrapper for ") + (isPhoto ? "photo" : "album");
2977     tracer.Start(traceName.c_str());
2978     int ret = -1;
2979     if (wrapper->uriSize_ > MAX_QUERY_LIMIT) {
2980         return ret;
2981     }
2982 
2983     std::shared_ptr<NativeRdb::ResultSet> result = wrapper->sharedAssets_;
2984     if (result == nullptr) {
2985         NAPI_WARN_LOG("ParseSharedPhotoAssets result is nullptr");
2986         return ret;
2987     }
2988     wrapper->sharedAssetsRowObjVector_.clear();
2989     while (result->GoToNextRow() == NativeRdb::E_OK) {
2990         std::shared_ptr<RowObject> rowObj = std::make_shared<RowObject>();
2991         if (isPhoto) {
2992             ret = MediaLibraryNapiUtils::ParseNextRowObject(rowObj, result, true);
2993         } else {
2994             ret = MediaLibraryNapiUtils::ParseNextRowAlbumObject(rowObj, result);
2995         }
2996         if (ret != NativeRdb::E_OK) {
2997             result->Close();
2998             return ret;
2999         }
3000         wrapper->sharedAssetsRowObjVector_.emplace_back(std::move(rowObj));
3001     }
3002     result->Close();
3003     return ret;
3004 }
3005 
BuildSharedPhotoAssetsObj(const napi_env & env,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,bool isPhoto)3006 napi_value ChangeListenerNapi::BuildSharedPhotoAssetsObj(const napi_env& env,
3007     ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper, bool isPhoto)
3008 {
3009     napi_value value = nullptr;
3010     napi_status status = napi_create_array_with_length(env, wrapper->sharedAssetsRowObjVector_.size(), &value);
3011     CHECK_COND_RET(status == napi_ok, nullptr, "Create array error!");
3012     napi_value tmpValue = nullptr;
3013     status = napi_create_array_with_length(env, 0, &tmpValue);
3014     CHECK_COND_RET(status == napi_ok, nullptr, "Create array error!");
3015     if (wrapper->uriSize_ > MAX_QUERY_LIMIT) {
3016         NAPI_WARN_LOG("BuildSharedPhotoAssetsObj uriSize is over limit");
3017         return tmpValue;
3018     }
3019     if (wrapper->sharedAssets_ == nullptr) {
3020         NAPI_WARN_LOG("wrapper sharedAssets is nullptr");
3021         return tmpValue;
3022     }
3023     size_t elementIndex = 0;
3024     while (elementIndex < wrapper->sharedAssetsRowObjVector_.size()) {
3025         napi_value assetValue;
3026         if (isPhoto) {
3027             assetValue = MediaLibraryNapiUtils::BuildNextRowObject(
3028                 env, wrapper->sharedAssetsRowObjVector_[elementIndex], true);
3029         } else {
3030             assetValue = MediaLibraryNapiUtils::BuildNextRowAlbumObject(
3031                 env, wrapper->sharedAssetsRowObjVector_[elementIndex]);
3032         }
3033         if (assetValue == nullptr) {
3034             wrapper->sharedAssets_->Close();
3035             return tmpValue;
3036         }
3037         status = napi_set_element(env, value, elementIndex++, assetValue);
3038         if (status != napi_ok) {
3039             NAPI_ERR_LOG("Set photo asset value failed");
3040             wrapper->sharedAssets_->Close();
3041             return tmpValue;
3042         }
3043     }
3044     wrapper->sharedAssets_->Close();
3045     return value;
3046 }
3047 
GetListenerType(const string & str) const3048 int32_t MediaLibraryNapi::GetListenerType(const string &str) const
3049 {
3050     auto iter = ListenerTypeMaps.find(str);
3051     if (iter == ListenerTypeMaps.end()) {
3052         NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
3053         return INVALID_LISTENER;
3054     }
3055 
3056     return iter->second;
3057 }
3058 
RegisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)3059 void MediaLibraryNapi::RegisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
3060 {
3061     NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
3062 
3063     int32_t typeEnum = GetListenerType(type);
3064     switch (typeEnum) {
3065         case AUDIO_LISTENER:
3066             listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
3067             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
3068             break;
3069         case VIDEO_LISTENER:
3070             listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
3071             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
3072             break;
3073         case IMAGE_LISTENER:
3074             listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
3075             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
3076             break;
3077         case FILE_LISTENER:
3078             listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
3079             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
3080             break;
3081         case SMARTALBUM_LISTENER:
3082             listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
3083             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
3084                 listObj.smartAlbumDataObserver_);
3085             break;
3086         case DEVICE_LISTENER:
3087             listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
3088             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
3089             break;
3090         case REMOTEFILE_LISTENER:
3091             listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
3092             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
3093             break;
3094         case ALBUM_LISTENER:
3095             listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
3096             UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
3097             break;
3098         default:
3099             NAPI_ERR_LOG("Invalid Media Type!");
3100     }
3101 }
3102 
RegisterNotifyChange(napi_env env,const std::string & uri,bool isDerived,napi_ref ref,ChangeListenerNapi & listObj)3103 void MediaLibraryNapi::RegisterNotifyChange(napi_env env,
3104     const std::string &uri, bool isDerived, napi_ref ref, ChangeListenerNapi &listObj)
3105 {
3106     Uri notifyUri(uri);
3107     shared_ptr<MediaOnNotifyObserver> observer= make_shared<MediaOnNotifyObserver>(listObj, uri, ref);
3108     UserFileClient::RegisterObserverExt(notifyUri,
3109         static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), isDerived);
3110     lock_guard<mutex> lock(sOnOffMutex_);
3111     listObj.observers_.push_back(observer);
3112 }
3113 
JSOnCallback(napi_env env,napi_callback_info info)3114 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
3115 {
3116     MediaLibraryTracer tracer;
3117     tracer.Start("JSOnCallback");
3118     napi_value undefinedResult = nullptr;
3119     napi_get_undefined(env, &undefinedResult);
3120     size_t argc = ARGS_TWO;
3121     napi_value argv[ARGS_TWO] = {nullptr};
3122     napi_value thisVar = nullptr;
3123     GET_JS_ARGS(env, info, argc, argv, thisVar);
3124     NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
3125     MediaLibraryNapi *obj = nullptr;
3126     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3127     if (status == napi_ok && obj != nullptr) {
3128         napi_valuetype valueType = napi_undefined;
3129         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
3130             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3131             return undefinedResult;
3132         }
3133         char buffer[ARG_BUF_SIZE];
3134         size_t res = 0;
3135         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3136             NAPI_ERR_LOG("Failed to get value string utf8 for type");
3137             return undefinedResult;
3138         }
3139         string type = string(buffer);
3140         const int32_t refCount = 1;
3141         napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
3142         tracer.Start("RegisterChange");
3143         obj->RegisterChange(env, type, *g_listObj);
3144         tracer.Finish();
3145     }
3146     return undefinedResult;
3147 }
3148 
CheckRef(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,bool isOff,const string & uri)3149 bool MediaLibraryNapi::CheckRef(napi_env env,
3150     napi_ref ref, ChangeListenerNapi &listObj, bool isOff, const string &uri)
3151 {
3152     napi_value offCallback = nullptr;
3153     napi_status status = napi_get_reference_value(env, ref, &offCallback);
3154     if (status != napi_ok) {
3155         NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
3156         return false;
3157     }
3158     bool isSame = false;
3159     shared_ptr<DataShare::DataShareObserver> obs;
3160     string obsUri;
3161     {
3162         lock_guard<mutex> lock(sOnOffMutex_);
3163         for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
3164             napi_value onCallback = nullptr;
3165             status = napi_get_reference_value(env, (*it)->ref_, &onCallback);
3166             if (status != napi_ok) {
3167                 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
3168                 return false;
3169             }
3170             napi_strict_equals(env, offCallback, onCallback, &isSame);
3171             if (isSame) {
3172                 obsUri = (*it)->uri_;
3173                 if ((isOff) && (uri.compare(obsUri) == 0)) {
3174                     obs = static_cast<shared_ptr<DataShare::DataShareObserver>>(*it);
3175                     listObj.observers_.erase(it);
3176                     break;
3177                 }
3178                 if (uri.compare(obsUri) != 0) {
3179                     return true;
3180                 }
3181                 return false;
3182             }
3183         }
3184     }
3185     if (isSame && isOff) {
3186         if (obs != nullptr) {
3187             UserFileClient::UnregisterObserverExt(Uri(obsUri), obs);
3188         }
3189     }
3190     return true;
3191 }
3192 
UserFileMgrOnCallback(napi_env env,napi_callback_info info)3193 napi_value MediaLibraryNapi::UserFileMgrOnCallback(napi_env env, napi_callback_info info)
3194 {
3195     MediaLibraryTracer tracer;
3196     tracer.Start("UserFileMgrOnCallback");
3197     napi_value undefinedResult = nullptr;
3198     napi_get_undefined(env, &undefinedResult);
3199     size_t argc = ARGS_THREE;
3200     napi_value argv[ARGS_THREE] = {nullptr};
3201     napi_value thisVar = nullptr;
3202     GET_JS_ARGS(env, info, argc, argv, thisVar);
3203     if (argc == ARGS_TWO) {
3204         return JSOnCallback(env, info);
3205     }
3206     NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
3207     MediaLibraryNapi *obj = nullptr;
3208     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3209     if (status == napi_ok && obj != nullptr) {
3210         napi_valuetype valueType = napi_undefined;
3211         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
3212             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
3213             napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
3214             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3215             return undefinedResult;
3216         }
3217         char buffer[ARG_BUF_SIZE];
3218         size_t res = 0;
3219         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3220             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3221             return undefinedResult;
3222         }
3223         string uri = string(buffer);
3224         bool isDerived = false;
3225         if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
3226             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3227             return undefinedResult;
3228         }
3229         const int32_t refCount = 1;
3230         napi_ref cbOnRef = nullptr;
3231         napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
3232         tracer.Start("RegisterNotifyChange");
3233         if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
3234             obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
3235         } else {
3236             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3237             napi_delete_reference(env, cbOnRef);
3238             cbOnRef = nullptr;
3239             return undefinedResult;
3240         }
3241         tracer.Finish();
3242     }
3243     return undefinedResult;
3244 }
3245 
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)3246 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
3247 {
3248     NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
3249 
3250     MediaType mediaType;
3251     int32_t typeEnum = GetListenerType(type);
3252 
3253     switch (typeEnum) {
3254         case AUDIO_LISTENER:
3255             CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
3256             mediaType = MEDIA_TYPE_AUDIO;
3257             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
3258             listObj.audioDataObserver_ = nullptr;
3259             break;
3260         case VIDEO_LISTENER:
3261             CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
3262             mediaType = MEDIA_TYPE_VIDEO;
3263             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
3264             listObj.videoDataObserver_ = nullptr;
3265             break;
3266         case IMAGE_LISTENER:
3267             CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
3268             mediaType = MEDIA_TYPE_IMAGE;
3269             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
3270             listObj.imageDataObserver_ = nullptr;
3271             break;
3272         case FILE_LISTENER:
3273             CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
3274             mediaType = MEDIA_TYPE_FILE;
3275             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
3276             listObj.fileDataObserver_ = nullptr;
3277             break;
3278         case SMARTALBUM_LISTENER:
3279             CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
3280             mediaType = MEDIA_TYPE_SMARTALBUM;
3281             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
3282                 listObj.smartAlbumDataObserver_);
3283             listObj.smartAlbumDataObserver_ = nullptr;
3284             break;
3285         case DEVICE_LISTENER:
3286             CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
3287             mediaType = MEDIA_TYPE_DEVICE;
3288             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
3289             listObj.deviceDataObserver_ = nullptr;
3290             break;
3291         case REMOTEFILE_LISTENER:
3292             CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
3293             mediaType = MEDIA_TYPE_REMOTEFILE;
3294             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
3295             listObj.remoteFileDataObserver_ = nullptr;
3296             break;
3297         case ALBUM_LISTENER:
3298             CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
3299             mediaType = MEDIA_TYPE_ALBUM;
3300             UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
3301             listObj.albumDataObserver_ = nullptr;
3302             break;
3303         default:
3304             NAPI_ERR_LOG("Invalid Media Type");
3305             return;
3306     }
3307 
3308     if (listObj.cbOffRef_ != nullptr) {
3309         MediaChangeListener listener;
3310         listener.mediaType = mediaType;
3311         listObj.OnChange(listener, listObj.cbOffRef_);
3312     }
3313 }
3314 
UnRegisterNotifyChange(napi_env env,const std::string & uri,napi_ref ref,ChangeListenerNapi & listObj)3315 void MediaLibraryNapi::UnRegisterNotifyChange(napi_env env,
3316     const std::string &uri, napi_ref ref, ChangeListenerNapi &listObj)
3317 {
3318     if (ref != nullptr) {
3319         CheckRef(env, ref, listObj, true, uri);
3320         return;
3321     }
3322     if (listObj.observers_.size() == 0) {
3323         return;
3324     }
3325     std::vector<std::shared_ptr<MediaOnNotifyObserver>> offObservers;
3326     {
3327         lock_guard<mutex> lock(sOnOffMutex_);
3328         for (auto iter = listObj.observers_.begin(); iter != listObj.observers_.end();) {
3329             if (uri.compare((*iter)->uri_) == 0) {
3330                 offObservers.push_back(*iter);
3331                 vector<shared_ptr<MediaOnNotifyObserver>>::iterator tmp = iter;
3332                 iter = listObj.observers_.erase(tmp);
3333             } else {
3334                 iter++;
3335             }
3336         }
3337     }
3338     for (auto obs : offObservers) {
3339         UserFileClient::UnregisterObserverExt(Uri(uri),
3340             static_cast<shared_ptr<DataShare::DataShareObserver>>(obs));
3341     }
3342 }
3343 
JSOffCallback(napi_env env,napi_callback_info info)3344 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
3345 {
3346     MediaLibraryTracer tracer;
3347     tracer.Start("JSOffCallback");
3348     napi_value undefinedResult = nullptr;
3349     napi_get_undefined(env, &undefinedResult);
3350     size_t argc = ARGS_TWO;
3351     napi_value argv[ARGS_TWO] = {nullptr};
3352     napi_value thisVar = nullptr;
3353     GET_JS_ARGS(env, info, argc, argv, thisVar);
3354     NAPI_ASSERT(env, ARGS_ONE <= argc && argc <= ARGS_TWO, "requires one or two parameters");
3355     if (thisVar == nullptr || argv[PARAM0] == nullptr) {
3356         NAPI_ERR_LOG("Failed to retrieve details about the callback");
3357         return undefinedResult;
3358     }
3359     MediaLibraryNapi *obj = nullptr;
3360     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3361     if (status == napi_ok && obj != nullptr) {
3362         napi_valuetype valueType = napi_undefined;
3363         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
3364             return undefinedResult;
3365         }
3366         if (argc == ARGS_TWO) {
3367             auto status = napi_typeof(env, argv[PARAM1], &valueType);
3368             if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
3369                 argc -= 1;
3370             }
3371         }
3372         size_t res = 0;
3373         char buffer[ARG_BUF_SIZE];
3374         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3375             NAPI_ERR_LOG("Failed to get value string utf8 for type");
3376             return undefinedResult;
3377         }
3378         string type = string(buffer);
3379         if (argc == ARGS_TWO) {
3380             if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
3381                 g_listObj == nullptr) {
3382                 return undefinedResult;
3383             }
3384             const int32_t refCount = 1;
3385             napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
3386         }
3387 
3388         tracer.Start("UnregisterChange");
3389         obj->UnregisterChange(env, type, *g_listObj);
3390         tracer.Finish();
3391     }
3392 
3393     return undefinedResult;
3394 }
3395 
UserFileMgrOffCheckArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3396 static napi_value UserFileMgrOffCheckArgs(napi_env env, napi_callback_info info,
3397     unique_ptr<MediaLibraryAsyncContext> &context)
3398 {
3399     napi_value thisVar = nullptr;
3400     context->argc = ARGS_TWO;
3401     GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
3402     NAPI_ASSERT(env, ARGS_ONE <= context->argc && context->argc<= ARGS_TWO, "requires one or two parameters");
3403     if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
3404         return nullptr;
3405     }
3406 
3407     napi_valuetype valueType = napi_undefined;
3408     if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
3409         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3410         return nullptr;
3411     }
3412 
3413     if (context->argc == ARGS_TWO) {
3414         auto status = napi_typeof(env, context->argv[PARAM1], &valueType);
3415         if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
3416             context->argc -= 1;
3417         }
3418     }
3419 
3420     return thisVar;
3421 }
3422 
UserFileMgrOffCallback(napi_env env,napi_callback_info info)3423 napi_value MediaLibraryNapi::UserFileMgrOffCallback(napi_env env, napi_callback_info info)
3424 {
3425     MediaLibraryTracer tracer;
3426     tracer.Start("UserFileMgrOffCallback");
3427     napi_value undefinedResult = nullptr;
3428     napi_get_undefined(env, &undefinedResult);
3429 
3430     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3431     napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
3432     MediaLibraryNapi *obj = nullptr;
3433     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3434     if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
3435         return undefinedResult;
3436     }
3437     size_t res = 0;
3438     char buffer[ARG_BUF_SIZE];
3439     if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3440         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3441         return undefinedResult;
3442     }
3443 
3444     string uri = string(buffer);
3445     napi_valuetype valueType = napi_undefined;
3446     if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
3447         if (asyncContext->argc == ARGS_TWO) {
3448             if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3449                 return undefinedResult;
3450             }
3451             const int32_t refCount = 1;
3452             napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
3453         }
3454         obj->UnregisterChange(env, uri, *g_listObj);
3455         return undefinedResult;
3456     }
3457     napi_ref cbOffRef = nullptr;
3458     if (asyncContext->argc == ARGS_TWO) {
3459         if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3460             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3461             return undefinedResult;
3462         }
3463         const int32_t refCount = 1;
3464         napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
3465     }
3466     tracer.Start("UnRegisterNotifyChange");
3467     obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
3468     return undefinedResult;
3469 }
3470 
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3471 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
3472                                       MediaLibraryAsyncContext *context)
3473 {
3474     MediaLibraryTracer tracer;
3475     tracer.Start("JSReleaseCompleteCallback");
3476 
3477     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3478 
3479     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3480     jsContext->status = false;
3481     napi_create_int32(env, E_SUCCESS, &jsContext->data);
3482     jsContext->status = true;
3483     napi_get_undefined(env, &jsContext->error);
3484 
3485     tracer.Finish();
3486     MediaLibraryNapiUtils::InvokeJSAsyncMethodWithoutWork(env, context->deferred, context->callbackRef,
3487         *jsContext);
3488 
3489     delete context;
3490 }
3491 
JSRelease(napi_env env,napi_callback_info info)3492 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
3493 {
3494     napi_status status;
3495     napi_value result = nullptr;
3496     size_t argc = ARGS_ONE;
3497     napi_value argv[ARGS_ONE] = {0};
3498     napi_value thisVar = nullptr;
3499     int32_t refCount = 1;
3500 
3501     MediaLibraryTracer tracer;
3502     tracer.Start("JSRelease");
3503 
3504     GET_JS_ARGS(env, info, argc, argv, thisVar);
3505     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
3506     napi_get_undefined(env, &result);
3507 
3508     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3509     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3510     NAPI_ASSERT(env, status == napi_ok && asyncContext->objectInfo != nullptr, "Failed to get object info");
3511 
3512     if (argc == PARAM1) {
3513         napi_valuetype valueType = napi_undefined;
3514         napi_typeof(env, argv[PARAM0], &valueType);
3515         if (valueType == napi_function) {
3516             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
3517         }
3518     }
3519     CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3520     NAPI_CALL(env, napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
3521     asyncContext->objectInfo = nullptr;
3522     NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3523     MediaLibraryAsyncContext *context = asyncContext.get();
3524     std::function<void()> task = [env, status, context]() {
3525         JSReleaseCompleteCallback(env, status, context);
3526     };
3527 
3528     status = napi_send_event(env, task, napi_eprio_immediate);
3529     if (status != napi_ok) {
3530         napi_get_undefined(env, &result);
3531     } else {
3532         napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
3533         asyncContext.release();
3534     }
3535 
3536     return result;
3537 }
3538 
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)3539 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
3540 {
3541     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3542     if (smartAlbum == nullptr) {
3543         NAPI_ERR_LOG("SmartAlbumAsset is nullptr");
3544         return;
3545     }
3546     if (smartAlbum->GetAlbumCapacity() == 0) {
3547         return;
3548     }
3549     string trashPrefix;
3550     if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
3551         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
3552     } else {
3553         trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
3554     }
3555     MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
3556     context->selectionArgs.emplace_back("0");
3557     context->selectionArgs.emplace_back(to_string(smartAlbum->GetAlbumId()));
3558     DataShare::DataSharePredicates predicates;
3559     predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC LIMIT 0,1 ");
3560     predicates.SetWhereClause(context->selection);
3561     predicates.SetWhereArgs(context->selectionArgs);
3562     vector<string> columns;
3563     Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + ASSETMAP_VIEW_NAME);
3564     int errCode = 0;
3565     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode,
3566         context->userId);
3567     if (resultSet == nullptr) {
3568         NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
3569         return;
3570     }
3571     unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
3572     unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
3573     CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
3574     string coverUri = fileAsset->GetUri();
3575     smartAlbum->SetCoverUri(coverUri);
3576     NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
3577 }
3578 
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)3579 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
3580     MediaLibraryAsyncContext *context)
3581 {
3582     CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
3583     smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
3584     smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
3585         TYPE_STRING)));
3586     smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUMASSETS_ALBUMCAPACITY,
3587         resultSet, TYPE_INT32)));
3588     MediaFileUri fileUri(MEDIA_TYPE_SMARTALBUM, to_string(smartAlbumData->GetAlbumId()), context->networkId,
3589         MEDIA_API_VERSION_DEFAULT);
3590     smartAlbumData->SetAlbumUri(fileUri.ToString());
3591     smartAlbumData->SetDescription(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_DESCRIPTION, resultSet,
3592         TYPE_STRING)));
3593     smartAlbumData->SetExpiredTime(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_EXPIRED_TIME, resultSet,
3594         TYPE_INT32)));
3595     smartAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_COVER_URI, resultSet,
3596         TYPE_STRING)));
3597     smartAlbumData->SetResultNapiType(context->resultNapiType);
3598 }
3599 
3600 #ifndef MEDIALIBRARY_COMPATIBILITY
GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3601 static void GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3602 {
3603     MediaLibraryTracer tracer;
3604     tracer.Start("GetAllSmartAlbumResultDataExecute");
3605 
3606     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3607     NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
3608 
3609     if (context->privateAlbumType == TYPE_TRASH) {
3610         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
3611         NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
3612     }
3613     if (context->privateAlbumType == TYPE_FAVORITE) {
3614         context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
3615         NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
3616     }
3617 
3618     vector<string> columns;
3619     string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3620     if (!context->networkId.empty()) {
3621         uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
3622             "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3623     }
3624     Uri uri(uriStr);
3625     int errCode = 0;
3626     auto resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode,
3627         context->userId);
3628     if (resultSet == nullptr) {
3629         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
3630         context->error = E_PERMISSION_DENIED;
3631         return;
3632     }
3633 
3634     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
3635         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
3636         context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
3637         context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
3638         context->fetchSmartAlbumResult->SetResultNapiType(context->resultNapiType);
3639         return;
3640     }
3641     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3642         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3643         SetSmartAlbumData(albumData.get(), resultSet, context);
3644         if (albumData->GetCoverUri().empty()) {
3645             SetSmartAlbumCoverUri(context, albumData);
3646         }
3647         context->privateSmartAlbumNativeArray.push_back(move(albumData));
3648     }
3649 }
3650 
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3651 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3652     unique_ptr<JSAsyncContextOutput> &jsContext)
3653 {
3654     if (context->smartAlbumData != nullptr) {
3655         NAPI_ERR_LOG("context->smartAlbumData != nullptr");
3656         jsContext->status = true;
3657         napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3658         napi_get_undefined(env, &jsContext->error);
3659         jsContext->data = albumNapiObj;
3660     } else if (!context->privateSmartAlbumNativeArray.empty()) {
3661         jsContext->status = true;
3662         napi_value albumArray = nullptr;
3663         napi_create_array(env, &albumArray);
3664         for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
3665             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3666                 context->privateSmartAlbumNativeArray[i]);
3667             napi_set_element(env, albumArray, i, albumNapiObj);
3668         }
3669         napi_get_undefined(env, &jsContext->error);
3670         jsContext->data = albumArray;
3671     } else {
3672         NAPI_ERR_LOG("No fetch file result found!");
3673         napi_get_undefined(env, &jsContext->data);
3674         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3675             "Failed to obtain Fetch File Result");
3676     }
3677 }
3678 
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3679 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3680     unique_ptr<JSAsyncContextOutput> &jsContext)
3681 {
3682     if (context->fetchSmartAlbumResult->GetCount() < 0) {
3683         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
3684             "find no data by options");
3685     } else {
3686         napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
3687         if (fileResult == nullptr) {
3688             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3689                 "Failed to create js object for Fetch SmartAlbum Result");
3690         } else {
3691             jsContext->data = fileResult;
3692             jsContext->status = true;
3693             napi_get_undefined(env, &jsContext->error);
3694         }
3695     }
3696 }
3697 
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3698 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3699     unique_ptr<JSAsyncContextOutput> &jsContext)
3700 {
3701     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
3702         MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
3703     } else {
3704         UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
3705     }
3706 }
3707 
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)3708 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
3709 {
3710     MediaLibraryTracer tracer;
3711     tracer.Start("GetPrivateAlbumCallbackComplete");
3712 
3713     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3714     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3715     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3716     jsContext->status = false;
3717     napi_get_undefined(env, &jsContext->error);
3718     if (context->error != ERR_DEFAULT) {
3719         napi_get_undefined(env, &jsContext->data);
3720         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3721             "Query for get fileAssets failed");
3722     } else {
3723         SmartAlbumsAsyncResult(env, context, jsContext);
3724     }
3725 
3726     tracer.Finish();
3727     if (context->work != nullptr) {
3728         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3729                                                    context->work, *jsContext);
3730     }
3731     delete context;
3732 }
3733 #endif
3734 
GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3735 static void GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3736 {
3737     DataShare::DataSharePredicates predicates;
3738     predicates.SetWhereClause(context->selection);
3739     predicates.SetWhereArgs(context->selectionArgs);
3740     vector<string> columns;
3741     Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3742     int errCode = 0;
3743     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
3744     if (resultSet == nullptr) {
3745         NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3746         context->error = ERR_INVALID_OUTPUT;
3747         return;
3748     }
3749     if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
3750         context->smartAlbumData = make_unique<SmartAlbumAsset>();
3751         SetSmartAlbumData(context->smartAlbumData.get(), resultSet, context);
3752         SetSmartAlbumCoverUri(context, context->smartAlbumData);
3753     } else {
3754         NAPI_ERR_LOG("Failed to goToFirstRow");
3755         context->error = ERR_INVALID_OUTPUT;
3756         return;
3757     }
3758 }
3759 
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)3760 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
3761 {
3762     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3763     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3764     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3765     jsContext->status = false;
3766     napi_get_undefined(env, &jsContext->error);
3767     if (context->error != ERR_DEFAULT) {
3768         napi_get_undefined(env, &jsContext->data);
3769         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3770             "Query for get smartAlbums failed");
3771     } else {
3772         if (!context->smartAlbumNativeArray.empty()) {
3773             jsContext->status = true;
3774             napi_value albumArray = nullptr;
3775             napi_create_array(env, &albumArray);
3776             for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
3777                 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3778                     context->smartAlbumNativeArray[i]);
3779                 napi_set_element(env, albumArray, i, albumNapiObj);
3780             }
3781             napi_get_undefined(env, &jsContext->error);
3782             jsContext->data = albumArray;
3783         } else {
3784             NAPI_ERR_LOG("No SmartAlbums result found!");
3785             napi_get_undefined(env, &jsContext->data);
3786             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3787                 "Failed to obtain SmartAlbums Result");
3788         }
3789     }
3790     if (context->work != nullptr) {
3791         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3792                                                    context->work, *jsContext);
3793     }
3794     delete context;
3795 }
3796 
GetJSArgsForGetSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3797 napi_value GetJSArgsForGetSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3798                                      MediaLibraryAsyncContext &asyncContext)
3799 {
3800     napi_value result = nullptr;
3801     auto context = &asyncContext;
3802     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3803     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3804     for (size_t i = 0; i < argc; i++) {
3805         napi_valuetype valueType = napi_undefined;
3806         napi_typeof(env, argv[i], &valueType);
3807         if (i == 0 && valueType == napi_number) {
3808             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3809         } else if ((i == PARAM1) && valueType == napi_function) {
3810             napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3811             break;
3812         } else {
3813             NAPI_ASSERT(env, false, "type mismatch");
3814         }
3815     }
3816     if (context->parentSmartAlbumId < 0) {
3817         NAPI_ASSERT(env, false, "type mismatch");
3818     }
3819     napi_get_boolean(env, true, &result);
3820     return result;
3821 }
3822 
GetSmartAlbumsResultDataExecute(napi_env env,void * data)3823 static void GetSmartAlbumsResultDataExecute(napi_env env, void *data)
3824 {
3825     auto context = static_cast<MediaLibraryAsyncContext *>(data);
3826     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3827     if (context->parentSmartAlbumId < 0) {
3828         context->error = ERR_INVALID_OUTPUT;
3829         NAPI_ERR_LOG("ParentSmartAlbumId is invalid");
3830         return;
3831     }
3832     DataShare::DataSharePredicates predicates;
3833     if (context->parentSmartAlbumId == 0) {
3834         predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " ISNULL");
3835     } else {
3836         predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " = ? ");
3837         predicates.SetWhereArgs({ to_string(context->parentSmartAlbumId) });
3838     }
3839     vector<string> columns;
3840     Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3841     int errCode = 0;
3842     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
3843     if (resultSet == nullptr) {
3844         NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3845         context->error = ERR_INVALID_OUTPUT;
3846         return;
3847     }
3848     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3849         unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3850         SetSmartAlbumData(albumData.get(), resultSet, context);
3851         if (albumData->GetCoverUri().empty()) {
3852             SetSmartAlbumCoverUri(context, albumData);
3853         }
3854         context->smartAlbumNativeArray.push_back(move(albumData));
3855     }
3856 }
3857 
JSGetSmartAlbums(napi_env env,napi_callback_info info)3858 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
3859 {
3860     napi_status status;
3861     napi_value result = nullptr;
3862     size_t argc = ARGS_TWO;
3863     napi_value argv[ARGS_TWO] = {0};
3864     napi_value thisVar = nullptr;
3865 
3866     GET_JS_ARGS(env, info, argc, argv, thisVar);
3867     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3868     napi_get_undefined(env, &result);
3869     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3870     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3871     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
3872     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3873     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3874         result = GetJSArgsForGetSmartAlbum(env, argc, argv, *asyncContext);
3875         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3876         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3877         SetUserIdFromObjectInfo(asyncContext);
3878         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
3879             GetSmartAlbumsResultDataExecute, SmartAlbumsAsyncCallbackComplete);
3880     }
3881 
3882     return result;
3883 }
3884 
CheckAlbumFetchColumns(const vector<string> & fetchColumn)3885 static bool CheckAlbumFetchColumns(const vector<string> &fetchColumn)
3886 {
3887     for (const auto &column : fetchColumn) {
3888         if (!PhotoAlbumColumns::IsPhotoAlbumColumn(column) && column.compare(MEDIA_DATA_DB_URI) != 0) {
3889             return false;
3890         }
3891     }
3892     return true;
3893 }
3894 
AddDefaultPhotoAlbumColumns(vector<string> & fetchColumn)3895 static void AddDefaultPhotoAlbumColumns(vector<string> &fetchColumn)
3896 {
3897     auto columns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
3898     for (const auto &column : fetchColumn) {
3899         if (column.compare(MEDIA_DATA_DB_URI) == 0) {
3900             continue;
3901         }
3902         if (columns.count(column) == 0) {
3903             columns.insert(column);
3904         }
3905     }
3906     fetchColumn.assign(columns.begin(), columns.end());
3907 }
3908 
AddDefaultColumnsForNonAnalysisAlbums(MediaLibraryAsyncContext & context)3909 static void AddDefaultColumnsForNonAnalysisAlbums(MediaLibraryAsyncContext& context)
3910 {
3911     if (!context.isAnalysisAlbum) {
3912         context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
3913         context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
3914         context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_LPATH);
3915         context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_DATE_ADDED);
3916     }
3917 }
3918 
3919 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatGetPrivateAlbumExecute(napi_env env,void * data)3920 static void CompatGetPrivateAlbumExecute(napi_env env, void *data)
3921 {
3922     MediaLibraryTracer tracer;
3923     tracer.Start("CompatGetPrivateAlbumExecute");
3924 
3925     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3926     string queryUri = URI_QUERY_PHOTO_ALBUM;
3927     Uri uri(queryUri);
3928     int err = 0;
3929     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, err,
3930         context->userId);
3931     if (resultSet == nullptr) {
3932         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", err);
3933         context->SaveError(err);
3934         return;
3935     }
3936     err = resultSet->GoToFirstRow();
3937     if (err != NativeRdb::E_OK) {
3938         context->SaveError(E_HAS_DB_ERROR);
3939         return;
3940     }
3941 
3942     auto albumData = make_unique<AlbumAsset>();
3943     SetAlbumData(albumData.get(), resultSet, "");
3944     CompatSetAlbumCoverUri(context, albumData);
3945     context->albumNativeArray.push_back(move(albumData));
3946 }
3947 
CompatGetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3948 static void CompatGetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
3949     unique_ptr<JSAsyncContextOutput> &jsContext)
3950 {
3951     jsContext->status = true;
3952     napi_value albumArray = nullptr;
3953     CHECK_ARGS_RET_VOID(env, napi_create_array(env, &albumArray), JS_INNER_FAIL);
3954     for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
3955         napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
3956         CHECK_ARGS_RET_VOID(env, napi_set_element(env, albumArray, i, albumNapiObj), JS_INNER_FAIL);
3957     }
3958     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3959     jsContext->data = albumArray;
3960 }
3961 
CompatGetPrivateAlbumComplete(napi_env env,napi_status status,void * data)3962 static void CompatGetPrivateAlbumComplete(napi_env env, napi_status status, void *data)
3963 {
3964     MediaLibraryTracer tracer;
3965     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
3966 
3967     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3968     auto jsContext = make_unique<JSAsyncContextOutput>();
3969     jsContext->status = false;
3970 
3971     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3972     if (context->error != ERR_DEFAULT || context->albumNativeArray.empty()) {
3973         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3974         context->HandleError(env, jsContext->error);
3975     } else {
3976         CompatGetPhotoAlbumQueryResult(env, context, jsContext);
3977     }
3978 
3979     tracer.Finish();
3980     if (context->work != nullptr) {
3981         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3982                                                    context->work, *jsContext);
3983     }
3984     delete context;
3985 }
3986 
ParseArgsGetPrivateAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3987 napi_value ParseArgsGetPrivateAlbum(napi_env env, napi_callback_info info,
3988     unique_ptr<MediaLibraryAsyncContext> &context)
3989 {
3990     int32_t privateAlbumType = -1;
3991     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, context, privateAlbumType),
3992         JS_ERR_PARAMETER_INVALID);
3993     if (privateAlbumType != PrivateAlbumType::TYPE_FAVORITE && privateAlbumType != PrivateAlbumType::TYPE_TRASH) {
3994         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3995         return nullptr;
3996     }
3997 
3998     PhotoAlbumSubType subType = ANY;
3999     switch (privateAlbumType) {
4000         case PrivateAlbumType::TYPE_FAVORITE: {
4001             subType = PhotoAlbumSubType::FAVORITE;
4002             break;
4003         }
4004         case PrivateAlbumType::TYPE_TRASH: {
4005             subType = PhotoAlbumSubType::TRASH;
4006             break;
4007         }
4008         default: {
4009             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
4010             return nullptr;
4011         }
4012     }
4013     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
4014     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subType));
4015     CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
4016     AddDefaultPhotoAlbumColumns(context->fetchColumn);
4017 
4018     napi_value result = nullptr;
4019     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4020     return result;
4021 }
4022 
CompatGetPrivateAlbum(napi_env env,napi_callback_info info)4023 napi_value CompatGetPrivateAlbum(napi_env env, napi_callback_info info)
4024 {
4025     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
4026     CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
4027 
4028     SetUserIdFromObjectInfo(asyncContext);
4029     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CompatGetPrivateAlbum",
4030         CompatGetPrivateAlbumExecute, CompatGetPrivateAlbumComplete);
4031 }
4032 #endif // MEDIALIBRARY_COMPATIBILITY
4033 
JSGetPrivateAlbum(napi_env env,napi_callback_info info)4034 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
4035 {
4036 #ifdef MEDIALIBRARY_COMPATIBILITY
4037     return CompatGetPrivateAlbum(env, info);
4038 #else
4039     napi_status status;
4040     napi_value result = nullptr;
4041     size_t argc = ARGS_TWO;
4042     napi_value argv[ARGS_TWO] = {0};
4043     napi_value thisVar = nullptr;
4044     const int32_t refCount = 1;
4045 
4046     GET_JS_ARGS(env, info, argc, argv, thisVar);
4047     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
4048     napi_get_undefined(env, &result);
4049     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4050     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
4051     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4052     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4053         for (size_t i = PARAM0; i < argc; i++) {
4054             napi_valuetype valueType = napi_undefined;
4055             napi_typeof(env, argv[i], &valueType);
4056             if (i == PARAM0 && valueType == napi_number) {
4057                 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
4058             } else if (i == PARAM1 && valueType == napi_function) {
4059                 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
4060                 break;
4061             } else {
4062                 NAPI_ASSERT(env, false, "type mismatch");
4063             }
4064         }
4065 
4066         SetUserIdFromObjectInfo(asyncContext);
4067         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
4068             [](napi_env env, void *data) {
4069                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4070                 GetAllSmartAlbumResultDataExecute(context);
4071             }, GetPrivateAlbumCallbackComplete);
4072     }
4073     return result;
4074 #endif
4075 }
4076 
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)4077 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
4078                                         MediaLibraryAsyncContext &asyncContext)
4079 {
4080     const int32_t refCount = 1;
4081     napi_value result = nullptr;
4082     auto context = &asyncContext;
4083     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
4084     size_t res = 0;
4085     char buffer[PATH_MAX];
4086     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
4087     for (size_t i = 0; i < argc; i++) {
4088         napi_valuetype valueType = napi_undefined;
4089         napi_typeof(env, argv[i], &valueType);
4090         if (i == 0 && valueType == napi_number) {
4091             napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
4092         } else if (i == PARAM1 && valueType == napi_string) {
4093             napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
4094         } else if (i == PARAM2 && valueType == napi_function) {
4095             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
4096             break;
4097         } else {
4098             NAPI_ASSERT(env, false, "type mismatch");
4099         }
4100     }
4101     if (context->parentSmartAlbumId < 0) {
4102         NAPI_ASSERT(env, false, "type mismatch");
4103     }
4104     string smartName = string(buffer);
4105     if (smartName.empty()) {
4106         NAPI_ASSERT(env, false, "type mismatch");
4107     }
4108     context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
4109     napi_get_boolean(env, true, &result);
4110     return result;
4111 }
4112 
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4113 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
4114                                                MediaLibraryAsyncContext *context)
4115 {
4116     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4117     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4118     jsContext->status = false;
4119     if (context->error == ERR_DEFAULT) {
4120         if (context->smartAlbumData == nullptr) {
4121             NAPI_ERR_LOG("No albums found");
4122             napi_get_undefined(env, &jsContext->data);
4123             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4124                 "No albums found");
4125         } else {
4126             jsContext->status = true;
4127             napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
4128             jsContext->data = albumNapiObj;
4129             napi_get_undefined(env, &jsContext->error);
4130         }
4131     } else {
4132         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4133             "File asset creation failed");
4134         napi_get_undefined(env, &jsContext->data);
4135     }
4136     if (context->work != nullptr) {
4137         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4138                                                    context->work, *jsContext);
4139     }
4140     delete context;
4141 }
4142 
CreateSmartAlbumExecute(MediaLibraryAsyncContext * context)4143 static void CreateSmartAlbumExecute(MediaLibraryAsyncContext *context)
4144 {
4145     context->valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
4146     Uri CreateSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMOPRN + "/" +
4147                             MEDIA_SMARTALBUMOPRN_CREATEALBUM);
4148     int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
4149     if (retVal < 0) {
4150         context->SaveError(retVal);
4151         NAPI_ERR_LOG("CreateSmartAlbum failed, retVal = %{private}d", retVal);
4152         return;
4153     }
4154     context->selection = SMARTALBUM_DB_ID + " = ?";
4155     context->selectionArgs = { to_string(retVal) };
4156     GetSmartAlbumResultDataExecute(context);
4157     // If parentSmartAlbumId == 0 do not need to add to smart map
4158     if (context->parentSmartAlbumId != 0) {
4159         DataShare::DataShareValuesBucket valuesBucket;
4160         valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
4161         valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ALBUM_ID, retVal);
4162         NAPI_DEBUG_LOG("CreateSmartAlbumExecute retVal = %{public}d, parentSmartAlbumId = %{public}d",
4163             retVal, context->parentSmartAlbumId);
4164         Uri addAsseturi(MEDIALIBRARY_DATA_URI +
4165             "/" + MEDIA_SMARTALBUMMAPOPRN + "/" + MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM);
4166         int32_t changedRows = UserFileClient::Insert(addAsseturi, valuesBucket);
4167         context->SaveError(changedRows);
4168     }
4169 }
4170 
JSCreateSmartAlbum(napi_env env,napi_callback_info info)4171 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
4172 {
4173     napi_status status;
4174     napi_value result = nullptr;
4175     size_t argc = ARGS_THREE;
4176     napi_value argv[ARGS_THREE] = {0};
4177     napi_value thisVar = nullptr;
4178     napi_value resource = nullptr;
4179 
4180     GET_JS_ARGS(env, info, argc, argv, thisVar);
4181     NAPI_ASSERT(env, (argc == ARGS_TWO || argc == ARGS_THREE), "requires 3 parameters maximum");
4182     napi_get_undefined(env, &result);
4183     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4184     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
4185     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4186     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4187         result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
4188         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
4189         SetUserIdFromObjectInfo(asyncContext);
4190         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4191         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
4192         status = napi_create_async_work(
4193             env, nullptr, resource, [](napi_env env, void *data) {
4194                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4195                 CreateSmartAlbumExecute(context);
4196             },
4197             reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
4198             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4199         if (status != napi_ok) {
4200             napi_get_undefined(env, &result);
4201         } else {
4202             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4203             asyncContext.release();
4204         }
4205     }
4206     return result;
4207 }
4208 
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)4209 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
4210 {
4211     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4212     if (context->smartAlbumId == TYPE_TRASH) {
4213         NAPI_ERR_LOG("Trash smartalbum can not be deleted");
4214         context->error = E_TRASHALBUM_CAN_NOT_DELETE;
4215         return;
4216     }
4217     if (context->smartAlbumId == TYPE_FAVORITE) {
4218         NAPI_ERR_LOG("Facorite smartalbum can not be deleted");
4219         context->error = E_FAVORITEALBUM_CAN_NOT_DELETE;
4220         return;
4221     }
4222     DataShare::DataShareValuesBucket valuesBucket;
4223     valuesBucket.Put(SMARTALBUM_DB_ID, context->smartAlbumId);
4224     Uri DeleteSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" +
4225         MEDIA_SMARTALBUMOPRN + "/" + MEDIA_SMARTALBUMOPRN_DELETEALBUM);
4226     int retVal = UserFileClient::Insert(DeleteSmartAlbumUri, valuesBucket);
4227     NAPI_DEBUG_LOG("JSDeleteSmartAlbumExecute retVal = %{private}d, smartAlbumId = %{private}d",
4228         retVal, context->smartAlbumId);
4229     if (retVal < 0) {
4230         context->SaveError(retVal);
4231     } else {
4232         context->retVal = retVal;
4233     }
4234 }
4235 
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)4236 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
4237                                         MediaLibraryAsyncContext &asyncContext)
4238 {
4239     napi_value result = nullptr;
4240     auto context = &asyncContext;
4241     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
4242     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
4243     for (size_t i = 0; i < argc; i++) {
4244         napi_valuetype valueType = napi_undefined;
4245         napi_typeof(env, argv[i], &valueType);
4246         if (i == 0 && valueType == napi_number) {
4247             napi_get_value_int32(env, argv[i], &context->smartAlbumId);
4248         } else if (i == PARAM1 && valueType == napi_function) {
4249             napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
4250             break;
4251         } else {
4252             NAPI_ASSERT(env, false, "type mismatch");
4253         }
4254     }
4255     if (context->smartAlbumId < 0) {
4256         NAPI_ASSERT(env, false, "type mismatch");
4257     }
4258     napi_get_boolean(env, true, &result);
4259     return result;
4260 }
4261 
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4262 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
4263                                                MediaLibraryAsyncContext *context)
4264 {
4265     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4266     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4267     jsContext->status = false;
4268     if (context->error == ERR_DEFAULT) {
4269         napi_create_int32(env, context->retVal, &jsContext->data);
4270         napi_get_undefined(env, &jsContext->error);
4271         jsContext->status = true;
4272     } else {
4273         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4274             "UserFileClient is invalid");
4275         napi_get_undefined(env, &jsContext->data);
4276     }
4277     if (context->work != nullptr) {
4278         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4279                                                    context->work, *jsContext);
4280     }
4281     delete context;
4282 }
4283 
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)4284 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
4285 {
4286     napi_status status;
4287     napi_value result = nullptr;
4288     size_t argc = ARGS_TWO;
4289     napi_value argv[ARGS_TWO] = {0};
4290     napi_value thisVar = nullptr;
4291     napi_value resource = nullptr;
4292 
4293     GET_JS_ARGS(env, info, argc, argv, thisVar);
4294     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
4295     napi_get_undefined(env, &result);
4296     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4297     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4298     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4299         result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
4300         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
4301         SetUserIdFromObjectInfo(asyncContext);
4302         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4303         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
4304         status = napi_create_async_work(
4305             env, nullptr, resource, [](napi_env env, void *data) {
4306                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4307                 JSDeleteSmartAlbumExecute(context);
4308             },
4309             reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
4310             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4311         if (status != napi_ok) {
4312             napi_get_undefined(env, &result);
4313         } else {
4314             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4315             asyncContext.release();
4316         }
4317     }
4318     return result;
4319 }
4320 
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)4321 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
4322 {
4323     napi_value value;
4324     napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
4325     if (status != napi_ok) {
4326         NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
4327         return status;
4328     }
4329     status = napi_set_named_property(env, result, fieldStr, value);
4330     if (status != napi_ok) {
4331         NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
4332     }
4333     return status;
4334 }
4335 
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)4336 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
4337 {
4338     napi_value value = nullptr;
4339     napi_status status = napi_get_boolean(env, boolvalue, &value);
4340     if (status != napi_ok) {
4341         NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
4342         return status;
4343     }
4344     status = napi_set_named_property(env, result, fieldStr, value);
4345     if (status != napi_ok) {
4346         NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
4347     }
4348     return status;
4349 }
4350 
PeerInfoToJsArray(const napi_env & env,const vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)4351 static void PeerInfoToJsArray(const napi_env &env, const vector<unique_ptr<PeerInfo>> &vecPeerInfo,
4352     const int32_t idx, napi_value &arrayResult)
4353 {
4354     if (idx >= (int32_t) vecPeerInfo.size()) {
4355         return;
4356     }
4357     auto info = vecPeerInfo[idx].get();
4358     if (info == nullptr) {
4359         return;
4360     }
4361     napi_value result = nullptr;
4362     napi_create_object(env, &result);
4363     SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
4364     SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
4365     SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
4366     SetValueBool(env, "isOnline", info->isOnline, result);
4367 
4368     napi_status status = napi_set_element(env, arrayResult, idx, result);
4369     if (status != napi_ok) {
4370         NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
4371     }
4372 }
4373 
QueryActivePeer(int & errCode,MediaLibraryAsyncContext * context,string & uriType)4374 shared_ptr<DataShare::DataShareResultSet> QueryActivePeer(int &errCode,
4375     MediaLibraryAsyncContext *context, string &uriType)
4376 {
4377     vector<string> columns;
4378     DataShare::DataSharePredicates predicates;
4379     Uri uri(uriType);
4380     if (uriType == MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE) {
4381         string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
4382         predicates.SetWhereClause(strQueryCondition);
4383     } else if (uriType == MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE) {
4384         predicates.SetWhereClause(context->selection);
4385     }
4386     predicates.SetWhereArgs(context->selectionArgs);
4387     return UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
4388 }
4389 
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4390 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
4391     MediaLibraryAsyncContext *context)
4392 {
4393     napi_value jsPeerInfoArray = nullptr;
4394     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4395     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4396     jsContext->status = false;
4397     napi_get_undefined(env, &jsContext->data);
4398     string uriType = MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE;
4399     int errCode = 0;
4400     shared_ptr<DataShare::DataShareResultSet> resultSet = QueryActivePeer(errCode, context, uriType);
4401     if (resultSet == nullptr) {
4402         NAPI_ERR_LOG("JSGetActivePeers resultSet is null, errCode is %{public}d", errCode);
4403         delete context;
4404         return;
4405     }
4406 
4407     vector<unique_ptr<PeerInfo>> peerInfoArray;
4408     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
4409         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
4410         if (peerInfo != nullptr) {
4411             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
4412                 TYPE_STRING));
4413             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
4414                 TYPE_STRING));
4415             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
4416                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
4417             peerInfo->isOnline = true;
4418             peerInfoArray.push_back(move(peerInfo));
4419         }
4420     }
4421 
4422     if (napi_create_array(env, &jsPeerInfoArray) == napi_ok) {
4423         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
4424             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
4425         }
4426 
4427         jsContext->data = jsPeerInfoArray;
4428         napi_get_undefined(env, &jsContext->error);
4429         jsContext->status = true;
4430     }
4431 
4432     if (context->work != nullptr) {
4433         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4434                                                    context->work, *jsContext);
4435     }
4436 
4437     delete context;
4438 }
4439 
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4440 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
4441     MediaLibraryAsyncContext *context)
4442 {
4443     napi_value jsPeerInfoArray = nullptr;
4444     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4445     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4446     jsContext->status = false;
4447     napi_get_undefined(env, &jsContext->data);
4448     string uriType = MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE;
4449     int errCode = 0;
4450     shared_ptr<DataShare::DataShareResultSet> resultSet = QueryActivePeer(errCode, context, uriType);
4451     if (resultSet == nullptr) {
4452         NAPI_ERR_LOG("JSGetAllPeers resultSet is null, errCode is %{public}d", errCode);
4453         delete context;
4454         return;
4455     }
4456 
4457     vector<unique_ptr<PeerInfo>> peerInfoArray;
4458     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
4459         unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
4460         if (peerInfo != nullptr) {
4461             peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
4462                 TYPE_STRING));
4463             peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
4464                 TYPE_STRING));
4465             peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
4466                 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
4467             peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
4468                 TYPE_INT32)) == 0);
4469             peerInfoArray.push_back(move(peerInfo));
4470         }
4471     }
4472 
4473     if (napi_create_array(env, &jsPeerInfoArray) == napi_ok) {
4474         for (size_t i = 0; i < peerInfoArray.size(); ++i) {
4475             PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
4476         }
4477 
4478         jsContext->data = jsPeerInfoArray;
4479         napi_get_undefined(env, &jsContext->error);
4480         jsContext->status = true;
4481     }
4482 
4483     if (context->work != nullptr) {
4484         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4485                                                    context->work, *jsContext);
4486     }
4487     delete context;
4488 }
4489 
JSGetActivePeers(napi_env env,napi_callback_info info)4490 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
4491 {
4492     napi_status status;
4493     napi_value result = nullptr;
4494     const int32_t refCount = 1;
4495     size_t argc = ARGS_ONE;
4496     napi_value argv[ARGS_ONE] = {0};
4497     napi_value thisVar = nullptr;
4498 
4499     MediaLibraryTracer tracer;
4500     tracer.Start("JSGetActivePeers");
4501 
4502     GET_JS_ARGS(env, info, argc, argv, thisVar);
4503     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
4504     napi_get_undefined(env, &result);
4505 
4506     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4507     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4508     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4509         if (argc == ARGS_ONE) {
4510             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
4511         }
4512         SetUserIdFromObjectInfo(asyncContext);
4513 
4514         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4515 
4516         NAPI_CALL(env, napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
4517         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4518         MediaLibraryAsyncContext *context = asyncContext.get();
4519         std::function<void()> task = [env, status, context]() {
4520             JSGetActivePeersCompleteCallback(env, status, context);
4521         };
4522 
4523         status = napi_send_event(env, task, napi_eprio_immediate);
4524         if (status != napi_ok) {
4525             napi_get_undefined(env, &result);
4526         } else {
4527             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4528             asyncContext.release();
4529         }
4530     }
4531 
4532     return result;
4533 }
4534 
JSGetAllPeers(napi_env env,napi_callback_info info)4535 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
4536 {
4537     napi_status status;
4538     napi_value result = nullptr;
4539     const int32_t refCount = 1;
4540     size_t argc = ARGS_ONE;
4541     napi_value argv[ARGS_ONE] = {0};
4542     napi_value thisVar = nullptr;
4543 
4544     MediaLibraryTracer tracer;
4545     tracer.Start("JSGetAllPeers");
4546 
4547     GET_JS_ARGS(env, info, argc, argv, thisVar);
4548     NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
4549     napi_get_undefined(env, &result);
4550 
4551     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4552     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4553     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4554         if (argc == ARGS_ONE) {
4555             GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
4556         }
4557         SetUserIdFromObjectInfo(asyncContext);
4558 
4559         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4560         MediaLibraryAsyncContext *context = asyncContext.get();
4561         std::function<void()> task = [env, status, context]() {
4562             JSGetAllPeersCompleteCallback(env, status, context);
4563         };
4564         status = napi_send_event(env, task, napi_eprio_immediate);
4565         if (status != napi_ok) {
4566             napi_get_undefined(env, &result);
4567         } else {
4568             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4569             asyncContext.release();
4570         }
4571     }
4572 
4573     return result;
4574 }
4575 
CloseAsset(MediaLibraryAsyncContext * context,string uri)4576 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
4577 {
4578     string abilityUri = MEDIALIBRARY_DATA_URI;
4579     Uri closeAssetUri(URI_CLOSE_FILE);
4580     context->valuesBucket.Clear();
4581     context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
4582     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
4583     NAPI_DEBUG_LOG("File close asset %{public}d", ret);
4584     if (ret != E_SUCCESS) {
4585         context->error = ret;
4586         NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
4587     }
4588     return ret;
4589 }
4590 
GetStoreMediaAssetUri(MediaLibraryAsyncContext * context,string & uri)4591 static void GetStoreMediaAssetUri(MediaLibraryAsyncContext *context, string &uri)
4592 {
4593     bool isValid = false;
4594     string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
4595     if (relativePath.find(CAMERA_DIR_VALUES) == 0 ||
4596         relativePath.find(VIDEO_DIR_VALUES) == 0 ||
4597         relativePath.find(PIC_DIR_VALUES) == 0) {
4598         uri = URI_CREATE_PHOTO;
4599     } else if (relativePath.find(AUDIO_DIR_VALUES) == 0) {
4600         uri = URI_CREATE_AUDIO;
4601     } else {
4602         uri = URI_CREATE_FILE;
4603     }
4604 }
4605 
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)4606 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
4607 {
4608     string realPath;
4609     if (!PathToRealPath(context->storeMediaSrc, realPath)) {
4610         NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
4611         context->error = JS_ERR_NO_SUCH_FILE;
4612         return;
4613     }
4614     context->error = JS_E_RELATIVEPATH;
4615     int32_t srcFd = open(realPath.c_str(), O_RDWR);
4616     CHECK_IF_EQUAL(srcFd != -1, "src path open fail, %{public}d", errno);
4617     struct stat statSrc;
4618     if (fstat(srcFd, &statSrc) == -1) {
4619         close(srcFd);
4620         NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
4621         return;
4622     }
4623     string uriString;
4624     GetStoreMediaAssetUri(context, uriString);
4625     Uri createFileUri(uriString);
4626     int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
4627     if (index < 0) {
4628         close(srcFd);
4629         NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
4630         return;
4631     }
4632     SetFileAssetByIdV9(index, "", context);
4633     if (context->fileAsset == nullptr) {
4634         close(srcFd);
4635         NAPI_ERR_LOG("JSGetStoreMediaAssetExecute: context->fileAsset is nullptr");
4636         return;
4637     }
4638     LogMedialibraryAPI(context->fileAsset->GetUri());
4639     Uri openFileUri(context->fileAsset->GetUri());
4640     int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE, context->userId);
4641     if (destFd < 0) {
4642         context->error = destFd;
4643         NAPI_DEBUG_LOG("File open asset failed");
4644         close(srcFd);
4645         return;
4646     }
4647     if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
4648         close(srcFd);
4649         close(destFd);
4650         CloseAsset(context, context->fileAsset->GetUri());
4651         NAPI_ERR_LOG("copy file fail %{public}d ", errno);
4652         return;
4653     }
4654     close(srcFd);
4655     close(destFd);
4656     CloseAsset(context, context->fileAsset->GetUri());
4657     context->error = ERR_DEFAULT;
4658 }
4659 
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4660 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
4661     MediaLibraryAsyncContext *context)
4662 {
4663     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4664     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4665     CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
4666     jsContext->status = false;
4667     napi_get_undefined(env, &jsContext->data);
4668     if (context->error != ERR_DEFAULT) {
4669         NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
4670         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4671             "storeMediaAsset fail");
4672     } else {
4673         napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4674         jsContext->status = true;
4675         napi_get_undefined(env, &jsContext->error);
4676     }
4677 
4678     if (context->work != nullptr) {
4679         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4680                                                    context->work, *jsContext);
4681     }
4682     delete context;
4683 }
4684 
ConvertMediaType(const string & mimeType)4685 static int ConvertMediaType(const string &mimeType)
4686 {
4687     string res;
4688     // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
4689     size_t slash = mimeType.find('/');
4690     if (slash != string::npos) {
4691         res = mimeType.substr(0, slash);
4692         if (res.empty()) {
4693             return MediaType::MEDIA_TYPE_FILE;
4694         }
4695     }
4696     if (res == "image") {
4697         return MediaType::MEDIA_TYPE_IMAGE;
4698     } else if (res == "video") {
4699         return MediaType::MEDIA_TYPE_VIDEO;
4700     } else if (res == "audio") {
4701         return MediaType::MEDIA_TYPE_AUDIO;
4702     }
4703     return MediaType::MEDIA_TYPE_FILE;
4704 }
4705 
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)4706 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
4707 {
4708     napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
4709     if (value == nullptr) {
4710         NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
4711         return false;
4712     }
4713     unique_ptr<char[]> tmp;
4714     bool succ;
4715     tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
4716     if (!succ) {
4717         NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
4718         return false;
4719     }
4720     res = string(tmp.get());
4721     return true;
4722 }
4723 
GetDefaultDirectory(int mediaType)4724 static string GetDefaultDirectory(int mediaType)
4725 {
4726     string relativePath;
4727     if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
4728         relativePath = "Pictures/";
4729     } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
4730         relativePath = "Videos/";
4731     } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
4732         relativePath = "Audios/";
4733     } else {
4734         relativePath = DOCS_PATH + DOC_DIR_VALUES;
4735     }
4736     return relativePath;
4737 }
4738 
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)4739 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
4740     MediaLibraryAsyncContext &asyncContext)
4741 {
4742     auto context = &asyncContext;
4743     if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
4744         NAPI_ERR_LOG("param get fail");
4745         return nullptr;
4746     }
4747     string fileName = MediaFileUtils::GetFileName(context->storeMediaSrc);
4748     if (fileName.empty() || (fileName.at(0) == '.')) {
4749         NAPI_ERR_LOG("src file name is not proper");
4750         context->error = JS_E_RELATIVEPATH;
4751         return nullptr;
4752     };
4753     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
4754     string mimeType;
4755     if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
4756         NAPI_ERR_LOG("param get fail");
4757         return nullptr;
4758     }
4759     auto mediaType = ConvertMediaType(mimeType);
4760     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
4761     string relativePath;
4762     if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
4763         NAPI_DEBUG_LOG("optional relativePath param empty");
4764         relativePath = GetDefaultDirectory(mediaType);
4765     }
4766     relativePath = MediaFileUtils::AddDocsToRelativePath(relativePath);
4767     context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
4768     NAPI_DEBUG_LOG("src:%{private}s mime:%{private}s relp:%{private}s filename:%{private}s",
4769         context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
4770     napi_value result = nullptr;
4771     napi_get_undefined(env, &result);
4772     return result;
4773 }
4774 
JSStoreMediaAsset(napi_env env,napi_callback_info info)4775 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
4776 {
4777     size_t argc = ARGS_TWO;
4778     napi_value argv[ARGS_TWO] = {0};
4779     napi_value thisVar = nullptr;
4780     GET_JS_ARGS(env, info, argc, argv, thisVar);
4781     napi_value result = nullptr;
4782     napi_get_undefined(env, &result);
4783     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4784     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4785     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4786     if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
4787         napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
4788         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
4789         if (argc == ARGS_TWO) {
4790             const int32_t refCount = 1;
4791             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4792         }
4793         SetUserIdFromObjectInfo(asyncContext);
4794         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4795         napi_value resource = nullptr;
4796         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
4797         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4798                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4799                 JSGetStoreMediaAssetExecute(context);
4800             },
4801             reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
4802             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4803         if (status != napi_ok) {
4804             napi_get_undefined(env, &result);
4805         } else {
4806             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4807             asyncContext.release();
4808         }
4809     }
4810     return result;
4811 }
4812 
CreateAsyncCallbackInfo(napi_env env)4813 static Ability *CreateAsyncCallbackInfo(napi_env env)
4814 {
4815     if (env == nullptr) {
4816         NAPI_ERR_LOG("env == nullptr.");
4817         return nullptr;
4818     }
4819     napi_status ret;
4820     napi_value global = 0;
4821     const napi_extended_error_info *errorInfo = nullptr;
4822     ret = napi_get_global(env, &global);
4823     if (ret != napi_ok) {
4824         napi_get_last_error_info(env, &errorInfo);
4825         NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
4826     }
4827     napi_value abilityObj = 0;
4828     ret = napi_get_named_property(env, global, "ability", &abilityObj);
4829     if (ret != napi_ok) {
4830         napi_get_last_error_info(env, &errorInfo);
4831         NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
4832     }
4833     Ability *ability = nullptr;
4834     ret = napi_get_value_external(env, abilityObj, (void **)&ability);
4835     if (ret != napi_ok) {
4836         napi_get_last_error_info(env, &errorInfo);
4837         NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
4838     }
4839     return ability;
4840 }
4841 
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4842 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4843 {
4844     uint32_t arraySize = 0;
4845     if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
4846         NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
4847         return nullptr;
4848     }
4849     string uri = "";
4850     for (uint32_t i = 0; i < arraySize; i++) {
4851         napi_value jsValue = nullptr;
4852         if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
4853             NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
4854             return nullptr;
4855         }
4856         unique_ptr<char[]> inputStr;
4857         bool succ;
4858         tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
4859         if (!succ) {
4860             NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
4861             return nullptr;
4862         }
4863         uri += MediaLibraryNapiUtils::TransferUri(string(inputStr.get()));
4864         uri += "?";
4865     }
4866     context.uri = uri.substr(0, uri.length() - 1);
4867     NAPI_DEBUG_LOG("GetImagePreviewArgs res %{private}s", context.uri.c_str());
4868     napi_value res;
4869     napi_get_undefined(env, &res);
4870     return res;
4871 }
4872 
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4873 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4874 {
4875     context.imagePreviewIndex = 0;
4876     napi_valuetype valueType = napi_undefined;
4877     napi_typeof(env, param, &valueType);
4878     if (valueType != napi_number) {
4879         NAPI_ERR_LOG("not napi value");
4880         return nullptr;
4881     }
4882     if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
4883         NAPI_ERR_LOG("get property value fail");
4884     }
4885     NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
4886     napi_value res;
4887     napi_get_undefined(env, &res);
4888     return res;
4889 }
4890 
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)4891 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
4892 {
4893     if (context->ability_ == nullptr) {
4894         NAPI_ERR_LOG("ability_ is not exist");
4895         context->error = ERR_INVALID_OUTPUT;
4896         return;
4897     }
4898     Want want;
4899     want.SetType("image/jpeg");
4900     want.SetAction("ohos.want.action.viewData");
4901     want.SetUri(context->uri);
4902     want.SetParam("viewIndex", context->imagePreviewIndex + 1);
4903     context->error = context->ability_->StartAbility(want);
4904 }
4905 
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4906 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
4907     MediaLibraryAsyncContext *context)
4908 {
4909     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4910     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4911     CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
4912     jsContext->status = true;
4913     napi_get_undefined(env, &jsContext->data);
4914     if (context->error != 0) {
4915         jsContext->status = false;
4916         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4917             "startImagePreview currently fail");
4918     }
4919     if (context->work != nullptr) {
4920         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4921                                                    context->work, *jsContext);
4922     }
4923     delete context;
4924 }
4925 
JSStartImagePreview(napi_env env,napi_callback_info info)4926 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
4927 {
4928     size_t argc = ARGS_THREE;
4929     napi_value argv[ARGS_THREE] = {0};
4930     napi_value thisVar = nullptr;
4931     GET_JS_ARGS(env, info, argc, argv, thisVar);
4932     napi_value result = nullptr;
4933     napi_get_undefined(env, &result);
4934     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4935     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4936     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4937     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4938         napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
4939         CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
4940         GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
4941         asyncContext->ability_ = CreateAsyncCallbackInfo(env);
4942         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
4943         const int32_t refCount = 1;
4944         if (argc == ARGS_THREE) {
4945             GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
4946         } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
4947             GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4948         }
4949         SetUserIdFromObjectInfo(asyncContext);
4950         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4951         napi_value resource = nullptr;
4952         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
4953         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4954                 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4955                 JSStartImagePreviewExecute(context);
4956             },
4957             reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
4958             static_cast<void *>(asyncContext.get()), &asyncContext->work);
4959         if (status != napi_ok) {
4960             napi_get_undefined(env, &result);
4961         } else {
4962             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4963             asyncContext.release();
4964         }
4965     }
4966     return result;
4967 }
4968 
CheckCreateOption(MediaLibraryAsyncContext & context)4969 static napi_status CheckCreateOption(MediaLibraryAsyncContext &context)
4970 {
4971     bool isValid = false;
4972     int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
4973     string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
4974     if (isValid) {
4975         if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
4976             NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
4977             return napi_invalid_arg;
4978         }
4979         if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
4980             NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
4981             return napi_invalid_arg;
4982         } else {
4983             context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
4984         }
4985     }
4986 
4987     return napi_ok;
4988 }
4989 
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4990 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4991 {
4992     for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
4993         string param = iter.first;
4994         bool present = false;
4995         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4996         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4997         if (!present) {
4998             continue;
4999         }
5000         napi_value value;
5001         result = napi_get_named_property(env, arg, param.c_str(), &value);
5002         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5003         napi_valuetype valueType = napi_undefined;
5004         result = napi_typeof(env, value, &valueType);
5005         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5006         if (valueType == napi_number) {
5007             int32_t number = 0;
5008             result = napi_get_value_int32(env, value, &number);
5009             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5010             context.valuesBucket.Put(iter.second, number);
5011         } else if (valueType == napi_boolean) {
5012             bool isTrue = false;
5013             result = napi_get_value_bool(env, value, &isTrue);
5014             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
5015             context.valuesBucket.Put(iter.second, isTrue);
5016         } else if (valueType == napi_string) {
5017             char buffer[ARG_BUF_SIZE];
5018             size_t res = 0;
5019             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5020             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5021             context.valuesBucket.Put(iter.second, string(buffer));
5022         } else if (valueType == napi_undefined || valueType == napi_null) {
5023             continue;
5024         } else {
5025             NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
5026             return napi_invalid_arg;
5027         }
5028     }
5029 
5030     return CheckCreateOption(context);
5031 }
5032 
ParseCreateOptions(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)5033 static napi_status ParseCreateOptions(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
5034 {
5035     for (const auto &iter : CREATE_OPTIONS_PARAM) {
5036         string param = iter.first;
5037         bool present = false;
5038         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
5039         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
5040         if (!present) {
5041             continue;
5042         }
5043         napi_value value;
5044         result = napi_get_named_property(env, arg, param.c_str(), &value);
5045         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5046         napi_valuetype valueType = napi_undefined;
5047         result = napi_typeof(env, value, &valueType);
5048         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5049         if (valueType == napi_number) {
5050             int32_t number = 0;
5051             result = napi_get_value_int32(env, value, &number);
5052             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5053             context.valuesBucket.Put(iter.second, number);
5054         } else if (valueType == napi_boolean) {
5055             bool isTrue = false;
5056             result = napi_get_value_bool(env, value, &isTrue);
5057             CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
5058             context.valuesBucket.Put(iter.second, isTrue);
5059         } else if (valueType == napi_string) {
5060             char buffer[ARG_BUF_SIZE];
5061             size_t res = 0;
5062             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5063             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5064             context.valuesBucket.Put(iter.second, string(buffer));
5065         } else if (valueType == napi_undefined || valueType == napi_null) {
5066             continue;
5067         } else {
5068             NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
5069                 static_cast<int>(valueType));
5070             return napi_invalid_arg;
5071         }
5072     }
5073 
5074     return napi_ok;
5075 }
5076 
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5077 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
5078     unique_ptr<MediaLibraryAsyncContext> &context)
5079 {
5080     /* Parse the first argument into displayName */
5081     napi_valuetype valueType;
5082     MediaType mediaType;
5083     string displayName;
5084     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
5085         napi_ok, "Failed to get displayName");
5086     mediaType = MediaFileUtils::GetMediaType(displayName);
5087     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
5088     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
5089 
5090     /* Parse the second argument into albumUri if exists */
5091     string albumUri;
5092     if ((context->argc >= ARGS_TWO)) {
5093         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
5094         if (valueType == napi_string) {
5095             if (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok) {
5096                 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
5097             }
5098         } else if (valueType == napi_object) {
5099             NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
5100                 "Parse asset create option failed");
5101         }
5102     }
5103 
5104     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5105     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
5106 
5107     napi_value result = nullptr;
5108     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5109     return result;
5110 }
5111 
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5112 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
5113     unique_ptr<MediaLibraryAsyncContext> &context)
5114 {
5115     /* Parse the first argument into displayName */
5116     napi_valuetype valueType;
5117     MediaType mediaType;
5118     int32_t type = 0;
5119     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
5120         "Failed to get type value");
5121     mediaType = static_cast<MediaType>(type);
5122     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
5123 
5124     /* Parse the second argument into albumUri if exists */
5125     string extension;
5126     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extension) ==
5127         napi_ok, "Failed to get extension");
5128     CHECK_COND_WITH_MESSAGE(env, mediaType == MediaFileUtils::GetMediaType("." + extension),
5129         "Failed to check extension");
5130     context->valuesBucket.Put(ASSET_EXTENTION, extension);
5131 
5132     /* Parse the third argument into albumUri if exists */
5133     if (context->argc >= ARGS_THREE) {
5134         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
5135         if (valueType == napi_object) {
5136             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
5137                 "Parse asset create option failed");
5138         } else if (valueType != napi_function) {
5139             NAPI_ERR_LOG("Napi type is wrong in create options");
5140             return nullptr;
5141         }
5142     }
5143 
5144     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5145 
5146     napi_value result = nullptr;
5147     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5148     return result;
5149 }
5150 
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5151 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
5152     unique_ptr<MediaLibraryAsyncContext> &context)
5153 {
5154     constexpr size_t minArgs = ARGS_ONE;
5155     constexpr size_t maxArgs = ARGS_FOUR;
5156     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5157         napi_ok, "Failed to get object info");
5158 
5159     napi_valuetype valueType;
5160     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
5161     if (valueType == napi_string) {
5162         context->isCreateByComponent = false;
5163         context->needSystemApp = true;
5164         if (!MediaLibraryNapiUtils::IsSystemApp()) {
5165             NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5166             return nullptr;
5167         }
5168         return ParseArgsCreatePhotoAssetSystem(env, info, context);
5169     } else if (valueType == napi_number) {
5170         context->isCreateByComponent = true;
5171         return ParseArgsCreatePhotoAssetComponent(env, info, context);
5172     } else {
5173         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5174         return nullptr;
5175     }
5176 }
5177 
ParseTokenId(napi_env env,napi_value arg,uint32_t & tokenId)5178 static napi_status ParseTokenId(napi_env env, napi_value arg,
5179     uint32_t &tokenId)
5180 {
5181     napi_valuetype valueType = napi_undefined;
5182     CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
5183     if (valueType == napi_number) {
5184         CHECK_STATUS_RET(MediaLibraryNapiUtils::GetUInt32(env, arg, tokenId), "Failed to get tokenId");
5185         CHECK_COND_RET(tokenId > 0, napi_invalid_arg, "Invalid tokenId");
5186     } else {
5187         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5188         return napi_invalid_arg;
5189     }
5190     return napi_ok;
5191 }
5192 
ParsePermissionType(napi_env env,napi_value arg,int32_t & permissionType)5193 static napi_status ParsePermissionType(napi_env env, napi_value arg, int32_t &permissionType)
5194 {
5195     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetInt32(env, arg, permissionType), "Failed to get permissionType");
5196     if (AppUriPermissionColumn::PERMISSION_TYPES_PICKER.find((int)permissionType) ==
5197         AppUriPermissionColumn::PERMISSION_TYPES_PICKER.end()) {
5198         NAPI_ERR_LOG("invalid picker permissionType, permissionType=%{public}d", permissionType);
5199         return napi_invalid_arg;
5200     }
5201     return napi_ok;
5202 }
5203 
ParseHidenSensitiveType(napi_env env,napi_value arg,int32_t & hideSensitiveType)5204 static napi_status ParseHidenSensitiveType(napi_env env, napi_value arg, int32_t &hideSensitiveType)
5205 {
5206     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetInt32(env, arg, hideSensitiveType), "Failed to get hideSensitiveType");
5207     if (AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.find((int)hideSensitiveType) ==
5208         AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.end()) {
5209         NAPI_ERR_LOG("invalid picker hideSensitiveType, hideSensitiveType=%{public}d", hideSensitiveType);
5210         return napi_invalid_arg;
5211     }
5212     return napi_ok;
5213 }
5214 
ParseGrantMediaUris(napi_env env,napi_value arg,vector<string> & uris)5215 static napi_status ParseGrantMediaUris(napi_env env, napi_value arg, vector<string> &uris)
5216 {
5217     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetStringArray(env, arg, uris), "Failed to get uris");
5218     size_t urisMaxSize = 1000;
5219     if (uris.empty() || uris.size() > urisMaxSize) {
5220         NAPI_ERR_LOG("the size of uriList is invalid");
5221         return napi_invalid_arg;
5222     }
5223     return napi_ok;
5224 }
5225 
ParseArgsGrantPhotoUriPermissionInner(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5226 static napi_value ParseArgsGrantPhotoUriPermissionInner(napi_env env, napi_callback_info info,
5227     unique_ptr<MediaLibraryAsyncContext> &context)
5228 {
5229     // parse appid or tokenId
5230     uint32_t tokenId;
5231     NAPI_ASSERT(env, ParseTokenId(env, context->argv[ARGS_ZERO], tokenId) ==
5232         napi_ok, "Invalid args[0]");
5233     context->valuesBucket.Put(AppUriPermissionColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5234     uint32_t srcTokenId = IPCSkeleton::GetCallingTokenID();
5235     context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(srcTokenId));
5236 
5237     // parse fileId
5238     string uri;
5239     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], uri) ==
5240         napi_ok, "Failed to get uri");
5241     int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5242     NAPI_ASSERT(env, fileId >= 0, "Invalid uri");
5243     context->valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5244 
5245     // parse permissionType
5246     int32_t permissionType;
5247     NAPI_ASSERT(env, ParsePermissionType(env, context->argv[ARGS_TWO], permissionType) ==
5248         napi_ok, "Invalid PermissionType");
5249     context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5250 
5251     // parse hideSensitiveType
5252     int32_t hideSensitiveType;
5253     NAPI_ASSERT(env, ParseHidenSensitiveType(env, context->argv[ARGS_THREE],
5254         hideSensitiveType) == napi_ok, "Invalid SensitiveType");
5255     context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
5256 
5257     // parsing fileId ensured uri is photo.
5258     context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5259 
5260     napi_value result = nullptr;
5261     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5262     return result;
5263 }
5264 
ParseArgsGrantPhotoUriPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5265 static napi_value ParseArgsGrantPhotoUriPermission(napi_env env, napi_callback_info info,
5266     unique_ptr<MediaLibraryAsyncContext> &context)
5267 {
5268     constexpr size_t minArgs = ARGS_ONE;
5269     constexpr size_t maxArgs = ARGS_FOUR;
5270     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5271         napi_ok, "Failed to get object info");
5272 
5273     context->isCreateByComponent = false;
5274     context->needSystemApp = true;
5275     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5276         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5277         return nullptr;
5278     }
5279 
5280     return ParseArgsGrantPhotoUriPermissionInner(env, info, context);
5281 }
5282 
ParseUriTypes(std::vector<std::string> & uris,unique_ptr<MediaLibraryAsyncContext> & context)5283 static napi_status ParseUriTypes(std::vector<std::string> &uris, unique_ptr<MediaLibraryAsyncContext> &context)
5284 {
5285     // used for deduplication
5286     std::set<int32_t> fileIdSet;
5287     for (const auto &uri : uris) {
5288         OHOS::DataShare::DataShareValuesBucket valuesBucket;
5289         int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5290         if (fileId < 0) {
5291             NAPI_ERR_LOG("invalid uri can not find fileid");
5292             return napi_invalid_arg;
5293         }
5294         if (fileIdSet.find(fileId) != fileIdSet.end()) {
5295             continue;
5296         }
5297         fileIdSet.insert(fileId);
5298         valuesBucket = context->valuesBucket;
5299         valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5300         valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5301         context->valuesBucketArray.push_back(move(valuesBucket));
5302     }
5303     return napi_ok;
5304 }
5305 
ParseArgsGrantPhotoUrisForForceSensitive(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5306 static napi_value ParseArgsGrantPhotoUrisForForceSensitive(napi_env env, napi_callback_info info,
5307     unique_ptr<MediaLibraryAsyncContext> &context)
5308 {
5309     constexpr size_t minArgs = ARGS_ONE;
5310     constexpr size_t maxArgs = ARGS_TWO;
5311     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5312         napi_ok, "Failed to get object info");
5313 
5314     context->isCreateByComponent = false;
5315     context->needSystemApp = true;
5316     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5317         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5318         return nullptr;
5319     }
5320 
5321     // tokenId
5322     uint32_t tokenId = IPCSkeleton::GetCallingTokenID();
5323     context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(tokenId));
5324     context->valuesBucket.Put(AppUriSensitiveColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5325 
5326     // parse uris
5327     vector<string> uris;
5328     NAPI_ASSERT(env, ParseGrantMediaUris(env, context->argv[ARGS_ZERO], uris) ==
5329         napi_ok, "Invalid uri");
5330 
5331     // parse hideSensitiveType
5332     int32_t hideSensitiveType;
5333     NAPI_ASSERT(env, ParseHidenSensitiveType(env, context->argv[ARGS_ONE],
5334         hideSensitiveType) == napi_ok, "Invalid SensitiveType");
5335     context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
5336     NAPI_ASSERT(env, ParseUriTypes(uris, context) == napi_ok, "ParseUriTypes failed");
5337 
5338     napi_value result = nullptr;
5339     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5340     return result;
5341 }
5342 
ParseArgsGrantPhotoUrisPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5343 static napi_value ParseArgsGrantPhotoUrisPermission(napi_env env, napi_callback_info info,
5344     unique_ptr<MediaLibraryAsyncContext> &context)
5345 {
5346     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, ARGS_ONE, ARGS_FOUR) ==
5347         napi_ok, "Failed to get object info");
5348 
5349     context->isCreateByComponent = false;
5350     context->needSystemApp = true;
5351     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5352         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5353         return nullptr;
5354     }
5355     // parse appid or tokenId
5356     uint32_t tokenId;
5357     NAPI_ASSERT(env, ParseTokenId(env, context->argv[ARGS_ZERO], tokenId) ==
5358         napi_ok, "Invalid tokenId");
5359     context->valuesBucket.Put(AppUriPermissionColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5360     uint32_t srcTokenId = IPCSkeleton::GetCallingTokenID();
5361     context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(srcTokenId));
5362 
5363     // parse permissionType
5364     int32_t permissionType;
5365     NAPI_ASSERT(env, ParsePermissionType(env, context->argv[ARGS_TWO], permissionType) ==
5366         napi_ok, "Invalid PermissionType");
5367     context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5368 
5369     // parse hideSensitiveType
5370     int32_t hideSensitiveType;
5371     NAPI_ASSERT(env, ParseHidenSensitiveType(env, context->argv[ARGS_THREE], hideSensitiveType) ==
5372         napi_ok, "Invalid SensitiveType");
5373     context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
5374 
5375     // parsing fileId ensured uri is photo.
5376     context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5377 
5378     // parse uris
5379     vector<string> uris;
5380     NAPI_ASSERT(env, ParseGrantMediaUris(env, context->argv[ARGS_ONE], uris) ==
5381         napi_ok, "Invalid uris");
5382     NAPI_ASSERT(env, ParseUriTypes(uris, context) == napi_ok, "ParseUriTypes failed");
5383 
5384     napi_value result = nullptr;
5385     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5386     return result;
5387 }
5388 
ParseArgsCancelPhotoUriPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5389 static napi_value ParseArgsCancelPhotoUriPermission(napi_env env, napi_callback_info info,
5390     unique_ptr<MediaLibraryAsyncContext> &context)
5391 {
5392     constexpr size_t minArgs = ARGS_ONE;
5393     constexpr size_t maxArgs = ARGS_THREE;
5394     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5395         napi_ok, "Failed to get object info");
5396 
5397     context->isCreateByComponent = false;
5398     context->needSystemApp = true;
5399     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5400         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5401         return nullptr;
5402     }
5403     // parse tokenId
5404     uint32_t tokenId;
5405     NAPI_ASSERT(env, ParseTokenId(env, context->argv[ARGS_ZERO], tokenId) ==
5406         napi_ok, "Invalid args[0]");
5407     context->valuesBucket.Put(AppUriPermissionColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5408 
5409     //get caller tokenid
5410     uint32_t callerTokenId = IPCSkeleton::GetCallingTokenID();
5411     context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(callerTokenId));
5412 
5413     // parse fileId
5414     string uri;
5415     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], uri) ==
5416         napi_ok, "Failed to get uri");
5417     int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5418     if (fileId < 0) {
5419         return nullptr;
5420     }
5421     context->valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5422 
5423     // parse permissionType
5424     int32_t permissionType;
5425     NAPI_ASSERT(env, ParsePermissionType(env, context->argv[ARGS_TWO], permissionType) ==
5426         napi_ok, "Invalid args[2]");
5427     context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5428 
5429     // parsing fileId ensured uri is photo.
5430     context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5431 
5432     napi_value result = nullptr;
5433     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5434     return result;
5435 }
5436 
HandleBundleInfo(OHOS::DataShare::DataShareValuesBucket & valuesBucket,bool isAuthorization,BundleInfo bundleInfo)5437 static void HandleBundleInfo(OHOS::DataShare::DataShareValuesBucket &valuesBucket, bool isAuthorization,
5438     BundleInfo bundleInfo)
5439 {
5440     if (isAuthorization) {
5441         valuesBucket.Put(MEDIA_DATA_DB_OWNER_PACKAGE, bundleInfo.bundleName);
5442         valuesBucket.Put(MEDIA_DATA_DB_OWNER_APPID, bundleInfo.appId);
5443         valuesBucket.Put(MEDIA_DATA_DB_PACKAGE_NAME, bundleInfo.packageName);
5444     }
5445     if (!bundleInfo.ownerAlbumId.empty()) {
5446         valuesBucket.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, bundleInfo.ownerAlbumId);
5447         NAPI_INFO_LOG("client put ownerAlbumId: %{public}s", bundleInfo.ownerAlbumId.c_str());
5448     }
5449 }
5450 
ParseCreateConfig(napi_env env,napi_value arg,BundleInfo bundleInfo,MediaLibraryAsyncContext & context,bool isAuthorization=true)5451 static napi_status ParseCreateConfig(napi_env env, napi_value arg,
5452     BundleInfo bundleInfo, MediaLibraryAsyncContext &context, bool isAuthorization = true)
5453 {
5454     const std::map<std::string, std::string> PHOTO_CREATE_CONFIG_PARAM = {
5455         { PHOTO_TYPE, MEDIA_DATA_DB_MEDIA_TYPE },
5456         { PHOTO_SUB_TYPE, PhotoColumn::PHOTO_SUBTYPE },
5457         { TITLE, MediaColumn::MEDIA_TITLE },
5458         { EXTENSION, ASSET_EXTENTION }
5459     };
5460 
5461     OHOS::DataShare::DataShareValuesBucket valuesBucket;
5462     for (const auto &iter : PHOTO_CREATE_CONFIG_PARAM) {
5463         string param = iter.first;
5464         bool present = false;
5465         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
5466         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
5467         if (!present) {
5468             continue;
5469         }
5470         napi_value value;
5471         result = napi_get_named_property(env, arg, param.c_str(), &value);
5472         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5473         napi_valuetype valueType = napi_undefined;
5474         result = napi_typeof(env, value, &valueType);
5475         CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5476         if (valueType == napi_number) {
5477             int32_t number = 0;
5478             result = napi_get_value_int32(env, value, &number);
5479             CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5480             valuesBucket.Put(iter.second, number);
5481         } else if (valueType == napi_string) {
5482             char buffer[ARG_BUF_SIZE];
5483             size_t res = 0;
5484             result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5485             CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5486             string bufferString(buffer);
5487             if (!bufferString.empty()) {
5488                 valuesBucket.Put(iter.second, bufferString);
5489             }
5490         } else if (valueType == napi_undefined || valueType == napi_null) {
5491             continue;
5492         } else {
5493             NAPI_ERR_LOG("ParseCreateConfig failed, valueType %{public}d is unaccepted", static_cast<int>(valueType));
5494             return napi_invalid_arg;
5495         }
5496     }
5497     HandleBundleInfo(valuesBucket, isAuthorization, bundleInfo);
5498     if (isAuthorization) {
5499         context.tokenId = bundleInfo.tokenId;
5500     }
5501     context.valuesBucketArray.push_back(move(valuesBucket));
5502     return napi_ok;
5503 }
5504 
ParseCreateSource(napi_env env,napi_value arg,BundleInfo & bundleInfo)5505 static napi_value ParseCreateSource(napi_env env, napi_value arg, BundleInfo &bundleInfo)
5506 {
5507     napi_value valueBundleName = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5508         CONFIRM_BOX_BUNDLE_NAME.c_str());
5509     CHECK_NULLPTR_RET(valueBundleName);
5510     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, valueBundleName,
5511         bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
5512     napi_value valueAppName = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5513         CONFIRM_BOX_APP_NAME.c_str());
5514     CHECK_NULLPTR_RET(valueAppName);
5515     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, valueAppName,
5516         bundleInfo.packageName) == napi_ok, "Failed to get appName");
5517     napi_value valueAppId = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5518         CONFIRM_BOX_APP_ID.c_str());
5519     CHECK_NULLPTR_RET(valueAppId);
5520     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, valueAppId,
5521         bundleInfo.appId) == napi_ok, "Failed to get appId");
5522     napi_value valueTokenId = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5523         TOKEN_ID.c_str());
5524     CHECK_NULLPTR_RET(valueTokenId);
5525     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetUInt32(env, valueTokenId,
5526         bundleInfo.tokenId) == napi_ok, "Failed to get appId");
5527     napi_value result = nullptr;
5528     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5529     return result;
5530 }
5531 
ParseArgsCreatePhotoAssetForAppWithAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5532 static napi_value ParseArgsCreatePhotoAssetForAppWithAlbum(napi_env env, napi_callback_info info,
5533     unique_ptr<MediaLibraryAsyncContext> &context)
5534 {
5535     constexpr size_t minArgs = ARGS_FOUR;
5536     constexpr size_t maxArgs = ARGS_FOUR;
5537     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5538         napi_ok, "Failed to get object info");
5539     context->isCreateByComponent = false;
5540     context->isCreateByAgent = true;
5541     BundleInfo bundleInfo;
5542     string albumUri;
5543     bool isAuthorization = false;
5544     ParseCreateSource(env, context->argv[ARGS_ZERO], bundleInfo);
5545     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
5546         albumUri) == napi_ok, "Failed to get albumUri");
5547     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[ARGS_TWO],
5548         isAuthorization) == napi_ok, "Failed to get isAuthorization");
5549     MediaFileUri fileUri = MediaFileUri(albumUri);
5550     CHECK_COND_WITH_MESSAGE(env, fileUri.GetUriType() == API10_PHOTOALBUM_URI, "Failed to get photoAlbum");
5551     bundleInfo.ownerAlbumId = MediaFileUtils::GetIdFromUri(albumUri);
5552     context->isContainsAlbumUri = true;
5553     if (isAuthorization) {
5554         context->tokenId = bundleInfo.tokenId;
5555     }
5556     napi_value result = nullptr;
5557     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5558 
5559     vector<napi_value> napiValues;
5560     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_THREE], napiValues));
5561     if (napiValues.empty() || napiValues.size() > MAX_CREATE_ASSET_LIMIT) {
5562         NAPI_ERR_LOG("the size of albumid is invalid");
5563         return nullptr;
5564     }
5565 
5566     for (const auto& napiValue : napiValues) {
5567         CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context,
5568             isAuthorization) == napi_ok, "Parse asset create config failed");
5569     }
5570 
5571     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
5572         == napi_ok, "Failed to get callback");
5573     return result;
5574 }
5575 
ParseArgsCreateAgentCreateAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5576 static napi_value ParseArgsCreateAgentCreateAssets(napi_env env, napi_callback_info info,
5577     unique_ptr<MediaLibraryAsyncContext> &context)
5578 {
5579     /* Parse the arguments */
5580     BundleInfo bundleInfo;
5581     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO],
5582         bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
5583     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
5584         bundleInfo.packageName) == napi_ok, "Failed to get appName");
5585     CHECK_COND_WITH_MESSAGE(env, ParseTokenId(env, context->argv[ARGS_TWO],
5586         bundleInfo.tokenId) == napi_ok, "Failed to get tokenId");
5587 
5588     napi_value result = nullptr;
5589     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5590 
5591     vector<napi_value> napiValues;
5592     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_THREE], napiValues));
5593     if (napiValues.empty()) {
5594         return result;
5595     }
5596 
5597     for (const auto& napiValue : napiValues) {
5598         CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context) == napi_ok,
5599             "Parse asset create config failed");
5600     }
5601 
5602     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
5603         == napi_ok, "Failed to get callback");
5604     return result;
5605 }
5606 
ParseArgsAgentCreateAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5607 static napi_value ParseArgsAgentCreateAssets(napi_env env, napi_callback_info info,
5608     unique_ptr<MediaLibraryAsyncContext> &context)
5609 {
5610     constexpr size_t minArgs = ARGS_FOUR;
5611     constexpr size_t maxArgs = ARGS_FOUR;
5612     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5613         napi_ok, "Failed to get object info");
5614 
5615     context->isCreateByComponent = false;
5616     context->isCreateByAgent = true;
5617 
5618     return ParseArgsCreateAgentCreateAssets(env, info, context);
5619 }
5620 
ParseArgsCreateAudioAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5621 static napi_value ParseArgsCreateAudioAssetSystem(napi_env env, napi_callback_info info,
5622     unique_ptr<MediaLibraryAsyncContext> &context)
5623 {
5624     /* Parse the first argument into displayName */
5625     string displayName;
5626     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
5627         napi_ok, "Failed to get displayName");
5628 
5629     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_AUDIO);
5630     context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
5631 
5632     napi_value result = nullptr;
5633     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5634     return result;
5635 }
5636 
ParseArgsCreateAudioAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5637 static napi_value ParseArgsCreateAudioAssetComponent(napi_env env, napi_callback_info info,
5638     unique_ptr<MediaLibraryAsyncContext> &context)
5639 {
5640     /* Parse the first argument into displayName */
5641     napi_valuetype valueType;
5642     MediaType mediaType;
5643     int32_t type = 0;
5644     NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
5645         "Failed to get type value");
5646     mediaType = static_cast<MediaType>(type);
5647     NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_AUDIO), "invalid file type");
5648 
5649     /* Parse the second argument into albumUri if exists */
5650     string extention;
5651     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
5652         napi_ok, "Failed to get extention");
5653     context->valuesBucket.Put(ASSET_EXTENTION, extention);
5654 
5655     /* Parse the third argument into albumUri if exists */
5656     if (context->argc >= ARGS_THREE) {
5657         NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
5658         if (valueType == napi_object) {
5659             NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
5660                 "Parse asset create option failed");
5661         } else if (valueType != napi_function) {
5662             NAPI_ERR_LOG("Napi type is wrong in create options");
5663             return nullptr;
5664         }
5665     }
5666 
5667     context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5668     NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
5669 
5670     napi_value result = nullptr;
5671     NAPI_CALL(env, napi_get_boolean(env, true, &result));
5672     return result;
5673 }
5674 
ParseArgsCreateAudioAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5675 static napi_value ParseArgsCreateAudioAsset(napi_env env, napi_callback_info info,
5676     unique_ptr<MediaLibraryAsyncContext> &context)
5677 {
5678     constexpr size_t minArgs = ARGS_ONE;
5679     constexpr size_t maxArgs = ARGS_FOUR;
5680     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5681         napi_ok, "Failed to get object info");
5682 
5683     napi_valuetype valueType;
5684     NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
5685     if (valueType == napi_string) {
5686         context->isCreateByComponent = false;
5687         return ParseArgsCreateAudioAssetSystem(env, info, context);
5688     } else if (valueType == napi_number) {
5689         context->isCreateByComponent = true;
5690         return ParseArgsCreateAudioAssetComponent(env, info, context);
5691     } else {
5692         NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5693         return nullptr;
5694     }
5695 }
5696 
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5697 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
5698     unique_ptr<MediaLibraryAsyncContext> &context)
5699 {
5700     constexpr size_t minArgs = ARGS_ONE;
5701     constexpr size_t maxArgs = ARGS_TWO;
5702     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5703         JS_ERR_PARAMETER_INVALID);
5704 
5705     /* Parse the first argument */
5706     CHECK_ARGS(env,
5707         MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
5708         JS_INNER_FAIL);
5709 
5710     switch (context->assetType) {
5711         case TYPE_AUDIO: {
5712             CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5713                 AudioColumn::IsAudioColumn, TYPE_AUDIO));
5714             break;
5715         }
5716         case TYPE_PHOTO: {
5717             CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5718                 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
5719             break;
5720         }
5721         default: {
5722             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5723             return nullptr;
5724         }
5725     }
5726     auto &predicates = context->predicates;
5727     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
5728     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5729     if (context->assetType == TYPE_PHOTO) {
5730         predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
5731         predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
5732         predicates.EqualTo(
5733             PhotoColumn::PHOTO_BURST_COVER_LEVEL, to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
5734     }
5735     napi_value result = nullptr;
5736     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5737     return result;
5738 }
5739 
ParseArgsGetBurstAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5740 static napi_value ParseArgsGetBurstAssets(napi_env env, napi_callback_info info,
5741     unique_ptr<MediaLibraryAsyncContext> &context)
5742 {
5743     constexpr size_t minArgs = ARGS_ONE;
5744     constexpr size_t maxArgs = ARGS_TWO;
5745     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5746         OHOS_INVALID_PARAM_CODE);
5747 
5748     /* Parse the first argument */
5749     std::string burstKey;
5750     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], burstKey),
5751         OHOS_INVALID_PARAM_CODE);
5752     if (burstKey.empty()) {
5753         NAPI_ERR_LOG("The input burstkey cannot be empty");
5754         return nullptr;
5755     }
5756     /* Parse the second argument */
5757     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ASSET_FETCH_OPT, context),
5758         JS_INNER_FAIL);
5759 
5760     auto &predicates = context->predicates;
5761     if (context->assetType != TYPE_PHOTO) {
5762         return nullptr;
5763     }
5764     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5765         PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
5766     predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_KEY, burstKey);
5767     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5768     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
5769     predicates.OrderByAsc(MediaColumn::MEDIA_NAME);
5770     context->burstKey = burstKey;
5771 
5772     napi_value result = nullptr;
5773     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5774     return result;
5775 }
5776 
ParseArgsIndexUri(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,string & uri,string & albumUri)5777 static napi_status ParseArgsIndexUri(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, string &uri,
5778     string &albumUri)
5779 {
5780     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], uri),
5781         "Failed to get first string argument");
5782     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri),
5783         "Failed to get second string argument");
5784     return napi_ok;
5785 }
5786 
ParseArgsIndexof(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5787 static napi_value ParseArgsIndexof(napi_env env, napi_callback_info info,
5788     unique_ptr<MediaLibraryAsyncContext> &context)
5789 {
5790     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5791         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5792         return nullptr;
5793     }
5794 
5795     constexpr size_t minArgs = ARGS_THREE;
5796     constexpr size_t maxArgs = ARGS_FOUR;
5797     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5798         JS_ERR_PARAMETER_INVALID);
5799 
5800     string uri;
5801     string album;
5802     CHECK_ARGS(env, ParseArgsIndexUri(env, context, uri, album), JS_INNER_FAIL);
5803     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM2], ASSET_FETCH_OPT, context),
5804         JS_INNER_FAIL);
5805     auto &predicates = context->predicates;
5806     predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
5807     predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5808     predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
5809     predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
5810 
5811     context->fetchColumn.clear();
5812     MediaFileUri photoUri(uri);
5813     CHECK_COND(env, photoUri.GetUriType() == API10_PHOTO_URI, JS_ERR_PARAMETER_INVALID);
5814     context->fetchColumn.emplace_back(photoUri.GetFileId());
5815     NAPI_INFO_LOG("current fileId: %{public}s", photoUri.GetFileId().c_str());
5816     if (!album.empty()) {
5817         MediaFileUri albumUri(album);
5818         CHECK_COND(env, albumUri.GetUriType() == API10_PHOTOALBUM_URI ||
5819             albumUri.GetUriType() == API10_ANALYSISALBUM_URI, JS_ERR_PARAMETER_INVALID);
5820         context->isAnalysisAlbum = (albumUri.GetUriType() == API10_ANALYSISALBUM_URI);
5821         context->fetchColumn.emplace_back(albumUri.GetFileId());
5822         NAPI_INFO_LOG("current albumId: %{public}s", albumUri.GetFileId().c_str());
5823     } else {
5824         context->fetchColumn.emplace_back(album);
5825     }
5826     napi_value result = nullptr;
5827     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5828     return result;
5829 }
5830 
JSGetAssetsExecute(napi_env env,void * data)5831 static void JSGetAssetsExecute(napi_env env, void *data)
5832 {
5833     MediaLibraryTracer tracer;
5834     tracer.Start("JSGetAssetsExecute");
5835 
5836     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5837     string queryUri;
5838     switch (context->assetType) {
5839         case TYPE_AUDIO: {
5840             queryUri = UFM_QUERY_AUDIO;
5841             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5842             break;
5843         }
5844         case TYPE_PHOTO: {
5845             queryUri = UFM_QUERY_PHOTO;
5846             MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5847             break;
5848         }
5849         default: {
5850             context->SaveError(-EINVAL);
5851             return;
5852         }
5853     }
5854 
5855     Uri uri(queryUri);
5856     int errCode = 0;
5857     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
5858         context->predicates, context->fetchColumn, errCode, context->userId);
5859     if (resultSet == nullptr) {
5860         context->SaveError(errCode);
5861         return;
5862     }
5863     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
5864     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
5865     context->fetchFileResult->SetUserId(context->userId);
5866 }
5867 
GetPhotoIndexAsyncCallbackComplete(napi_env env,napi_status status,void * data)5868 static void GetPhotoIndexAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5869 {
5870     MediaLibraryTracer tracer;
5871     tracer.Start("GetPhotoIndexAsyncCallbackComplete");
5872 
5873     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5874     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5875 
5876     auto jsContext = make_unique<JSAsyncContextOutput>();
5877     jsContext->status = false;
5878     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
5879     if (context->error != ERR_DEFAULT) {
5880         context->HandleError(env, jsContext->error);
5881     } else {
5882         int32_t count = -1;
5883         if (context->fetchFileResult != nullptr) {
5884             auto fileAsset = context->fetchFileResult->GetFirstObject();
5885             if (fileAsset != nullptr) {
5886                 count = fileAsset->GetPhotoIndex();
5887             }
5888         }
5889         jsContext->status = true;
5890         napi_create_int32(env, count, &jsContext->data);
5891     }
5892 
5893     tracer.Finish();
5894     if (context->work != nullptr) {
5895         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5896                                                    context->work, *jsContext);
5897     }
5898     delete context;
5899 }
5900 
GetPhotoIndexExec(napi_env env,void * data,ResultNapiType type)5901 static void GetPhotoIndexExec(napi_env env, void *data, ResultNapiType type)
5902 {
5903     MediaLibraryTracer tracer;
5904     tracer.Start("JsGetPhotoIndexExec");
5905     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5906     string queryUri = context->isAnalysisAlbum ? PAH_GET_ANALYSIS_INDEX : UFM_GET_INDEX;
5907     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5908     Uri uri(queryUri);
5909     int errCode = 0;
5910     if (context->fetchColumn.size() < 2) { // 2: photoId, albumId
5911         context->SaveError(E_ERR);
5912         return;
5913     }
5914     GetPhotoIndexReqBody reqBody;
5915     reqBody.predicates = context->predicates;
5916     reqBody.photoId = context->fetchColumn[0];
5917     reqBody.albumId = context->fetchColumn[1];
5918     reqBody.isAnalysisAlbum = context->isAnalysisAlbum;
5919     QueryResultRespBody respBody;
5920     errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(
5921         static_cast<uint32_t>(MediaLibraryBusinessCode::GET_PHOTO_INDEX), reqBody, respBody);
5922     auto resultSet = respBody.resultSet;
5923     if (resultSet == nullptr) {
5924         NAPI_ERR_LOG("resultSet is nullptr");
5925         context->SaveError(errCode);
5926         return;
5927     }
5928     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
5929     context->fetchFileResult->SetResultNapiType(type);
5930 }
5931 
PhotoAccessGetPhotoIndexExec(napi_env env,void * data)5932 static void PhotoAccessGetPhotoIndexExec(napi_env env, void *data)
5933 {
5934     GetPhotoIndexExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
5935 }
5936 
JsGetPhotoIndexExec(napi_env env,void * data)5937 static void JsGetPhotoIndexExec(napi_env env, void *data)
5938 {
5939     GetPhotoIndexExec(env, data, ResultNapiType::TYPE_USERFILE_MGR);
5940 }
5941 
JSGetPhotoIndex(napi_env env,napi_callback_info info)5942 napi_value MediaLibraryNapi::JSGetPhotoIndex(napi_env env, napi_callback_info info)
5943 {
5944     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5945     CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
5946 
5947     SetUserIdFromObjectInfo(asyncContext);
5948     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
5949         JsGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
5950 }
5951 
PhotoAccessGetPhotoIndex(napi_env env,napi_callback_info info)5952 napi_value MediaLibraryNapi::PhotoAccessGetPhotoIndex(napi_env env, napi_callback_info info)
5953 {
5954     MediaLibraryTracer tracer;
5955     tracer.Start("PhotoAccessGetPhotoIndex");
5956 
5957     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5958     CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
5959 
5960     SetUserIdFromObjectInfo(asyncContext);
5961     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
5962         PhotoAccessGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
5963 }
5964 
GetIndexConstructProgressAsyncCallbackComplete(napi_env env,napi_status status,void * data)5965 static void GetIndexConstructProgressAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5966 {
5967     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5968     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5969     auto jsContext = make_unique<JSAsyncContextOutput>();
5970     jsContext->status = false;
5971 
5972     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
5973     if (context->error != ERR_DEFAULT) {
5974         context->HandleError(env, jsContext->error);
5975     } else {
5976         CHECK_ARGS_RET_VOID(
5977             env, napi_create_string_utf8(env, context->indexProgress.c_str(), NAPI_AUTO_LENGTH, &jsContext->data),
5978             JS_INNER_FAIL);
5979         jsContext->status = true;
5980     }
5981 
5982     if (context->work != nullptr) {
5983         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5984             context->work, *jsContext);
5985     }
5986     delete context;
5987 }
5988 
PhotoAccessGetIndexConstructProgressExec(napi_env env,void * data)5989 static void PhotoAccessGetIndexConstructProgressExec(napi_env env, void *data)
5990 {
5991     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
5992     CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
5993 
5994     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::GET_INDEX_CONSTRUCT_PROGRESS);
5995     GetIndexConstructProgressRespBody respBody;
5996     int32_t errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Get(businessCode, respBody);
5997 
5998     if (errCode != E_OK) {
5999         NAPI_ERR_LOG("get index construct progress failed, errCode is %{public}d", errCode);
6000         context->SaveError(errCode);
6001         return;
6002     }
6003     context->indexProgress = respBody.indexProgress;
6004 }
6005 
PhotoAccessGetIndexConstructProgress(napi_env env,napi_callback_info info)6006 napi_value MediaLibraryNapi::PhotoAccessGetIndexConstructProgress(napi_env env, napi_callback_info info)
6007 {
6008     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6009         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6010         return nullptr;
6011     }
6012 
6013     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6014 
6015     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, 0, 0),
6016         JS_ERR_PARAMETER_INVALID);
6017 
6018     SetUserIdFromObjectInfo(asyncContext);
6019     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetIndexConstructProgress",
6020         PhotoAccessGetIndexConstructProgressExec, GetIndexConstructProgressAsyncCallbackComplete);
6021 }
6022 
CheckFormId(string & formId)6023 static napi_status CheckFormId(string &formId)
6024 {
6025     if (formId.empty() || formId.length() > FORMID_MAX_LEN) {
6026         return napi_invalid_arg;
6027     }
6028     for (uint32_t i = 0; i < formId.length(); i++) {
6029         if (!isdigit(formId[i])) {
6030             return napi_invalid_arg;
6031         }
6032     }
6033     unsigned long long num = stoull(formId);
6034     if (num > MAX_INT64) {
6035         return napi_invalid_arg;
6036     }
6037     return napi_ok;
6038 }
6039 
ParseUpdateGalleryFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)6040 static napi_status ParseUpdateGalleryFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
6041 {
6042     const std::string formIdKey = "formId";
6043     const std::string assetUrisKey = "assetUris";
6044 
6045     bool formIdPresent = false;
6046     napi_status result = napi_has_named_property(env, arg, formIdKey.c_str(), &formIdPresent);
6047     CHECK_COND_RET(result == napi_ok, result, "failed to check formId property");
6048     if (!formIdPresent) {
6049         return napi_invalid_arg;
6050     }
6051     napi_value formIdValue;
6052     result = napi_get_named_property(env, arg, formIdKey.c_str(), &formIdValue);
6053     CHECK_COND_RET(result == napi_ok, result, "failed to get formId property");
6054     char formIdBuffer[ARG_BUF_SIZE];
6055     size_t formIdLength = 0;
6056     result = napi_get_value_string_utf8(env, formIdValue, formIdBuffer, ARG_BUF_SIZE, &formIdLength);
6057     CHECK_COND_RET(result == napi_ok, result, "failed to get formId string");
6058     std::string formId = std::string(formIdBuffer);
6059     if (CheckFormId(formId) != napi_ok) {
6060         return napi_invalid_arg;
6061     }
6062     context.formId = formId;
6063 
6064     bool urisPresent = false;
6065     result = napi_has_named_property(env, arg, assetUrisKey.c_str(), &urisPresent);
6066     CHECK_COND_RET(result == napi_ok, result, "failed to check uris property");
6067     if (!urisPresent) {
6068         return napi_invalid_arg;
6069     }
6070     napi_value urisValue;
6071     result = napi_get_named_property(env, arg, assetUrisKey.c_str(), &urisValue);
6072     CHECK_COND_RET(result == napi_ok, result, "failed to get uris property");
6073     bool isArray = false;
6074     result = napi_is_array(env, urisValue, &isArray);
6075     CHECK_COND_RET(result == napi_ok && isArray, napi_invalid_arg, "uris is not an array");
6076 
6077     uint32_t arrayLength = 0;
6078     result = napi_get_array_length(env, urisValue, &arrayLength);
6079     CHECK_COND_RET(result == napi_ok, result, "failed to get array length");
6080     if (arrayLength == 0) {
6081         return napi_invalid_arg;
6082     }
6083 
6084     for (uint32_t i = 0; i < arrayLength; ++i) {
6085         napi_value uriValue;
6086         result = napi_get_element(env, urisValue, i, &uriValue);
6087         CHECK_COND_RET(result == napi_ok, result, "failed to get array element");
6088         char uriBuffer[ARG_BUF_SIZE];
6089         size_t uriLength = 0;
6090         result = napi_get_value_string_utf8(env, uriValue, uriBuffer, ARG_BUF_SIZE, &uriLength);
6091         CHECK_COND_RET(result == napi_ok, result, "failed to get URI string");
6092         std::string assetUri = std::string(uriBuffer);
6093         OHOS::DataShare::DataShareValuesBucket bucket;
6094         bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, formId);
6095         bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, assetUri);
6096         context.valuesBucketArray.push_back(move(bucket));
6097     }
6098     return napi_ok;
6099 }
6100 
ParseSaveGalleryFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)6101 static napi_status ParseSaveGalleryFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
6102 {
6103     const std::string formIdKey = "formId";
6104     const std::string assetUrisKey = "assetUris";
6105 
6106     bool formIdPresent = false;
6107     napi_status result = napi_has_named_property(env, arg, formIdKey.c_str(), &formIdPresent);
6108     CHECK_COND_RET(result == napi_ok, result, "failed to check formId property");
6109     if (!formIdPresent) {
6110         NAPI_ERR_LOG("ParseSaveGalleryFormInfoOption formIdPresent is false");
6111         return napi_invalid_arg;
6112     }
6113 
6114     napi_value formIdValue;
6115     result = napi_get_named_property(env, arg, formIdKey.c_str(), &formIdValue);
6116     CHECK_COND_RET(result == napi_ok, result, "failed to get formId property");
6117 
6118     char formIdBuffer[ARG_BUF_SIZE];
6119     size_t formIdLength = 0;
6120     result = napi_get_value_string_utf8(env, formIdValue, formIdBuffer, ARG_BUF_SIZE, &formIdLength);
6121     CHECK_COND_RET(result == napi_ok, result, "failed to get formId string");
6122 
6123     std::string formId = std::string(formIdBuffer);
6124     if (CheckFormId(formId) != napi_ok) {
6125         return napi_invalid_arg;
6126     }
6127 
6128     bool urisPresent = false;
6129     result = napi_has_named_property(env, arg, assetUrisKey.c_str(), &urisPresent);
6130     CHECK_COND_RET(result == napi_ok, result, "failed to check uris property");
6131     if (!urisPresent) {
6132         NAPI_ERR_LOG("ParseSaveGalleryFormInfoOption urisPresent is false");
6133         return napi_invalid_arg;
6134     }
6135 
6136     napi_value urisValue;
6137     result = napi_get_named_property(env, arg, assetUrisKey.c_str(), &urisValue);
6138     CHECK_COND_RET(result == napi_ok, result, "failed to get uris property");
6139 
6140     bool isArray = false;
6141     result = napi_is_array(env, urisValue, &isArray);
6142     CHECK_COND_RET(result == napi_ok && isArray, napi_invalid_arg, "uris is not an array");
6143 
6144     uint32_t arrayLength = 0;
6145     result = napi_get_array_length(env, urisValue, &arrayLength);
6146     CHECK_COND_RET(result == napi_ok, result, "failed to get array length");
6147     if (arrayLength == 0) {
6148         return napi_invalid_arg;
6149     }
6150 
6151     for (uint32_t i = 0; i < arrayLength; ++i) {
6152         napi_value uriValue;
6153         result = napi_get_element(env, urisValue, i, &uriValue);
6154         CHECK_COND_RET(result == napi_ok, result, "failed to get array element");
6155 
6156         char uriBuffer[ARG_BUF_SIZE];
6157         size_t uriLength = 0;
6158         result = napi_get_value_string_utf8(env, uriValue, uriBuffer, ARG_BUF_SIZE, &uriLength);
6159         CHECK_COND_RET(result == napi_ok, result, "failed to get URI string");
6160         std::string assetUri = std::string(uriBuffer);
6161         OHOS::DataShare::DataShareValuesBucket bucket;
6162         bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, formId);
6163         bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, assetUri);
6164         context.valuesBucketArray.push_back(move(bucket));
6165     }
6166     return napi_ok;
6167 }
6168 
ParseSaveFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)6169 static napi_status ParseSaveFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
6170 {
6171     const std::string formId = "formId";
6172     const std::string uri = "uri";
6173     const std::map<std::string, std::string> saveFormInfoOptionsParam = {
6174         { formId, FormMap::FORMMAP_FORM_ID },
6175         { uri, FormMap::FORMMAP_URI }
6176     };
6177     for (const auto &iter : saveFormInfoOptionsParam) {
6178         string param = iter.first;
6179         bool present = false;
6180         napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
6181         CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
6182         if (!present) {
6183             return napi_invalid_arg;
6184         }
6185         napi_value value;
6186         result = napi_get_named_property(env, arg, param.c_str(), &value);
6187         CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
6188         char buffer[ARG_BUF_SIZE];
6189         size_t res = 0;
6190         result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
6191         CHECK_COND_RET(result == napi_ok, result, "failed to get string");
6192         context.valuesBucket.Put(iter.second, string(buffer));
6193     }
6194     bool isValid = false;
6195     string tempFormId = context.valuesBucket.Get(FormMap::FORMMAP_FORM_ID, isValid);
6196     if (!isValid) {
6197         return napi_invalid_arg;
6198     }
6199     return CheckFormId(tempFormId);
6200 }
6201 
ParseArgsUpdateGalleryFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6202 static napi_value ParseArgsUpdateGalleryFormInfo(napi_env env, napi_callback_info info,
6203     unique_ptr<MediaLibraryAsyncContext> &context)
6204 {
6205     constexpr size_t minArgs = ARGS_ONE;
6206     constexpr size_t maxArgs = ARGS_TWO;
6207     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6208         maxArgs) == napi_ok, "Failed to get object info");
6209 
6210     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6211         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6212         return nullptr;
6213     }
6214 
6215     CHECK_COND_WITH_MESSAGE(env, ParseUpdateGalleryFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
6216         "Parse formInfo Option failed");
6217 
6218     napi_value result = nullptr;
6219     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6220     return result;
6221 }
6222 
ParseArgsSaveGalleryFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6223 static napi_value ParseArgsSaveGalleryFormInfo(napi_env env, napi_callback_info info,
6224     unique_ptr<MediaLibraryAsyncContext> &context)
6225 {
6226     constexpr size_t minArgs = ARGS_ONE;
6227     constexpr size_t maxArgs = ARGS_TWO;
6228     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6229         maxArgs) == napi_ok, "Failed to get object info");
6230 
6231     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6232         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6233         return nullptr;
6234     }
6235 
6236     CHECK_COND_WITH_MESSAGE(env, ParseSaveGalleryFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
6237         "Parse formInfo Option failed");
6238 
6239     napi_value result = nullptr;
6240     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6241     return result;
6242 }
6243 
ParseArgsSaveFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6244 static napi_value ParseArgsSaveFormInfo(napi_env env, napi_callback_info info,
6245     unique_ptr<MediaLibraryAsyncContext> &context)
6246 {
6247     constexpr size_t minArgs = ARGS_ONE;
6248     constexpr size_t maxArgs = ARGS_TWO;
6249     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6250         maxArgs) == napi_ok, "Failed to get object info");
6251 
6252     CHECK_COND_WITH_MESSAGE(env, ParseSaveFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
6253         "Parse formInfo Option failed");
6254 
6255     napi_value result = nullptr;
6256     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6257     return result;
6258 }
6259 
SaveGalleryFormInfoExec(napi_env env,void * data,ResultNapiType type)6260 static void SaveGalleryFormInfoExec(napi_env env, void *data, ResultNapiType type)
6261 {
6262     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6263     context->resultNapiType = type;
6264     vector<string> formIds;
6265     vector<string> fileUris;
6266     bool isValid = false;
6267     for (const auto& valueBucket : context->valuesBucketArray) {
6268         formIds.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, isValid));
6269         fileUris.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, isValid));
6270     }
6271     FormInfoReqBody reqBody;
6272     reqBody.formIds = formIds;
6273     reqBody.fileUris = fileUris;
6274     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::SAVE_GALLERY_FORM_INFO);
6275     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6276     if (ret < 0) {
6277         if (ret == E_PERMISSION_DENIED) {
6278             context->error = OHOS_PERMISSION_DENIED_CODE;
6279         } else if (ret == E_GET_PRAMS_FAIL) {
6280             context->error = OHOS_INVALID_PARAM_CODE;
6281         } else {
6282             context->SaveError(ret);
6283         }
6284         NAPI_INFO_LOG("store formInfo failed, ret: %{public}d", ret);
6285     }
6286 }
6287 
SaveFormInfoExec(napi_env env,void * data,ResultNapiType type)6288 static void SaveFormInfoExec(napi_env env, void *data, ResultNapiType type)
6289 {
6290     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6291     context->resultNapiType = type;
6292     bool isValid = false;
6293     string formId = context->valuesBucket.Get(FormMap::FORMMAP_FORM_ID, isValid);
6294     string fileUri = context->valuesBucket.Get(FormMap::FORMMAP_URI, isValid);
6295     FormInfoReqBody reqBody;
6296     reqBody.formIds.emplace_back(formId);
6297     reqBody.fileUris.emplace_back(fileUri);
6298     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::SAVE_FORM_INFO);
6299     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6300     if (ret < 0) {
6301         if (ret == E_PERMISSION_DENIED) {
6302             context->error = OHOS_PERMISSION_DENIED_CODE;
6303         } else if (ret == E_GET_PRAMS_FAIL) {
6304             context->error = OHOS_INVALID_PARAM_CODE;
6305         } else {
6306             context->SaveError(ret);
6307         }
6308         NAPI_ERR_LOG("store formInfo failed, ret: %{public}d", ret);
6309     }
6310 }
6311 
SaveFormInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)6312 static void SaveFormInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
6313 {
6314     MediaLibraryTracer tracer;
6315     tracer.Start("SaveFormInfoAsyncCallbackComplete");
6316 
6317     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6318     auto jsContext = make_unique<JSAsyncContextOutput>();
6319     jsContext->status = false;
6320     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6321     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6322     if (context->error != ERR_DEFAULT) {
6323         context->HandleError(env, jsContext->error);
6324     } else {
6325         jsContext->status = true;
6326     }
6327     tracer.Finish();
6328     if (context->work != nullptr) {
6329         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6330                                                    context->work, *jsContext);
6331     }
6332     delete context;
6333 }
6334 
ParseArgsRemoveGalleryFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6335 static napi_value ParseArgsRemoveGalleryFormInfo(napi_env env, napi_callback_info info,
6336     unique_ptr<MediaLibraryAsyncContext> &context)
6337 {
6338     constexpr size_t minArgs = ARGS_ONE;
6339     constexpr size_t maxArgs = ARGS_TWO;
6340     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6341         maxArgs) == napi_ok, "Failed to get object info");
6342 
6343     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6344         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6345         return nullptr;
6346     }
6347 
6348     bool present = false;
6349     CHECK_COND_WITH_MESSAGE(env, napi_has_named_property(env, context->argv[ARGS_ZERO], "formId", &present) == napi_ok,
6350         "Failed to get object info");
6351     if (!present) {
6352         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check empty formId!");
6353         return nullptr;
6354     }
6355 
6356     napi_value value;
6357     CHECK_COND_WITH_MESSAGE(env, napi_get_named_property(env, context->argv[ARGS_ZERO], "formId", &value) == napi_ok,
6358         "failed to get named property");
6359     char buffer[ARG_BUF_SIZE];
6360     size_t res = 0;
6361     CHECK_COND_WITH_MESSAGE(env, napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res) == napi_ok,
6362         "failed to get string param");
6363     context->formId = string(buffer);
6364     CHECK_COND_WITH_MESSAGE(env, CheckFormId(context->formId) == napi_ok, "FormId is invalid");
6365     napi_value result = nullptr;
6366     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6367     return result;
6368 }
6369 
ParseArgsRemoveFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6370 static napi_value ParseArgsRemoveFormInfo(napi_env env, napi_callback_info info,
6371     unique_ptr<MediaLibraryAsyncContext> &context)
6372 {
6373     constexpr size_t minArgs = ARGS_ONE;
6374     constexpr size_t maxArgs = ARGS_TWO;
6375     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6376         maxArgs) == napi_ok, "Failed to get object info");
6377 
6378     bool present = false;
6379     CHECK_COND_WITH_MESSAGE(env, napi_has_named_property(env, context->argv[ARGS_ZERO], "formId", &present) == napi_ok,
6380         "Failed to get object info");
6381     if (!present) {
6382         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check empty formId!");
6383         return nullptr;
6384     }
6385 
6386     napi_value value;
6387     CHECK_COND_WITH_MESSAGE(env, napi_get_named_property(env, context->argv[ARGS_ZERO], "formId", &value) == napi_ok,
6388         "failed to get named property");
6389     char buffer[ARG_BUF_SIZE];
6390     size_t res = 0;
6391     CHECK_COND_WITH_MESSAGE(env, napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res) == napi_ok,
6392         "failed to get string param");
6393     context->formId = string(buffer);
6394     CHECK_COND_WITH_MESSAGE(env, CheckFormId(context->formId) == napi_ok, "FormId is invalid");
6395     napi_value result = nullptr;
6396     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6397     return result;
6398 }
6399 
UpdateGalleryFormInfoExec(napi_env env,void * data,ResultNapiType type)6400 static void UpdateGalleryFormInfoExec(napi_env env, void *data, ResultNapiType type)
6401 {
6402     MediaLibraryTracer tracer;
6403     tracer.Start("UpdateGalleryFormInfoExec");
6404 
6405     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6406     context->resultNapiType = type;
6407     vector<string> formIds;
6408     vector<string> fileUris;
6409     bool isValid = false;
6410     for (auto valueBucket : context->valuesBucketArray) {
6411         formIds.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, isValid));
6412         fileUris.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, isValid));
6413     }
6414     FormInfoReqBody reqBody;
6415     reqBody.formIds = formIds;
6416     reqBody.fileUris = fileUris;
6417     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::UPDATE_GALLERY_FORM_INFO);
6418     NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
6419     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6420     NAPI_INFO_LOG("after IPC::UserDefineIPCClient().Call");
6421     if (ret < 0) {
6422         if (ret == E_PERMISSION_DENIED) {
6423             context->error = OHOS_PERMISSION_DENIED_CODE;
6424         } else if (ret == E_GET_PRAMS_FAIL) {
6425             context->error = OHOS_INVALID_PARAM_CODE;
6426         } else {
6427             context->SaveError(ret);
6428         }
6429         NAPI_INFO_LOG("store formInfo failed, ret: %{public}d", ret);
6430     }
6431 }
6432 
RemoveGalleryFormInfoExec(napi_env env,void * data,ResultNapiType type)6433 static void RemoveGalleryFormInfoExec(napi_env env, void *data, ResultNapiType type)
6434 {
6435     MediaLibraryTracer tracer;
6436     tracer.Start("RemoveGalleryFormInfoExec");
6437 
6438     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6439     context->resultNapiType = type;
6440     string formId = context->formId;
6441     if (formId.empty()) {
6442         context->error = OHOS_INVALID_PARAM_CODE;
6443         return;
6444     }
6445     FormInfoReqBody reqBody;
6446     reqBody.formIds.emplace_back(formId);
6447     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::REMOVE_GALLERY_FORM_INFO);
6448     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6449     if (ret < 0) {
6450         if (ret == E_PERMISSION_DENIED) {
6451             context->error = OHOS_PERMISSION_DENIED_CODE;
6452         } else {
6453             context->SaveError(ret);
6454         }
6455         NAPI_ERR_LOG("remove formInfo failed, ret: %{public}d", ret);
6456     }
6457 }
6458 
RemoveFormInfoExec(napi_env env,void * data,ResultNapiType type)6459 static void RemoveFormInfoExec(napi_env env, void *data, ResultNapiType type)
6460 {
6461     MediaLibraryTracer tracer;
6462     tracer.Start("RemoveFormInfoExec");
6463 
6464     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6465     context->resultNapiType = type;
6466     string formId = context->formId;
6467     if (formId.empty()) {
6468         context->error = OHOS_INVALID_PARAM_CODE;
6469         return;
6470     }
6471     FormInfoReqBody reqBody;
6472     reqBody.formIds.emplace_back(formId);
6473     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::REMOVE_FORM_INFO);
6474     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6475     if (ret < 0) {
6476         if (ret == E_PERMISSION_DENIED) {
6477             context->error = OHOS_PERMISSION_DENIED_CODE;
6478         } else {
6479             context->SaveError(ret);
6480         }
6481         NAPI_ERR_LOG("remove formInfo failed, ret: %{public}d", ret);
6482     }
6483 }
6484 
RemoveFormInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)6485 static void RemoveFormInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
6486 {
6487     MediaLibraryTracer tracer;
6488     tracer.Start("RemoveFormInfoAsyncCallbackComplete");
6489 
6490     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6491     auto jsContext = make_unique<JSAsyncContextOutput>();
6492     jsContext->status = false;
6493     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6494     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6495     if (context->error != ERR_DEFAULT) {
6496         context->HandleError(env, jsContext->error);
6497     } else {
6498         jsContext->status = true;
6499     }
6500     tracer.Finish();
6501     if (context->work != nullptr) {
6502         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6503                                                    context->work, *jsContext);
6504     }
6505     delete context;
6506 }
6507 
PhotoAccessSaveFormInfoExec(napi_env env,void * data)6508 static void PhotoAccessSaveFormInfoExec(napi_env env, void *data)
6509 {
6510     SaveFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6511 }
6512 
PhotoAccessSaveFormInfo(napi_env env,napi_callback_info info)6513 napi_value MediaLibraryNapi::PhotoAccessSaveFormInfo(napi_env env, napi_callback_info info)
6514 {
6515     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6516     CHECK_NULLPTR_RET(ParseArgsSaveFormInfo(env, info, asyncContext));
6517 
6518     SetUserIdFromObjectInfo(asyncContext);
6519     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessSaveFormInfo",
6520         PhotoAccessSaveFormInfoExec, SaveFormInfoAsyncCallbackComplete);
6521 }
6522 
PhotoAccessSaveGalleryFormInfoExec(napi_env env,void * data)6523 static void PhotoAccessSaveGalleryFormInfoExec(napi_env env, void *data)
6524 {
6525     SaveGalleryFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6526 }
6527 
PhotoAccessSaveGalleryFormInfo(napi_env env,napi_callback_info info)6528 napi_value MediaLibraryNapi::PhotoAccessSaveGalleryFormInfo(napi_env env, napi_callback_info info)
6529 {
6530     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6531     CHECK_NULLPTR_RET(ParseArgsSaveGalleryFormInfo(env, info, asyncContext));
6532 
6533     SetUserIdFromObjectInfo(asyncContext);
6534     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessSaveGalleryFormInfo",
6535         PhotoAccessSaveGalleryFormInfoExec, SaveFormInfoAsyncCallbackComplete);
6536 }
6537 
PhotoAccessRemoveFormInfoExec(napi_env env,void * data)6538 static void PhotoAccessRemoveFormInfoExec(napi_env env, void *data)
6539 {
6540     RemoveFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6541 }
6542 
PhotoAccessRemoveGalleryFormInfoExec(napi_env env,void * data)6543 static void PhotoAccessRemoveGalleryFormInfoExec(napi_env env, void *data)
6544 {
6545     RemoveGalleryFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6546 }
6547 
PhotoAccessUpdateGalleryFormInfoExec(napi_env env,void * data)6548 static void PhotoAccessUpdateGalleryFormInfoExec(napi_env env, void *data)
6549 {
6550     UpdateGalleryFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6551 }
6552 
PhotoAccessRemoveGalleryFormInfo(napi_env env,napi_callback_info info)6553 napi_value MediaLibraryNapi::PhotoAccessRemoveGalleryFormInfo(napi_env env, napi_callback_info info)
6554 {
6555     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6556     CHECK_NULLPTR_RET(ParseArgsRemoveGalleryFormInfo(env, info, asyncContext));
6557 
6558     SetUserIdFromObjectInfo(asyncContext);
6559     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveGalleryFormInfo",
6560         PhotoAccessRemoveGalleryFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
6561 }
6562 
PhotoAccessUpdateGalleryFormInfo(napi_env env,napi_callback_info info)6563 napi_value MediaLibraryNapi::PhotoAccessUpdateGalleryFormInfo(napi_env env, napi_callback_info info)
6564 {
6565     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6566     CHECK_NULLPTR_RET(ParseArgsUpdateGalleryFormInfo(env, info, asyncContext));
6567 
6568     SetUserIdFromObjectInfo(asyncContext);
6569     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveGalleryFormInfo",
6570         PhotoAccessUpdateGalleryFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
6571 }
6572 
PhotoAccessRemoveFormInfo(napi_env env,napi_callback_info info)6573 napi_value MediaLibraryNapi::PhotoAccessRemoveFormInfo(napi_env env, napi_callback_info info)
6574 {
6575     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6576     CHECK_NULLPTR_RET(ParseArgsRemoveFormInfo(env, info, asyncContext));
6577 
6578     SetUserIdFromObjectInfo(asyncContext);
6579     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveFormInfo",
6580         PhotoAccessRemoveFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
6581 }
6582 
ParseArgsStartCreateThumbnailTask(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6583 static napi_value ParseArgsStartCreateThumbnailTask(napi_env env,
6584     napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
6585 {
6586     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6587         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6588         return nullptr;
6589     }
6590 
6591     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
6592         env, info, context, ARGS_TWO, ARGS_TWO), JS_ERR_PARAMETER_INVALID);
6593     CHECK_COND_WITH_MESSAGE(env, context->callbackRef, "Can not get callback function");
6594     CHECK_ARGS(env, MediaLibraryNapiUtils::ParsePredicates(env,
6595         context->argv[PARAM0], context, ASSET_FETCH_OPT), JS_INNER_FAIL);
6596 
6597     napi_value result = nullptr;
6598     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6599     return result;
6600 }
6601 
RegisterThumbnailGenerateObserver(napi_env env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)6602 static void RegisterThumbnailGenerateObserver(napi_env env,
6603     std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
6604 {
6605     std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
6606     if (thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
6607         NAPI_INFO_LOG("RequestId: %{public}d exist in observer map, no need to register", requestId);
6608         return;
6609     }
6610     dataObserver = std::make_shared<ThumbnailBatchGenerateObserver>();
6611     std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
6612     UserFileClient::RegisterObserverExt(Uri(observerUri), dataObserver, false);
6613     thumbnailGenerateObserverMap.Insert(requestId, dataObserver);
6614 }
6615 
UnregisterThumbnailGenerateObserver(int32_t requestId)6616 static void UnregisterThumbnailGenerateObserver(int32_t requestId)
6617 {
6618     std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
6619     if (!thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
6620         return;
6621     }
6622 
6623     std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
6624     UserFileClient::UnregisterObserverExt(Uri(observerUri), dataObserver);
6625     thumbnailGenerateObserverMap.Erase(requestId);
6626 }
6627 
DeleteThumbnailHandler(int32_t requestId)6628 static void DeleteThumbnailHandler(int32_t requestId)
6629 {
6630     std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6631     if (!thumbnailGenerateHandlerMap.Find(requestId, dataHandler)) {
6632         return;
6633     }
6634     napi_release_threadsafe_function(dataHandler->threadSafeFunc_, napi_tsfn_release);
6635     thumbnailGenerateHandlerMap.Erase(requestId);
6636 }
6637 
ReleaseThumbnailTask(int32_t requestId)6638 static void ReleaseThumbnailTask(int32_t requestId)
6639 {
6640     UnregisterThumbnailGenerateObserver(requestId);
6641     DeleteThumbnailHandler(requestId);
6642 }
6643 
CreateThumbnailHandler(napi_env env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)6644 static void CreateThumbnailHandler(napi_env env,
6645     std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
6646 {
6647     napi_value workName = nullptr;
6648     napi_create_string_utf8(env, "ThumbSafeThread", NAPI_AUTO_LENGTH, &workName);
6649     napi_threadsafe_function threadSafeFunc;
6650     napi_status status = napi_create_threadsafe_function(env, asyncContext->argv[PARAM1], NULL, workName, 0, 1,
6651         NULL, NULL, NULL, MediaLibraryNapi::OnThumbnailGenerated, &threadSafeFunc);
6652     if (status != napi_ok) {
6653         NAPI_ERR_LOG("napi_create_threadsafe_function fail");
6654         ReleaseThumbnailTask(requestId);
6655         asyncContext->SaveError(JS_INNER_FAIL);
6656         return;
6657     }
6658     std::shared_ptr<ThumbnailGenerateHandler> dataHandler =
6659         std::make_shared<ThumbnailGenerateHandler>(asyncContext->callbackRef, threadSafeFunc);
6660     thumbnailGenerateHandlerMap.Insert(requestId, dataHandler);
6661 }
6662 
OnThumbnailGenerated(napi_env env,napi_value cb,void * context,void * data)6663 void MediaLibraryNapi::OnThumbnailGenerated(napi_env env, napi_value cb, void *context, void *data)
6664 {
6665     if (env == nullptr) {
6666         return;
6667     }
6668     std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6669     if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
6670         return;
6671     }
6672 
6673     napi_status status = napi_get_reference_value(env, dataHandler->callbackRef_, &cb);
6674     if (status != napi_ok) {
6675         NapiError::ThrowError(env, JS_INNER_FAIL, "napi_get_reference_value fail");
6676         return;
6677     }
6678 
6679     napi_value result = nullptr;
6680     status = napi_call_function(env, nullptr, cb, 0, nullptr, &result);
6681     if (status != napi_ok) {
6682         NapiError::ThrowError(env, JS_INNER_FAIL, "calling onDataPrepared failed");
6683     }
6684 }
6685 
AssignRequestId()6686 static int32_t AssignRequestId()
6687 {
6688     return ++requestIdCounter_;
6689 }
6690 
GetRequestId()6691 static int32_t GetRequestId()
6692 {
6693     return requestIdCounter_;
6694 }
6695 
PhotoAccessStartCreateThumbnailTask(napi_env env,napi_callback_info info)6696 napi_value MediaLibraryNapi::PhotoAccessStartCreateThumbnailTask(napi_env env, napi_callback_info info)
6697 {
6698     MediaLibraryTracer tracer;
6699     tracer.Start("PhotoAccessStartCreateThumbnailTask");
6700     std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
6701     CHECK_NULLPTR_RET(ParseArgsStartCreateThumbnailTask(env, info, asyncContext));
6702 
6703     ReleaseThumbnailTask(GetRequestId());
6704     int32_t requestId = AssignRequestId();
6705     RegisterThumbnailGenerateObserver(env, asyncContext, requestId);
6706     CreateThumbnailHandler(env, asyncContext, requestId);
6707 
6708     StartThumbnailCreationTaskReqBody reqBody;
6709     reqBody.predicates = asyncContext->predicates;
6710     reqBody.requestId = requestId;
6711     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_START_THUMBNAIL_CREATION_TASK);
6712     NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call, %{public}d", requestId);
6713     int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6714     NAPI_INFO_LOG("after IPC::UserDefineIPCClient().Call");
6715 
6716     napi_value result = nullptr;
6717     NAPI_CALL(env, napi_get_undefined(env, &result));
6718     if (changedRows < 0) {
6719         ReleaseThumbnailTask(requestId);
6720         asyncContext->SaveError(changedRows);
6721         NAPI_ERR_LOG("Create thumbnail task, update failed, err: %{public}d", changedRows);
6722         napi_create_int32(env, changedRows, &result);
6723         return result;
6724     }
6725     napi_create_int32(env, requestId, &result);
6726     return result;
6727 }
6728 
OnChange(const ChangeInfo & changeInfo)6729 void ThumbnailBatchGenerateObserver::OnChange(const ChangeInfo &changeInfo)
6730 {
6731     if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_THUMB_UPDATE)) {
6732         return;
6733     }
6734 
6735     for (auto &uri : changeInfo.uris_) {
6736         string uriString = uri.ToString();
6737         auto pos = uriString.find_last_of('/');
6738         if (pos == std::string::npos) {
6739             continue;
6740         }
6741         if (!MediaFileUtils::IsValidInteger(uriString.substr(pos + 1))) {
6742             continue;
6743         }
6744         requestIdCallback_ = std::stoi(uriString.substr(pos + 1));
6745         std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6746         if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
6747             continue;
6748         }
6749 
6750         napi_status status = napi_acquire_threadsafe_function(dataHandler->threadSafeFunc_);
6751         if (status != napi_ok) {
6752             ReleaseThumbnailTask(requestIdCallback_);
6753             NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
6754             continue;
6755         }
6756         status = napi_call_threadsafe_function(dataHandler->threadSafeFunc_, NULL, napi_tsfn_blocking);
6757         if (status != napi_ok) {
6758             ReleaseThumbnailTask(requestIdCallback_);
6759             NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
6760             continue;
6761         }
6762     }
6763 }
6764 
ParseArgsStopCreateThumbnailTask(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6765 static napi_value ParseArgsStopCreateThumbnailTask(napi_env env,
6766     napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
6767 {
6768     if (!MediaLibraryNapiUtils::IsSystemApp()) {
6769         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6770         return nullptr;
6771     }
6772 
6773     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env,
6774         info, context, ARGS_ONE, ARGS_ONE), JS_ERR_PARAMETER_INVALID);
6775     napi_value result = nullptr;
6776     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6777     return result;
6778 }
6779 
PhotoAccessStopCreateThumbnailTask(napi_env env,napi_callback_info info)6780 napi_value MediaLibraryNapi::PhotoAccessStopCreateThumbnailTask(napi_env env, napi_callback_info info)
6781 {
6782     MediaLibraryTracer tracer;
6783     tracer.Start("PhotoAccessStopCreateThumbnailTask");
6784     std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
6785     CHECK_NULLPTR_RET(ParseArgsStopCreateThumbnailTask(env, info, asyncContext));
6786 
6787     int32_t requestId = 0;
6788     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetInt32(env,
6789         asyncContext->argv[PARAM0], requestId) == napi_ok, "Failed to get requestId");
6790     if (requestId <= 0) {
6791         NAPI_WARN_LOG("Invalid requestId: %{public}d", requestId);
6792         RETURN_NAPI_UNDEFINED(env);
6793     }
6794     ReleaseThumbnailTask(requestId);
6795 
6796     StopThumbnailCreationTaskReqBody reqBody;
6797     reqBody.requestId = requestId;
6798     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_STOP_THUMBNAIL_CREATION_TASK);
6799     NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
6800     int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6801     NAPI_INFO_LOG("after IPC::UserDefineIPCClient().Call");
6802     if (changedRows < 0) {
6803         asyncContext->SaveError(changedRows);
6804         NAPI_ERR_LOG("Stop create thumbnail task, update failed, err: %{public}d", changedRows);
6805     }
6806     RETURN_NAPI_UNDEFINED(env);
6807 }
6808 
GetMediaAnalysisServiceProgress(nlohmann::json & jsonObj,unordered_map<int,string> & idxToCount)6809 static void GetMediaAnalysisServiceProgress(nlohmann::json& jsonObj, unordered_map<int, string>& idxToCount)
6810 {
6811     int errCode = 0;
6812     GetAnalysisProcessReqBody reqBody;
6813     reqBody.analysisType = AnalysisType::ANALYSIS_LABEL;
6814     QueryResultRespBody respBody;
6815     errCode = IPC::UserDefineIPCClient().Call(
6816         static_cast<uint32_t>(MediaLibraryBusinessCode::GET_ANALYSIS_PROCESS), reqBody, respBody);
6817     shared_ptr<DataShare::DataShareResultSet> ret = respBody.resultSet;
6818     if (ret == nullptr) {
6819         NAPI_ERR_LOG("ret is nullptr");
6820         return;
6821     }
6822     if (ret->GoToFirstRow() != NativeRdb::E_OK) {
6823         NAPI_ERR_LOG("GotoFirstRow failed, errCode is %{public}d", errCode);
6824         ret->Close();
6825         return;
6826     }
6827     for (size_t i = 0; i < idxToCount.size(); ++i) {
6828         int tmp = -1;
6829         ret->GetInt(i, tmp);
6830         jsonObj[idxToCount[i]] = tmp;
6831     }
6832     ret->Close();
6833 }
6834 
GetLabelAnalysisProgress()6835 static std::string GetLabelAnalysisProgress()
6836 {
6837     unordered_map<int, string> idxToCount = {
6838         {0, "totalCount"}, {1, "finishedCount"}, {2, "LabelCount"}
6839     };
6840     nlohmann::json jsonObj;
6841     GetMediaAnalysisServiceProgress(jsonObj, idxToCount);
6842     NAPI_INFO_LOG("Progress json is %{public}s", jsonObj.dump().c_str());
6843     return jsonObj.dump();
6844 }
6845 
GetTotalCount()6846 static std::string GetTotalCount()
6847 {
6848     Uri uri(URI_TOTAL);
6849     string clause = VISION_TOTAL_TABLE + "." + MediaColumn::MEDIA_ID + " = " + PhotoColumn::PHOTOS_TABLE+ "." +
6850         MediaColumn::MEDIA_ID;
6851     DataShare::DataSharePredicates predicates;
6852     predicates.InnerJoin(PhotoColumn::PHOTOS_TABLE)->On({ clause });
6853     predicates.EqualTo(PhotoColumn::PHOTO_HIDDEN_TIME, 0)->And()
6854         ->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, 0)->And()
6855         ->EqualTo(MediaColumn::MEDIA_TIME_PENDING, 0);
6856 
6857     vector<string> column = {
6858         "SUM(CASE WHEN (media_type = 1 OR (media_type = 2 AND (position = 1 OR position = 3))) THEN 1 ELSE 0 END) AS "
6859             "totalCount"
6860     };
6861 
6862     int errCode = 0;
6863     shared_ptr<DataShare::DataShareResultSet> ret = UserFileClient::Query(uri, predicates, column, errCode);
6864     if (ret == nullptr) {
6865         NAPI_ERR_LOG("ret is nullptr");
6866         return "";
6867     }
6868     if (ret->GoToFirstRow() != NativeRdb::E_OK) {
6869         ret->Close();
6870         NAPI_ERR_LOG("GotoFirstRow failed, errCode is %{public}d", errCode);
6871         return "";
6872     }
6873     int totalCount = 0;
6874     ret->GetInt(0, totalCount);
6875     ret->Close();
6876     return to_string(totalCount);
6877 }
6878 
GetFaceAnalysisProgress()6879 static std::string GetFaceAnalysisProgress()
6880 {
6881     string curTotalCount = GetTotalCount();
6882 
6883     int errCode = 0;
6884     GetAnalysisProcessReqBody reqBody;
6885     reqBody.analysisType = AnalysisType::ANALYSIS_FACE;
6886     QueryResultRespBody respBody;
6887     errCode = IPC::UserDefineIPCClient().Call(
6888         static_cast<uint32_t>(MediaLibraryBusinessCode::GET_ANALYSIS_PROCESS), reqBody, respBody);
6889     shared_ptr<DataShare::DataShareResultSet> ret = respBody.resultSet;
6890     if (ret == nullptr) {
6891         NAPI_ERR_LOG("ret is nullptr");
6892         return "";
6893     }
6894     if (ret->GoToNextRow() != NativeRdb::E_OK) {
6895         ret->Close();
6896         nlohmann::json jsonObj;
6897         jsonObj["cvFinishedCount"] = 0;
6898         jsonObj["geoFinishedCount"] = 0;
6899         jsonObj["searchFinishedCount"] = 0;
6900         jsonObj["totalCount"] = curTotalCount;
6901         string retJson = jsonObj.dump();
6902         NAPI_ERR_LOG("GetFaceAnalysisProgress failed, errCode is %{public}d, json is %{public}s", errCode,
6903             retJson.c_str());
6904         return retJson;
6905     }
6906     string retJson = MediaLibraryNapiUtils::GetStringValueByColumn(ret, HIGHLIGHT_ANALYSIS_PROGRESS);
6907     if (retJson == "" || !nlohmann::json::accept(retJson)) {
6908         ret->Close();
6909         NAPI_ERR_LOG("retJson is empty or invalid");
6910         return "";
6911     }
6912     nlohmann::json curJsonObj = nlohmann::json::parse(retJson);
6913     int preTotalCount = curJsonObj["totalCount"];
6914     if (to_string(preTotalCount) != curTotalCount) {
6915         NAPI_ERR_LOG("preTotalCount != curTotalCount, curTotalCount is %{public}s, preTotalCount is %{public}d",
6916             curTotalCount.c_str(), preTotalCount);
6917         curJsonObj["totalCount"] = curTotalCount;
6918     }
6919     retJson = curJsonObj.dump();
6920     NAPI_INFO_LOG("GoToNextRow successfully and json is %{public}s", retJson.c_str());
6921     ret->Close();
6922     return retJson;
6923 }
6924 
GetHighlightAnalysisProgress()6925 static std::string GetHighlightAnalysisProgress()
6926 {
6927     unordered_map<int, string> idxToCount = {
6928         {0, "ClearCount"}, {1, "DeleteCount"}, {2, "NotProduceCount"}, {3, "ProduceCount"}, {4, "PushCount"}
6929     };
6930     int errCode = 0;
6931     GetAnalysisProcessReqBody reqBody;
6932     reqBody.analysisType = AnalysisType::ANALYSIS_HIGHLIGHT;
6933     QueryResultRespBody respBody;
6934     errCode = IPC::UserDefineIPCClient().Call(
6935         static_cast<uint32_t>(MediaLibraryBusinessCode::GET_ANALYSIS_PROCESS), reqBody, respBody);
6936     shared_ptr<DataShare::DataShareResultSet> ret = respBody.resultSet;
6937     if (ret == nullptr) {
6938         NAPI_ERR_LOG("ret is nullptr");
6939         return "";
6940     }
6941     if (ret->GoToFirstRow() != NativeRdb::E_OK) {
6942         NAPI_ERR_LOG("GotoFirstRow failed, errCode is %{public}d", errCode);
6943         ret->Close();
6944         return "";
6945     }
6946     nlohmann::json jsonObj;
6947     for (size_t i = 0; i < idxToCount.size(); ++i) {
6948         int tmp = -1;
6949         ret->GetInt(i, tmp);
6950         jsonObj[idxToCount[i]] = tmp;
6951     }
6952     ret->Close();
6953     string retStr = jsonObj.dump();
6954     NAPI_INFO_LOG("Progress json is %{public}s", retStr.c_str());
6955     return retStr;
6956 }
6957 
JSGetAnalysisProgressExecute(MediaLibraryAsyncContext * context)6958 static void JSGetAnalysisProgressExecute(MediaLibraryAsyncContext* context)
6959 {
6960     MediaLibraryTracer tracer;
6961     tracer.Start("JSGetAnalysisProgressExecute");
6962     std::vector<std::string> fetchColumn;
6963     DataShare::DataSharePredicates predicates;
6964     switch (context->analysisType) {
6965         case ANALYSIS_LABEL: {
6966             context->analysisProgress = GetLabelAnalysisProgress();
6967             break;
6968         }
6969         case ANALYSIS_FACE: {
6970             context->analysisProgress = GetFaceAnalysisProgress();
6971             break;
6972         }
6973         case ANALYSIS_HIGHLIGHT: {
6974             context->analysisProgress = GetHighlightAnalysisProgress();
6975             break;
6976         }
6977         default:
6978             break;
6979     }
6980 }
6981 
JSGetDataAnalysisProgressCompleteCallback(napi_env env,napi_status status,void * data)6982 static void JSGetDataAnalysisProgressCompleteCallback(napi_env env, napi_status status, void *data)
6983 {
6984     MediaLibraryTracer tracer;
6985     tracer.Start("JSGetDataAnalysisProgressCompleteCallback");
6986     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
6987     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
6988     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
6989     jsContext->status = false;
6990     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6991     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6992     if (context->error == ERR_DEFAULT) {
6993         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, context->analysisProgress.c_str(),
6994             NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
6995         jsContext->status = true;
6996     } else {
6997         context->HandleError(env, jsContext->error);
6998     }
6999     tracer.Finish();
7000     if (context->work != nullptr) {
7001         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work,
7002             *jsContext);
7003     }
7004     delete context;
7005 }
7006 
PhotoAccessHelperGetDataAnalysisProgress(napi_env env,napi_callback_info info)7007 napi_value MediaLibraryNapi::PhotoAccessHelperGetDataAnalysisProgress(napi_env env, napi_callback_info info)
7008 {
7009     MediaLibraryTracer tracer;
7010     tracer.Start("PhotoAccessHelperGetDataAnalysisProgress");
7011 
7012     napi_value result = nullptr;
7013     NAPI_CALL(env, napi_get_undefined(env, &result));
7014     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7015     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
7016     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7017     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->analysisType),
7018         JS_ERR_PARAMETER_INVALID);
7019 
7020     SetUserIdFromObjectInfo(asyncContext);
7021     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetDataAnalysisProgress",
7022         [](napi_env env, void *data) {
7023             auto context = static_cast<MediaLibraryAsyncContext*>(data);
7024             JSGetAnalysisProgressExecute(context);
7025         }, reinterpret_cast<CompleteCallback>(JSGetDataAnalysisProgressCompleteCallback));
7026 }
7027 
JSGetAnalysisDataCompleteCallback(napi_env env,napi_status status,void * data)7028 static void JSGetAnalysisDataCompleteCallback(napi_env env, napi_status status, void *data)
7029 {
7030     MediaLibraryTracer tracer;
7031     tracer.Start("JSGetAnalysisDataCompleteCallback");
7032 
7033     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
7034     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
7035 
7036     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7037     jsContext->status = false;
7038 
7039     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7040     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7041     if (context->error == ERR_DEFAULT) {
7042         napi_value returnArray;
7043         napi_create_array(env, &returnArray);
7044         for (size_t i = 0; i < context->analysisDatas.size(); ++i) {
7045             napi_value element;
7046             napi_create_string_utf8(env, context->analysisDatas[i].c_str(), NAPI_AUTO_LENGTH, &element);
7047             napi_set_element(env, returnArray, i, element);
7048         }
7049         jsContext->data = returnArray;
7050         jsContext->status = true;
7051     } else {
7052         context->HandleError(env, jsContext->error);
7053     }
7054 
7055     tracer.Finish();
7056     if (context->work != nullptr) {
7057         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7058                                                    context->work, *jsContext);
7059     }
7060     delete context;
7061 }
7062 
JSGetAnalysisDataExecute(napi_env env,MediaLibraryAsyncContext * context)7063 static void JSGetAnalysisDataExecute(napi_env env, MediaLibraryAsyncContext *context)
7064 {
7065     MediaLibraryTracer tracer;
7066     tracer.Start("JSGetAnalysisDataExecute");
7067 
7068     std::string analysisUri;
7069     if (context->isForce) {
7070         analysisUri = PAH_QUERY_ANA_ADDRESS_ASSETS_ACTIVE;
7071     } else {
7072         analysisUri = PAH_QUERY_ANA_ADDRESS_ASSETS;
7073     }
7074     Uri uri(analysisUri);
7075     DataSharePredicates predicates;
7076     vector<string> columns;
7077 
7078     if (context->analysisType == ANALYSIS_DETAIL_ADDRESS) {
7079         columns = { PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, PhotoColumn::PHOTOS_TABLE + "." + LATITUDE,
7080             PhotoColumn::PHOTOS_TABLE + "." + LONGITUDE, LANGUAGE, COUNTRY, ADMIN_AREA, SUB_ADMIN_AREA, LOCALITY,
7081             SUB_LOCALITY, THOROUGHFARE, SUB_THOROUGHFARE, FEATURE_NAME, CITY_NAME, ADDRESS_DESCRIPTION, LOCATION_TYPE,
7082             AOI, POI, FIRST_AOI, FIRST_POI, LOCATION_VERSION, FIRST_AOI_CATEGORY, FIRST_POI_CATEGORY};
7083         string language = Global::I18n::LocaleConfig::GetSystemLanguage();
7084         //Chinese and English supported. Other languages English default.
7085         language = (language.find(LANGUAGE_ZH) == 0 || language.find(LANGUAGE_ZH_TR) == 0) ? LANGUAGE_ZH : LANGUAGE_EN;
7086         vector<string> onClause = { PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::MEDIA_ID + " = " +
7087             GEO_KNOWLEDGE_TABLE + "." + FILE_ID + " AND " +
7088             GEO_KNOWLEDGE_TABLE + "." + LANGUAGE + " = \'" + language + "\'" };
7089         predicates.LeftOuterJoin(GEO_KNOWLEDGE_TABLE)->On(onClause);
7090         predicates.In(PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, context->uris);
7091     } else {
7092         predicates.In(MediaColumn::MEDIA_ID, context->uris);
7093     }
7094 
7095     int errCode = 0;
7096     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode,
7097         context->userId);
7098     if (resultSet == nullptr) {
7099         NAPI_ERR_LOG("Query geo assets list failed");
7100         return;
7101     }
7102     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
7103         nlohmann::json jsonObject;
7104         for (uint32_t i = 0; i < columns.size(); i++) {
7105             string columnName = columns[i];
7106             auto it = NEED_COMPATIBLE_COLUMN_MAP.find(context->analysisType);
7107             if (it != NEED_COMPATIBLE_COLUMN_MAP.end() && columnName == it->second) {
7108                 jsonObject[columnName] = MediaLibraryNapiUtils::ParseColumnNeedCompatible(resultSet,
7109                     context->analysisType, columnName);
7110             } else {
7111                 jsonObject[columnName] = MediaLibraryNapiUtils::GetStringValueByColumn(resultSet, columnName);
7112             }
7113         }
7114         context->analysisDatas.push_back(jsonObject.dump());
7115     }
7116 }
7117 
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)7118 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
7119 {
7120     bool isArray = false;
7121     CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
7122     if (!isArray) {
7123         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array type");
7124         return nullptr;
7125     }
7126 
7127     uint32_t len = 0;
7128     CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
7129     if (len <= 0) {
7130         NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
7131         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array length");
7132         return nullptr;
7133     }
7134 
7135     for (uint32_t i = 0; i < len; i++) {
7136         napi_value asset = nullptr;
7137         CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
7138         if (asset == nullptr) {
7139             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset element");
7140             return nullptr;
7141         }
7142 
7143         FileAssetNapi *obj = nullptr;
7144         CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
7145         if (obj == nullptr) {
7146             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset napi object");
7147             return nullptr;
7148         }
7149         if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
7150             NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
7151             continue;
7152         }
7153         assetsArray.push_back(to_string(obj->GetFileId()));
7154     }
7155 
7156     napi_value result = nullptr;
7157     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7158     return result;
7159 }
7160 
ParseArgsStartAssetAnalysis(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7161 static napi_value ParseArgsStartAssetAnalysis(napi_env env, napi_callback_info info,
7162     unique_ptr<MediaLibraryAsyncContext> &context)
7163 {
7164     constexpr size_t minArgs = ARGS_ONE;
7165     constexpr size_t maxArgs = ARGS_TWO;
7166     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
7167         maxArgs) == napi_ok, "Failed to get object info");
7168 
7169     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7170         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7171         return nullptr;
7172     }
7173 
7174     // Parse analysis type
7175     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_ZERO],
7176         context->analysisType) == napi_ok, "analysisType invalid");
7177     CHECK_COND_WITH_MESSAGE(env, context->analysisType > AnalysisType::ANALYSIS_INVALID,
7178         "analysisType invalid:" + std::to_string(context->analysisType));
7179     CHECK_COND_WITH_MESSAGE(env,
7180         FOREGROUND_ANALYSIS_ASSETS_MAP.find(context->analysisType) != FOREGROUND_ANALYSIS_ASSETS_MAP.end(),
7181         "analysisType is not supported:" + std::to_string(context->analysisType));
7182 
7183     // Parse asset uris
7184     if (context->argc == ARGS_TWO) {
7185         vector<string> uris;
7186         CHECK_ARGS(env, MediaLibraryNapiUtils::GetStringArray(env, context->argv[ARGS_ONE], uris),
7187             OHOS_INVALID_PARAM_CODE);
7188         for (const auto &uri : uris) {
7189             if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
7190                 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check uri format, not a photo uri!");
7191                 return nullptr;
7192             }
7193         }
7194         if (!uris.empty()) {
7195             context->uris = uris;
7196         }
7197     } else if (context->argc == ARGS_ONE) {
7198         context->isFullAnalysis = true;
7199     }
7200 
7201     if (context->objectInfo) {
7202         context->userId = context->objectInfo->GetUserId();
7203     } else {
7204         NAPI_ERR_LOG("objectInfo is nullptr.");
7205     }
7206 
7207     napi_value result = nullptr;
7208     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7209     return result;
7210 }
7211 
JSStartAssetAnalysisCallback(napi_env env,napi_status status,void * data)7212 static void JSStartAssetAnalysisCallback(napi_env env, napi_status status, void *data)
7213 {
7214     MediaLibraryTracer tracer;
7215     tracer.Start("JSStartAssetAnalysisCallback");
7216 
7217     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
7218     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
7219 
7220     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7221     jsContext->status = false;
7222 
7223     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7224     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7225 
7226     if (context->error == ERR_DEFAULT) {
7227         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->taskId, &jsContext->data), JS_INNER_FAIL);
7228         jsContext->status = true;
7229     } else {
7230         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, -1, &jsContext->data), JS_INNER_FAIL);
7231         context->HandleError(env, jsContext->error);
7232     }
7233 
7234     tracer.Finish();
7235     if (context->work != nullptr) {
7236         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7237             context->work, *jsContext);
7238     }
7239     delete context;
7240 }
7241 
ParseArgsAnalysisData(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7242 static napi_value ParseArgsAnalysisData(napi_env env, napi_callback_info info,
7243     unique_ptr<MediaLibraryAsyncContext> &context)
7244 {
7245     constexpr size_t minArgs = ARGS_ONE;
7246     constexpr size_t maxArgs = ARGS_THREE;
7247     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
7248         napi_ok, "Failed to get object info");
7249 
7250     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7251         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7252         return nullptr;
7253     }
7254 
7255     // Parse analysis type
7256     CHECK_ARGS(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_ZERO], context->analysisType),
7257         JS_ERR_PARAMETER_INVALID);
7258 
7259     // Parse asset uris
7260     vector<string> uris;
7261     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[ARGS_ONE], uris));
7262     if (uris.empty()) {
7263         NAPI_ERR_LOG("Geo assets list empty");
7264         return nullptr;
7265     }
7266     context->uris = uris;
7267 
7268     //Parse isForce
7269     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[ARGS_TWO], context->isForce),
7270         JS_ERR_PARAMETER_INVALID);
7271 
7272     napi_value result = nullptr;
7273     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7274     return result;
7275 }
7276 
PhotoAccessHelperGetAnalysisData(napi_env env,napi_callback_info info)7277 napi_value MediaLibraryNapi::PhotoAccessHelperGetAnalysisData(napi_env env, napi_callback_info info)
7278 {
7279     MediaLibraryTracer tracer;
7280     tracer.Start("PhotoAccessHelperGetAnalysisData");
7281 
7282     napi_value result = nullptr;
7283     NAPI_CALL(env, napi_get_undefined(env, &result));
7284     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7285     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
7286 
7287     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7288     CHECK_NULLPTR_RET(ParseArgsAnalysisData(env, info, asyncContext));
7289 
7290     SetUserIdFromObjectInfo(asyncContext);
7291     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetAnalysisData",
7292         [](napi_env env, void *data) {
7293             auto context = static_cast<MediaLibraryAsyncContext*>(data);
7294             JSGetAnalysisDataExecute(env, context);
7295         }, reinterpret_cast<CompleteCallback>(JSGetAnalysisDataCompleteCallback));
7296 }
7297 
JSGetPhotoAssets(napi_env env,napi_callback_info info)7298 napi_value MediaLibraryNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
7299 {
7300     MediaLibraryTracer tracer;
7301     tracer.Start("JSGetPhotoAssets");
7302 
7303     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7304     asyncContext->assetType = TYPE_PHOTO;
7305     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7306 
7307     SetUserIdFromObjectInfo(asyncContext);
7308     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
7309         JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7310 }
7311 
7312 // Easter egg operation: query duplicate assets
EasterEgg(MediaLibraryAsyncContext * context)7313 static bool EasterEgg(MediaLibraryAsyncContext* context)
7314 {
7315     if (context->uri == URI_FIND_ALL_DUPLICATE_ASSETS) {
7316         context->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_ALL_DUPLICATE_ASSETS);
7317     } else if (context->uri == URI_FIND_ALL_DUPLICATE_ASSETS_TO_DELETE) {
7318         context->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_DUPLICATE_ASSETS_TO_DELETE);
7319     } else {
7320         return false;
7321     }
7322     if (!MediaLibraryNapiUtils::IsSystemApp()) {
7323         NAPI_ERR_LOG("Easter egg operation failed, target is not system app");
7324         return false;
7325     };
7326     bool isQueryCount = find(context->fetchColumn.begin(), context->fetchColumn.end(), MEDIA_COLUMN_COUNT)
7327         != context->fetchColumn.end();
7328     int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
7329     NAPI_INFO_LOG(
7330         "Easter egg operation start: %{public}s, is query count: %{public}d",
7331         context->businessCode == static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_ALL_DUPLICATE_ASSETS) ?
7332         "find all duplicate assets" : "find all duplicate assets to delete", isQueryCount);
7333 
7334     GetAssetsReqBody reqBody;
7335     reqBody.predicates = context->predicates;
7336     reqBody.columns = context->fetchColumn;
7337     GetAssetsRespBody respBody;
7338     int32_t errCode =
7339         IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
7340 
7341     if (errCode != E_OK || respBody.resultSet == nullptr) {
7342         context->SaveError(errCode);
7343         NAPI_ERR_LOG("Easter egg operation failed, errCode: %{public}d", errCode);
7344         return true;
7345     }
7346 
7347     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(respBody.resultSet));
7348     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7349     NAPI_INFO_LOG(
7350         "Easter egg operation end: %{public}s, is query count: %{public}d, cost time: %{public}" PRId64 "ms",
7351         context->businessCode == static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_ALL_DUPLICATE_ASSETS) ?
7352         "find all duplicate assets" : "find all duplicate assets to delete", isQueryCount,
7353         MediaFileUtils::UTCTimeMilliSeconds() - startTime);
7354     return true;
7355 }
7356 
PhotoAccessGetAssetsExecute(napi_env env,void * data)7357 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
7358 {
7359     MediaLibraryTracer tracer;
7360     tracer.Start("PhotoAccessGetAssetsExecute");
7361 
7362     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
7363     CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
7364 
7365     if (EasterEgg(context)) {
7366         return;
7367     }
7368     string queryUri = PAH_QUERY_PHOTO;
7369     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7370     Uri uri(queryUri);
7371     int errCode = 0;
7372     auto [accessSandbox, resultSet] = UserFileClient::QueryAccessibleViaSandBox(
7373         uri, context->predicates, context->fetchColumn, errCode, context->userId);
7374     if (accessSandbox) {
7375         if (resultSet == nullptr) {
7376             NAPI_ERR_LOG("QueryAccessibleViaSandBox failed, resultSet is nullptr");
7377         }
7378     } else {
7379         GetAssetsReqBody reqBody;
7380         reqBody.predicates = context->predicates;
7381         reqBody.columns = context->fetchColumn;
7382         reqBody.burstKey = context->burstKey;
7383         GetAssetsRespBody respBody;
7384         errCode = IPC::UserDefineIPCClient()
7385                       .SetUserId(context->userId)
7386                       .Call(context->businessCode, reqBody, respBody);
7387         if (errCode == E_OK) {
7388             resultSet = respBody.resultSet;
7389         } else {
7390             NAPI_ERR_LOG("UserDefineIPCClient Call failed, errCode is %{public}d", errCode);
7391         }
7392     }
7393 
7394     if (resultSet == nullptr) {
7395         NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
7396         context->SaveError(errCode);
7397         return;
7398     }
7399     tracer.Start("MakeFetchResult");
7400     context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
7401     tracer.Finish();
7402     context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7403     context->fetchFileResult->SetUserId(context->userId);
7404 }
7405 
PhotoAccessGetAssetsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)7406 static napi_value PhotoAccessGetAssetsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
7407 {
7408     auto context = &asyncContext;
7409     if (context->assetType != TYPE_PHOTO) {
7410         return nullptr;
7411     }
7412     string queryUri = PAH_QUERY_PHOTO;
7413     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7414     Uri uri(queryUri);
7415     int errCode = 0;
7416     RdbPredicates rdbPredicates = RdbDataShareAdapter::RdbUtils::ToPredicates(context->predicates, "Photos");
7417     NAPI_INFO_LOG("Predicates: %{public}s", rdbPredicates.ToString().c_str());
7418     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
7419         context->predicates, context->fetchColumn, errCode, context->userId);
7420     if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
7421         Uri queryWithUri(context->uri);
7422         resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
7423     }
7424     CHECK_NULLPTR_RET(resultSet);
7425     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
7426     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7427     fetchResult->SetUserId(context->userId);
7428     CHECK_NULLPTR_RET(fetchResult);
7429 
7430     std::vector<std::unique_ptr<FileAsset>> fileAssetArray;
7431     auto file = fetchResult->GetFirstObject();
7432     while (file != nullptr) {
7433         fileAssetArray.push_back(move(file));
7434         file = fetchResult->GetNextObject();
7435     }
7436     size_t len = fileAssetArray.size();
7437     napi_value jsFileArray = nullptr;
7438     napi_create_array_with_length(env, len, &jsFileArray);
7439     size_t i = 0;
7440     for (i = 0; i < len; i++) {
7441         fileAssetArray[i]->SetUserId(context->userId);
7442         napi_value jsFileAsset = FileAssetNapi::CreateFileAsset(env, fileAssetArray[i]);
7443         if ((jsFileAsset == nullptr) || (napi_set_element(env, jsFileArray, i, jsFileAsset) != napi_ok)) {
7444             NAPI_ERR_LOG("Failed to get file asset napi object");
7445             break;
7446         }
7447     }
7448     return (i == len) ? jsFileArray : nullptr;
7449 }
7450 
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)7451 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
7452 {
7453     MediaLibraryTracer tracer;
7454     tracer.Start("PhotoAccessGetPhotoAssets");
7455 
7456     NAPI_DEBUG_LOG("MediaLibraryNapi::PhotoAccessGetPhotoAssets start");
7457     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7458     asyncContext->assetType = TYPE_PHOTO;
7459     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7460     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GET_ASSETS);
7461 
7462     SetUserIdFromObjectInfo(asyncContext);
7463     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
7464         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7465 }
7466 
PhotoAccessGetBurstAssets(napi_env env,napi_callback_info info)7467 napi_value MediaLibraryNapi::PhotoAccessGetBurstAssets(napi_env env, napi_callback_info info)
7468 {
7469     NAPI_INFO_LOG("MediaLibraryNapi::PhotoAccessGetBurstAssets start");
7470     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7471     asyncContext->assetType = TYPE_PHOTO;
7472     CHECK_NULLPTR_RET(ParseArgsGetBurstAssets(env, info, asyncContext));
7473     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::GET_BURST_ASSETS);
7474 
7475     SetUserIdFromObjectInfo(asyncContext);
7476     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
7477         PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7478 }
7479 
PhotoAccessGetFileAssetsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)7480 static napi_value PhotoAccessGetFileAssetsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
7481 {
7482     auto context = &asyncContext;
7483     if (context->assetType != TYPE_PHOTO) {
7484         return nullptr;
7485     }
7486     string queryUri = PAH_QUERY_PHOTO;
7487     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7488 
7489     Uri uri(queryUri);
7490     shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
7491         context->predicates, context->fetchColumn);
7492     CHECK_NULLPTR_RET(resultSet);
7493 
7494     napi_value jsFileArray = 0;
7495     napi_create_array(env, &jsFileArray);
7496 
7497     int count = 0;
7498     while (!resultSet->GoToNextRow()) {
7499         napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet);
7500         napi_set_element(env, jsFileArray, count++, item);
7501     }
7502     return jsFileArray;
7503 }
7504 
PhotoAccessGetFileAssetsInfo(napi_env env,napi_callback_info info)7505 napi_value MediaLibraryNapi::PhotoAccessGetFileAssetsInfo(napi_env env, napi_callback_info info)
7506 {
7507     unique_ptr<MediaLibraryAsyncContext> context = make_unique<MediaLibraryAsyncContext>();
7508     context->assetType = TYPE_PHOTO;
7509     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, context));
7510 
7511     return PhotoAccessGetFileAssetsExecuteSync(env, *context);
7512 }
7513 
PhotoAccessGetPhotoAssetsSync(napi_env env,napi_callback_info info)7514 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssetsSync(napi_env env, napi_callback_info info)
7515 {
7516     MediaLibraryTracer tracer;
7517     tracer.Start("PhotoAccessGetPhotoAssetsSync");
7518 
7519     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7520     asyncContext->assetType = TYPE_PHOTO;
7521     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7522     SetUserIdFromObjectInfo(asyncContext);
7523     return PhotoAccessGetAssetsExecuteSync(env, *asyncContext);
7524 }
7525 
JSGetAudioAssets(napi_env env,napi_callback_info info)7526 napi_value MediaLibraryNapi::JSGetAudioAssets(napi_env env, napi_callback_info info)
7527 {
7528     MediaLibraryTracer tracer;
7529     tracer.Start("JSGetAudioAssets");
7530 
7531     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7532     asyncContext->assetType = TYPE_AUDIO;
7533     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7534 
7535     SetUserIdFromObjectInfo(asyncContext);
7536     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAudioAssets",
7537         JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7538 }
7539 
GetPhotoAlbumMap(napi_env env,std::unordered_map<int32_t,unique_ptr<PhotoAlbum>> fileResult)7540 static napi_value GetPhotoAlbumMap(napi_env env, std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> fileResult)
7541 {
7542     napi_status status;
7543     napi_value mapNapiValue {nullptr};
7544     status = napi_create_map(env, &mapNapiValue);
7545     CHECK_COND_RET(status == napi_ok && mapNapiValue != nullptr, nullptr,
7546         "Failed to create map napi value, napi status: %{public}d", static_cast<int>(status));
7547 
7548     NAPI_INFO_LOG("PhotoAlbumMap size: %{public}d", static_cast<int32_t>(fileResult.size()));
7549     for (auto &iter : fileResult) {
7550         napi_value albumId {nullptr};
7551         status = napi_create_int32(env, iter.first, &albumId);
7552         CHECK_COND_RET(status == napi_ok && albumId != nullptr, nullptr,
7553             "Failed to create album id, napi status: %{public}d", static_cast<int>(status));
7554         napi_value albumPhoto = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, iter.second);
7555         status = napi_map_set_property(env, mapNapiValue, albumId, albumPhoto);
7556         CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set albumMap, napi status: %{public}d",
7557             static_cast<int>(status));
7558     }
7559     return mapNapiValue;
7560 }
7561 
GetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)7562 static void GetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
7563     unique_ptr<JSAsyncContextOutput> &jsContext)
7564 {
7565     napi_value fileResult;
7566     if (context->albumIds.empty()) {
7567         fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
7568     } else {
7569         fileResult = GetPhotoAlbumMap(env, move(context->albumMap));
7570     }
7571     if (fileResult == nullptr) {
7572         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7573         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
7574             "Failed to create js object for Fetch Album Result");
7575         return;
7576     }
7577     jsContext->data = fileResult;
7578     jsContext->status = true;
7579     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7580 }
7581 
SetPhotoAlbum(PhotoAlbum * photoAlbumData,shared_ptr<DataShareResultSet> & resultSet)7582 static void SetPhotoAlbum(PhotoAlbum* photoAlbumData, shared_ptr<DataShareResultSet> &resultSet)
7583 {
7584     int32_t albumId = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
7585         TYPE_INT32));
7586     photoAlbumData->SetAlbumId(albumId);
7587     photoAlbumData->SetPhotoAlbumType(static_cast<PhotoAlbumType>(
7588         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
7589     photoAlbumData->SetPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(
7590         get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
7591     photoAlbumData->SetLPath(get<string>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_LPATH, resultSet,
7592         TYPE_STRING)));
7593     photoAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_NAME,
7594         resultSet, TYPE_STRING)));
7595     photoAlbumData->SetDateAdded(get<int64_t>(ResultSetUtils::GetValFromColumn(
7596         PhotoAlbumColumns::ALBUM_DATE_ADDED, resultSet, TYPE_INT64)));
7597     photoAlbumData->SetDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(
7598         PhotoAlbumColumns::ALBUM_DATE_MODIFIED, resultSet, TYPE_INT64)));
7599     photoAlbumData->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7600 
7601     string countColumn = PhotoAlbumColumns::ALBUM_COUNT;
7602     string coverColumn = PhotoAlbumColumns::ALBUM_COVER_URI;
7603     string albumUriPrefix = PhotoAlbumColumns::ALBUM_URI_PREFIX;
7604     string coverUriSource = PhotoAlbumColumns::COVER_URI_SOURCE;
7605     photoAlbumData->SetAlbumUri(albumUriPrefix + to_string(albumId));
7606     photoAlbumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(countColumn, resultSet, TYPE_INT32)));
7607     photoAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(coverColumn, resultSet, TYPE_STRING)));
7608     photoAlbumData->SetCoverUriSource(get<int32_t>(ResultSetUtils::GetValFromColumn(coverUriSource, resultSet, TYPE_INT32)));
7609 
7610     // Albums of hidden types (except hidden album itself) don't support image count and video count,
7611     // return -1 instead
7612     int32_t imageCount = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT,
7613         resultSet, TYPE_INT32));
7614     int32_t videoCount = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT,
7615         resultSet, TYPE_INT32));
7616     photoAlbumData->SetImageCount(imageCount);
7617     photoAlbumData->SetVideoCount(videoCount);
7618 }
7619 
BuildAlbumMap(std::unordered_map<int32_t,unique_ptr<PhotoAlbum>> & albumMap,shared_ptr<DataShareResultSet> resultSet)7620 static void BuildAlbumMap(std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> &albumMap,
7621     shared_ptr<DataShareResultSet> resultSet)
7622 {
7623     int32_t count = 0;
7624     auto ret = resultSet->GetRowCount(count);
7625     if (ret != NativeRdb::E_OK) {
7626         NAPI_ERR_LOG("get rdbstore failed");
7627         return;
7628     }
7629     if (count == 0) {
7630         NAPI_ERR_LOG("albumid not find");
7631         return;
7632     }
7633     NAPI_INFO_LOG("build album map size: %{public}d", count);
7634     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
7635         unique_ptr<PhotoAlbum> albumAssetPtr = make_unique<PhotoAlbum>();
7636         SetPhotoAlbum(albumAssetPtr.get(), resultSet);
7637         albumMap[albumAssetPtr->GetAlbumId()] = std::move(albumAssetPtr);
7638     }
7639 }
7640 
JSGetPhotoAlbumsExecute(napi_env env,void * data)7641 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
7642 {
7643     MediaLibraryTracer tracer;
7644     tracer.Start("JSGetPhotoAlbumsExecute");
7645 
7646     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7647     string queryUri;
7648     if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
7649         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7650             UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
7651     } else if (context->isAnalysisAlbum) {
7652         queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
7653             PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
7654     } else {
7655         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7656             UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
7657     }
7658     Uri uri(queryUri);
7659     int errCode = 0;
7660     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode,
7661         context->userId);
7662     if (resultSet == nullptr) {
7663         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
7664         if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
7665             context->SaveError(errCode);
7666         } else {
7667             context->SaveError(E_HAS_DB_ERROR);
7668         }
7669         return;
7670     }
7671 
7672     if (context->albumIds.empty()) {
7673         context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
7674         context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
7675         context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
7676         context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
7677             PhotoAlbumSubType::GEOGRAPHY_LOCATION);
7678         context->fetchPhotoAlbumResult->SetUserId(context->userId);
7679     } else {
7680         std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> albumMap;
7681         BuildAlbumMap(context->albumMap, resultSet);
7682     }
7683 }
7684 
JSGetPhotoAlbumsByIdsExecute(napi_env env,void * data)7685 static void JSGetPhotoAlbumsByIdsExecute(napi_env env, void *data)
7686 {
7687     MediaLibraryTracer tracer;
7688     tracer.Start("JSGetPhotoAlbumsByIdsExecute");
7689 
7690     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7691     GetAlbumsByIdsReqBody reqBody;
7692     GetAlbumsByIdsRespBody respBody;
7693     shared_ptr<DataShareResultSet> resultSet;
7694     reqBody.predicates = context->predicates;
7695     reqBody.columns = context->fetchColumn;
7696     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_QUERY_GET_ALBUMS_BY_IDS);
7697     int errCode = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
7698     resultSet = respBody.resultSet;
7699 
7700     if (resultSet == nullptr) {
7701         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
7702         if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
7703             context->SaveError(errCode);
7704         } else {
7705             context->SaveError(E_HAS_DB_ERROR);
7706         }
7707         return;
7708     }
7709 
7710     if (context->albumIds.empty()) {
7711         context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
7712         context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
7713         context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
7714         context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
7715             PhotoAlbumSubType::GEOGRAPHY_LOCATION);
7716         context->fetchPhotoAlbumResult->SetUserId(context->userId);
7717     } else {
7718         std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> albumMap;
7719         BuildAlbumMap(context->albumMap, resultSet);
7720     }
7721 }
7722 
JSGetPhotoAlbumsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)7723 static napi_value JSGetPhotoAlbumsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
7724 {
7725     auto context = &asyncContext;
7726     string queryUri;
7727     if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
7728         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7729             UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
7730     } else if (context->isAnalysisAlbum) {
7731         queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
7732             PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
7733     } else {
7734         queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7735             UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
7736     }
7737     Uri uri(queryUri);
7738     int errCode = 0;
7739     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode,
7740         context->userId);
7741     CHECK_NULLPTR_RET(resultSet);
7742 
7743     auto fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
7744     fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
7745     fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
7746     fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION);
7747     fetchPhotoAlbumResult->SetUserId(context->userId);
7748     context->photoAlbumData->SetUserId(context->userId);
7749     if (fetchPhotoAlbumResult->GetCount() <= 0) {
7750         return nullptr;
7751     }
7752     auto photoAlbum = fetchPhotoAlbumResult->GetFirstObject();
7753     CHECK_NULLPTR_RET(photoAlbum);
7754     return PhotoAlbumNapi::CreatePhotoAlbumNapi(env, photoAlbum);
7755 }
7756 
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)7757 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
7758 {
7759     MediaLibraryTracer tracer;
7760     tracer.Start("JSGetPhotoAlbumsCompleteCallback");
7761 
7762     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7763     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7764     jsContext->status = false;
7765     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7766     if (context->error == ERR_DEFAULT && context->albumMap.empty() && context->albumIds.size() > 0) {
7767         napi_status status;
7768         napi_value mapNapiValue {nullptr};
7769         status = napi_create_map(env, &mapNapiValue);
7770         if (status != napi_ok || mapNapiValue == nullptr) {
7771             CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7772             context->HandleError(env, jsContext->error);
7773         } else {
7774             jsContext->data = mapNapiValue;
7775             jsContext->status = true;
7776             CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7777         }
7778     } else if (context->error != ERR_DEFAULT  ||
7779         (context->fetchPhotoAlbumResult == nullptr && context->albumMap.empty())) {
7780         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7781         context->HandleError(env, jsContext->error);
7782     } else {
7783         GetPhotoAlbumQueryResult(env, context, jsContext);
7784     }
7785 
7786     tracer.Finish();
7787     if (context->work != nullptr) {
7788         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7789                                                    context->work, *jsContext);
7790     }
7791     delete context;
7792 }
7793 
JSGetPhotoAlbums(napi_env env,napi_callback_info info)7794 napi_value MediaLibraryNapi::JSGetPhotoAlbums(napi_env env, napi_callback_info info)
7795 {
7796     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7797     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext),
7798         JS_ERR_PARAMETER_INVALID);
7799     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7800 
7801     SetUserIdFromObjectInfo(asyncContext);
7802     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAlbums", JSGetPhotoAlbumsExecute,
7803         JSGetPhotoAlbumsCompleteCallback);
7804 }
7805 
UserFileMgrCreatePhotoAsset(napi_env env,napi_callback_info info)7806 napi_value MediaLibraryNapi::UserFileMgrCreatePhotoAsset(napi_env env, napi_callback_info info)
7807 {
7808     MediaLibraryTracer tracer;
7809     tracer.Start("UserFileMgrCreatePhotoAsset");
7810 
7811     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7812     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7813     asyncContext->assetType = TYPE_PHOTO;
7814     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
7815 
7816     SetUserIdFromObjectInfo(asyncContext);
7817     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreatePhotoAsset",
7818         JSCreateAssetExecute, JSCreateAssetCompleteCallback);
7819 }
7820 
UserFileMgrCreateAudioAsset(napi_env env,napi_callback_info info)7821 napi_value MediaLibraryNapi::UserFileMgrCreateAudioAsset(napi_env env, napi_callback_info info)
7822 {
7823     MediaLibraryTracer tracer;
7824     tracer.Start("UserFileMgrCreateAudioAsset");
7825 
7826     napi_value ret = nullptr;
7827     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7828     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
7829     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7830     asyncContext->assetType = TYPE_AUDIO;
7831     NAPI_ASSERT(env, ParseArgsCreateAudioAsset(env, info, asyncContext), "Failed to parse js args");
7832 
7833     SetUserIdFromObjectInfo(asyncContext);
7834     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAudioAsset",
7835         JSCreateAssetExecute, JSCreateAssetCompleteCallback);
7836 }
7837 
ParseArgsTrashAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7838 napi_value ParseArgsTrashAsset(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
7839 {
7840     string uri;
7841     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
7842         JS_ERR_PARAMETER_INVALID);
7843     if (uri.empty()) {
7844         NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
7845         return nullptr;
7846     }
7847     if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos &&
7848         uri.find(AudioColumn::AUDIO_URI_PREFIX) == string::npos) {
7849         NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo or audio uri");
7850         return nullptr;
7851     }
7852     context->uri = uri;
7853 
7854     napi_value result = nullptr;
7855     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7856     return result;
7857 }
7858 
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)7859 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
7860 {
7861     MediaLibraryTracer tracer;
7862     tracer.Start("UserFileMgrTrashAsset");
7863 
7864     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7865     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7866     CHECK_NULLPTR_RET(ParseArgsTrashAsset(env, info, asyncContext));
7867 
7868     SetUserIdFromObjectInfo(asyncContext);
7869     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
7870         JSTrashAssetCompleteCallback);
7871 }
7872 
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)7873 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
7874 {
7875     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7876     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7877     CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
7878 
7879     SetUserIdFromObjectInfo(asyncContext);
7880     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
7881         JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
7882 }
7883 
CreateMediaTypeEnum(napi_env env)7884 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
7885 {
7886     return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
7887 }
7888 
CreateKeyFrameThumbnailTypeEnum(napi_env env)7889 napi_value MediaLibraryNapi::CreateKeyFrameThumbnailTypeEnum(napi_env env)
7890 {
7891     const int32_t startIdx = 1;
7892     return CreateNumberEnumProperty(env, keyFrameThumbnailTypeEnum, sKeyFrameThumbnailTypeRef_, startIdx);
7893 }
7894 
CreateMediaTypeUserFileEnum(napi_env env)7895 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
7896 {
7897     const int32_t startIdx = 1;
7898     return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
7899 }
7900 
CreateDirectoryTypeEnum(napi_env env)7901 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
7902 {
7903     return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
7904 }
7905 
CreateVirtualAlbumTypeEnum(napi_env env)7906 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
7907 {
7908     return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
7909 }
7910 
CreatePrivateAlbumTypeEnum(napi_env env)7911 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
7912 {
7913     return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
7914 }
7915 
CreateHiddenPhotosDisplayModeEnum(napi_env env)7916 napi_value MediaLibraryNapi::CreateHiddenPhotosDisplayModeEnum(napi_env env)
7917 {
7918     return CreateNumberEnumProperty(env, HIDDEN_PHOTOS_DISPLAY_MODE_ENUM, sHiddenPhotosDisplayModeEnumRef_);
7919 }
7920 
CreateFileKeyEnum(napi_env env)7921 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
7922 {
7923     return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
7924 }
7925 
UserFileMgrCreateFileKeyEnum(napi_env env)7926 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
7927 {
7928     return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
7929 }
7930 
CreateAudioKeyEnum(napi_env env)7931 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
7932 {
7933     return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
7934 }
7935 
CreateImageVideoKeyEnum(napi_env env)7936 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
7937 {
7938     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
7939 }
7940 
CreatePhotoKeysEnum(napi_env env)7941 napi_value MediaLibraryNapi::CreatePhotoKeysEnum(napi_env env)
7942 {
7943     return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sPhotoKeysEnumRef_);
7944 }
7945 
CreateAlbumKeyEnum(napi_env env)7946 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
7947 {
7948     return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
7949 }
7950 
CreateImageFileTypeEnum(napi_env env)7951 napi_value MediaLibraryNapi::CreateImageFileTypeEnum(napi_env env)
7952 {
7953     const int32_t startIdx = 1;
7954     return CreateNumberEnumProperty(env, imageFileTypeEnum, sImageFileTypeEnumEnumRef_, startIdx);
7955 }
7956 
CreateAlbumTypeEnum(napi_env env)7957 napi_value MediaLibraryNapi::CreateAlbumTypeEnum(napi_env env)
7958 {
7959     napi_value result = nullptr;
7960     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
7961 
7962     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
7963     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
7964     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SMART", PhotoAlbumType::SMART), JS_INNER_FAIL);
7965     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE", PhotoAlbumType::SOURCE), JS_INNER_FAIL);
7966 
7967     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
7968     return result;
7969 }
7970 
CreateAlbumSubTypeEnum(napi_env env)7971 napi_value MediaLibraryNapi::CreateAlbumSubTypeEnum(napi_env env)
7972 {
7973     napi_value result = nullptr;
7974     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
7975 
7976     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
7977         JS_INNER_FAIL);
7978     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE_GENERIC", PhotoAlbumSubType::SOURCE_GENERIC),
7979         JS_INNER_FAIL);
7980     for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
7981         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
7982             PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
7983     }
7984     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "CLASSIFY", PhotoAlbumSubType::CLASSIFY),
7985         JS_INNER_FAIL);
7986     for (size_t i = 0; i < analysisAlbumSubType.size(); i++) {
7987         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, analysisAlbumSubType[i],
7988             PhotoAlbumSubType::GEOGRAPHY_LOCATION + i), JS_INNER_FAIL);
7989     }
7990     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
7991 
7992     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
7993     return result;
7994 }
7995 
CreateAnalysisTypeEnum(napi_env env)7996 napi_value MediaLibraryNapi::CreateAnalysisTypeEnum(napi_env env)
7997 {
7998     struct AnalysisProperty property[] = {
7999         { "ANALYSIS_AESTHETICS_SCORE", AnalysisType::ANALYSIS_AESTHETICS_SCORE },
8000         { "ANALYSIS_LABEL", AnalysisType::ANALYSIS_LABEL },
8001         { "ANALYSIS_VIDEO_LABEL", AnalysisType::ANALYSIS_VIDEO_LABEL },
8002         { "ANALYSIS_OCR", AnalysisType::ANALYSIS_OCR },
8003         { "ANALYSIS_FACE", AnalysisType::ANALYSIS_FACE },
8004         { "ANALYSIS_OBJECT", AnalysisType::ANALYSIS_OBJECT },
8005         { "ANALYSIS_RECOMMENDATION", AnalysisType::ANALYSIS_RECOMMENDATION },
8006         { "ANALYSIS_SEGMENTATION", AnalysisType::ANALYSIS_SEGMENTATION },
8007         { "ANALYSIS_COMPOSITION", AnalysisType::ANALYSIS_COMPOSITION },
8008         { "ANALYSIS_SALIENCY", AnalysisType::ANALYSIS_SALIENCY },
8009         { "ANALYSIS_DETAIL_ADDRESS", AnalysisType::ANALYSIS_DETAIL_ADDRESS },
8010         { "ANALYSIS_HUMAN_FACE_TAG", AnalysisType::ANALYSIS_HUMAN_FACE_TAG },
8011         { "ANALYSIS_HEAD_POSITION", AnalysisType::ANALYSIS_HEAD_POSITION },
8012         { "ANALYSIS_BONE_POSE", AnalysisType::ANALYSIS_BONE_POSE },
8013         { "ANALYSIS_MULTI_CROP", AnalysisType::ANALYSIS_MULTI_CROP },
8014         { "ANALYSIS_HIGHLIGHT", AnalysisType::ANALYSIS_HIGHLIGHT },
8015         { "ANALYSIS_SEARCH_INDEX", AnalysisType::ANALYSIS_SEARCH_INDEX },
8016     };
8017 
8018     napi_value result = nullptr;
8019     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8020 
8021     for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
8022         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
8023             JS_INNER_FAIL);
8024     }
8025 
8026     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAnalysisType_), JS_INNER_FAIL);
8027     return result;
8028 }
8029 
CreateHighlightAlbumInfoTypeEnum(napi_env env)8030 napi_value MediaLibraryNapi::CreateHighlightAlbumInfoTypeEnum(napi_env env)
8031 {
8032     struct AnalysisProperty property[] = {
8033         { "COVER_INFO", HighlightAlbumInfoType::COVER_INFO },
8034         { "PLAY_INFO", HighlightAlbumInfoType::PLAY_INFO },
8035     };
8036 
8037     napi_value result = nullptr;
8038     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8039 
8040     for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
8041         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
8042             JS_INNER_FAIL);
8043     }
8044 
8045     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sHighlightUserActionType_), JS_INNER_FAIL);
8046     return result;
8047 }
8048 
CreateHighlightUserActionTypeEnum(napi_env env)8049 napi_value MediaLibraryNapi::CreateHighlightUserActionTypeEnum(napi_env env)
8050 {
8051     struct AnalysisProperty property[] = {
8052         { "INSERTED_PIC_COUNT", HighlightUserActionType::INSERTED_PIC_COUNT },
8053         { "REMOVED_PIC_COUNT", HighlightUserActionType::REMOVED_PIC_COUNT },
8054         { "SHARED_SCREENSHOT_COUNT", HighlightUserActionType::SHARED_SCREENSHOT_COUNT },
8055         { "SHARED_COVER_COUNT", HighlightUserActionType::SHARED_COVER_COUNT },
8056         { "RENAMED_COUNT", HighlightUserActionType::RENAMED_COUNT },
8057         { "CHANGED_COVER_COUNT", HighlightUserActionType::CHANGED_COVER_COUNT },
8058         { "RENDER_VIEWED_TIMES", HighlightUserActionType::RENDER_VIEWED_TIMES },
8059         { "RENDER_VIEWED_DURATION", HighlightUserActionType::RENDER_VIEWED_DURATION },
8060         { "ART_LAYOUT_VIEWED_TIMES", HighlightUserActionType::ART_LAYOUT_VIEWED_TIMES },
8061         { "ART_LAYOUT_VIEWED_DURATION", HighlightUserActionType::ART_LAYOUT_VIEWED_DURATION },
8062     };
8063 
8064     napi_value result = nullptr;
8065     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8066 
8067     for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
8068         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
8069             JS_INNER_FAIL);
8070     }
8071 
8072     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sHighlightAlbumInfoType_), JS_INNER_FAIL);
8073     return result;
8074 }
8075 
CreateDefaultChangeUriEnum(napi_env env)8076 napi_value MediaLibraryNapi::CreateDefaultChangeUriEnum(napi_env env)
8077 {
8078     return CreateStringEnumProperty(env, DEFAULT_URI_ENUM_PROPERTIES, sDefaultChangeUriRef_);
8079 }
8080 
CreateNotifyTypeEnum(napi_env env)8081 napi_value MediaLibraryNapi::CreateNotifyTypeEnum(napi_env env)
8082 {
8083     return CreateNumberEnumProperty(env, notifyTypeEnum, sNotifyType_);
8084 }
8085 
CreateRequestPhotoTypeEnum(napi_env env)8086 napi_value MediaLibraryNapi::CreateRequestPhotoTypeEnum(napi_env env)
8087 {
8088     return CreateNumberEnumProperty(env, requestPhotoTypeEnum, sRequestPhotoTypeEnumRef_);
8089 }
8090 
CreateDeliveryModeEnum(napi_env env)8091 napi_value MediaLibraryNapi::CreateDeliveryModeEnum(napi_env env)
8092 {
8093     return CreateNumberEnumProperty(env, deliveryModeEnum, sDeliveryModeEnumRef_);
8094 }
8095 
CreateSourceModeEnum(napi_env env)8096 napi_value MediaLibraryNapi::CreateSourceModeEnum(napi_env env)
8097 {
8098     return CreateNumberEnumProperty(env, sourceModeEnum, sSourceModeEnumRef_);
8099 }
8100 
CreateAuthorizationModeEnum(napi_env env)8101 napi_value MediaLibraryNapi::CreateAuthorizationModeEnum(napi_env env)
8102 {
8103     return CreateNumberEnumProperty(env, AuthorizationModeEnum, sAuthorizationModeEnumRef_);
8104 }
8105 
CreateCompatibleModeEnum(napi_env env)8106 napi_value MediaLibraryNapi::CreateCompatibleModeEnum(napi_env env)
8107 {
8108     return CreateNumberEnumProperty(env, compatibleModeEnum, sCompatibleModeEnumRef_);
8109 }
8110 
CreateResourceTypeEnum(napi_env env)8111 napi_value MediaLibraryNapi::CreateResourceTypeEnum(napi_env env)
8112 {
8113     const int32_t startIdx = 1;
8114     return CreateNumberEnumProperty(env, resourceTypeEnum, sResourceTypeEnumRef_, startIdx);
8115 }
8116 
CreateCloudEnhancementTaskStageEnum(napi_env env)8117 napi_value MediaLibraryNapi::CreateCloudEnhancementTaskStageEnum(napi_env env)
8118 {
8119     return CreateNumberEnumProperty(env, cloudEnhancementTaskStageEnum, sCloudEnhancementTaskStageEnumRef_, -1);
8120 }
8121 
CreateCloudEnhancementStateEnum(napi_env env)8122 napi_value MediaLibraryNapi::CreateCloudEnhancementStateEnum(napi_env env)
8123 {
8124     return CreateNumberEnumProperty(env, cloudEnhancementStateEnum, sCloudEnhancementStateEnumRef_);
8125 }
8126 
CreateVideoEnhancementTypeEnum(napi_env env)8127 napi_value MediaLibraryNapi::CreateVideoEnhancementTypeEnum(napi_env env)
8128 {
8129     return CreateNumberEnumProperty(env, videoEnhancementTypeEnum, sVideoEnhancementTypeEnumRef_);
8130 }
8131 
CreateMovingPhotoEffectModeEnum(napi_env env)8132 napi_value MediaLibraryNapi::CreateMovingPhotoEffectModeEnum(napi_env env)
8133 {
8134     napi_value result = nullptr;
8135     CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8136     for (size_t i = 0; i < movingPhotoEffectModeEnum.size(); i++) {
8137         CHECK_ARGS(env, AddIntegerNamedProperty(env, result, movingPhotoEffectModeEnum[i], static_cast<int32_t>(i)),
8138             JS_INNER_FAIL);
8139     }
8140     CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "IMAGE_ONLY",
8141         static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY)), JS_INNER_FAIL);
8142     CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sMovingPhotoEffectModeEnumRef_),
8143         JS_INNER_FAIL);
8144     return result;
8145 }
8146 
CreateSupportedWatermarkTypeEnum(napi_env env)8147 napi_value MediaLibraryNapi::CreateSupportedWatermarkTypeEnum(napi_env env)
8148 {
8149     return CreateNumberEnumProperty(env, watermarkTypeEnum, sSupportedWatermarkTypeEnumRef_);
8150 }
8151 
CreateCloudMediaDownloadTypeEnum(napi_env env)8152 napi_value MediaLibraryNapi::CreateCloudMediaDownloadTypeEnum(napi_env env)
8153 {
8154     return CreateNumberEnumProperty(env, cloudMediaDownloadTypeEnum, sCloudMediaDownloadTypeEnumRef_);
8155 }
8156 
CreateCloudMediaRetainTypeEnum(napi_env env)8157 napi_value MediaLibraryNapi::CreateCloudMediaRetainTypeEnum(napi_env env)
8158 {
8159     return CreateNumberEnumProperty(env, cloudMediaRetainTypeEnum, sCloudMediaRetainTypeEnumRef_);
8160 }
8161 
CreateCloudMediaAssetTaskStatusEnum(napi_env env)8162 napi_value MediaLibraryNapi::CreateCloudMediaAssetTaskStatusEnum(napi_env env)
8163 {
8164     return CreateNumberEnumProperty(env, cloudMediaAssetTaskStatusEnum, sCloudMediaAssetTaskStatusEnumRef_);
8165 }
8166 
CreateCloudMediaTaskPauseCauseEnum(napi_env env)8167 napi_value MediaLibraryNapi::CreateCloudMediaTaskPauseCauseEnum(napi_env env)
8168 {
8169     return CreateNumberEnumProperty(env, cloudMediaTaskPauseCauseEnum, sCloudMediaTaskPauseCauseEnumRef_);
8170 }
8171 
CreateNotifyChangeTypeEnum(napi_env env)8172 napi_value MediaLibraryNapi::CreateNotifyChangeTypeEnum(napi_env env)
8173 {
8174     return CreateNumberEnumProperty(env, notifyChangeTypeEnum, sNotifyChangeTypeEnumRef_);
8175 }
8176 
CreateThumbnailChangeStatusEnum(napi_env env)8177 napi_value MediaLibraryNapi::CreateThumbnailChangeStatusEnum(napi_env env)
8178 {
8179     return CreateNumberEnumProperty(env, thumbnailChangeStatusEnum, sThumbnailChangeStatusEnumRef_);
8180 }
8181 
CreateStrongAssociationTypeEnum(napi_env env)8182 napi_value MediaLibraryNapi::CreateStrongAssociationTypeEnum(napi_env env)
8183 {
8184     return CreateNumberEnumProperty(env, strongAssociationTypeEnum, sStrongAssociationTypeEnumRef_);
8185 }
8186 
ParseArgsCreatePhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8187 static napi_value ParseArgsCreatePhotoAlbum(napi_env env, napi_callback_info info,
8188     unique_ptr<MediaLibraryAsyncContext> &context)
8189 {
8190     if (!MediaLibraryNapiUtils::IsSystemApp()) {
8191         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
8192         return nullptr;
8193     }
8194 
8195     constexpr size_t minArgs = ARGS_ONE;
8196     constexpr size_t maxArgs = ARGS_TWO;
8197     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
8198         JS_ERR_PARAMETER_INVALID);
8199 
8200     /* Parse the first argument into albumName */
8201     string albumName;
8202     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], albumName),
8203         JS_ERR_PARAMETER_INVALID);
8204 
8205     if (MediaFileUtils::CheckAlbumName(albumName) < 0) {
8206         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8207         return nullptr;
8208     }
8209     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, albumName);
8210     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_IS_LOCAL, 1); // local album is 1.
8211 
8212     napi_value result = nullptr;
8213     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8214     return result;
8215 }
8216 
GetExistsPhotoAlbum(const string & albumName,MediaLibraryAsyncContext * context)8217 static void GetExistsPhotoAlbum(const string &albumName, MediaLibraryAsyncContext *context)
8218 {
8219     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
8220         UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
8221     Uri uri(queryUri);
8222     DataSharePredicates predicates;
8223     predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
8224     vector<string> columns;
8225     int errCode = 0;
8226     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
8227     auto fetchResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
8228     fetchResult->SetResultNapiType(context->resultNapiType);
8229     context->photoAlbumData = fetchResult->GetFirstObject();
8230 }
8231 
GetPhotoAlbumById(const int32_t id,const string & albumName,MediaLibraryAsyncContext * context)8232 static void GetPhotoAlbumById(const int32_t id, const string &albumName, MediaLibraryAsyncContext *context)
8233 {
8234     auto photoAlbum = make_unique<PhotoAlbum>();
8235     photoAlbum->SetAlbumId(id);
8236     photoAlbum->SetPhotoAlbumType(USER);
8237     photoAlbum->SetPhotoAlbumSubType(USER_GENERIC);
8238     photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(id));
8239     photoAlbum->SetAlbumName(albumName);
8240     photoAlbum->SetResultNapiType(context->resultNapiType);
8241     context->photoAlbumData = move(photoAlbum);
8242 }
8243 
CallPhotoAccessCreateAlbum(MediaLibraryAsyncContext * context,const std::string & albumName)8244 int32_t CallPhotoAccessCreateAlbum(MediaLibraryAsyncContext *context, const std::string &albumName)
8245 {
8246     CreateAlbumReqBody reqBody;
8247     reqBody.albumName = albumName;
8248     int32_t errCode = IPC::UserDefineIPCClient().Call(context->businessCode, reqBody);
8249     if (errCode < 0) {
8250         NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
8251     }
8252     return errCode;
8253 }
8254 
JSCreatePhotoAlbumExecute(napi_env env,void * data)8255 static void JSCreatePhotoAlbumExecute(napi_env env, void *data)
8256 {
8257     MediaLibraryTracer tracer;
8258     tracer.Start("JSCreatePhotoAlbumExecute");
8259 
8260     bool isValid = false;
8261     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8262     string albumName = context->valuesBucket.Get(PhotoAlbumColumns::ALBUM_NAME, isValid);
8263     if (!isValid) {
8264         context->SaveError(-EINVAL);
8265         return;
8266     }
8267 
8268     int32_t ret = -EINVAL;
8269     if (context->businessCode != 0) {
8270         ret = CallPhotoAccessCreateAlbum(context, albumName);
8271     } else {
8272         string createAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
8273             UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
8274         Uri createPhotoAlbumUri(createAlbumUri);
8275         ret = UserFileClient::Insert(createPhotoAlbumUri, context->valuesBucket);
8276     }
8277 
8278     if (ret == -1) {
8279         // The album is already existed
8280         context->SaveError(-EEXIST);
8281         GetExistsPhotoAlbum(albumName, context);
8282         return;
8283     }
8284     if (ret < 0) {
8285         context->SaveError(ret);
8286         return;
8287     }
8288     GetPhotoAlbumById(ret, albumName, context);
8289 }
8290 
GetPhotoAlbumCreateResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)8291 static void GetPhotoAlbumCreateResult(napi_env env, MediaLibraryAsyncContext *context,
8292     unique_ptr<JSAsyncContextOutput> &jsContext)
8293 {
8294     if (context->photoAlbumData == nullptr) {
8295         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8296         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
8297             "Obtain photo album asset failed");
8298         return;
8299     }
8300     context->photoAlbumData->SetUserId(context->userId);
8301     napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
8302     if (jsPhotoAlbum == nullptr) {
8303         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8304         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
8305             "Failed to create js object for PhotoAlbum");
8306         return;
8307     }
8308     jsContext->data = jsPhotoAlbum;
8309     jsContext->status = true;
8310     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8311 }
8312 
HandleExistsError(napi_env env,MediaLibraryAsyncContext * context,napi_value & error)8313 static void HandleExistsError(napi_env env, MediaLibraryAsyncContext *context, napi_value &error)
8314 {
8315     if (context->photoAlbumData == nullptr) {
8316         MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_INVALID_OUTPUT,
8317             "Obtain photo album asset failed");
8318         return;
8319     }
8320     context->photoAlbumData->SetUserId(context->userId);
8321     napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
8322     if (jsPhotoAlbum == nullptr) {
8323         MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_MEM_ALLOCATION,
8324             "Failed to create js object for PhotoAlbum");
8325         return;
8326     }
8327     MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, JS_ERR_FILE_EXIST, "Album has existed");
8328     napi_value propertyName;
8329     CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &propertyName), JS_INNER_FAIL);
8330     CHECK_ARGS_RET_VOID(env, napi_set_property(env, error, propertyName, jsPhotoAlbum), JS_INNER_FAIL);
8331 }
8332 
JSCreatePhotoAlbumCompleteCallback(napi_env env,napi_status status,void * data)8333 static void JSCreatePhotoAlbumCompleteCallback(napi_env env, napi_status status, void *data)
8334 {
8335     MediaLibraryTracer tracer;
8336     tracer.Start("JSCreatePhotoAlbumCompleteCallback");
8337 
8338     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8339     auto jsContext = make_unique<JSAsyncContextOutput>();
8340     jsContext->status = false;
8341     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8342     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8343     if (context->error == ERR_DEFAULT) {
8344         GetPhotoAlbumCreateResult(env, context, jsContext);
8345     } else if (context->error == JS_ERR_FILE_EXIST) {
8346         HandleExistsError(env, context, jsContext->error);
8347     } else {
8348         context->HandleError(env, jsContext->error);
8349     }
8350 
8351     tracer.Finish();
8352     if (context->work != nullptr) {
8353         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
8354                                                    context->work, *jsContext);
8355     }
8356     delete context;
8357 }
8358 
CreatePhotoAlbum(napi_env env,napi_callback_info info)8359 napi_value MediaLibraryNapi::CreatePhotoAlbum(napi_env env, napi_callback_info info)
8360 {
8361     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8362     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
8363     CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
8364 
8365     SetUserIdFromObjectInfo(asyncContext);
8366     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
8367         JSCreatePhotoAlbumCompleteCallback);
8368 }
8369 
PhotoAccessCreatePhotoAlbum(napi_env env,napi_callback_info info)8370 napi_value MediaLibraryNapi::PhotoAccessCreatePhotoAlbum(napi_env env, napi_callback_info info)
8371 {
8372     MediaLibraryTracer tracer;
8373     tracer.Start("PhotoAccessCreatePhotoAlbum");
8374 
8375     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8376     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ALBUM);
8377     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8378     CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
8379 
8380     SetUserIdFromObjectInfo(asyncContext);
8381     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
8382         JSCreatePhotoAlbumCompleteCallback);
8383 }
8384 
ParseArgsDeletePhotoAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8385 static napi_value ParseArgsDeletePhotoAlbums(napi_env env, napi_callback_info info,
8386     unique_ptr<MediaLibraryAsyncContext> &context)
8387 {
8388     if (!MediaLibraryNapiUtils::IsSystemApp()) {
8389         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
8390         return nullptr;
8391     }
8392 
8393     constexpr size_t minArgs = ARGS_ONE;
8394     constexpr size_t maxArgs = ARGS_TWO;
8395     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
8396         JS_ERR_PARAMETER_INVALID);
8397 
8398     /* Parse the first argument into delete album id array */
8399     vector<string> deleteIds;
8400     uint32_t len = 0;
8401     CHECK_ARGS(env, napi_get_array_length(env, context->argv[PARAM0], &len), JS_INNER_FAIL);
8402     for (uint32_t i = 0; i < len; i++) {
8403         napi_value album = nullptr;
8404         CHECK_ARGS(env, napi_get_element(env, context->argv[PARAM0], i, &album), JS_INNER_FAIL);
8405         if (album == nullptr) {
8406             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8407             return nullptr;
8408         }
8409         PhotoAlbumNapi *obj = nullptr;
8410         CHECK_ARGS(env, napi_unwrap(env, album, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
8411         if (obj == nullptr) {
8412             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8413             return nullptr;
8414         }
8415         if (!PhotoAlbum::IsUserPhotoAlbum(obj->GetPhotoAlbumType(), obj->GetPhotoAlbumSubType())) {
8416             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8417             return nullptr;
8418         }
8419         deleteIds.push_back(to_string(obj->GetAlbumId()));
8420     }
8421     if (deleteIds.empty()) {
8422         napi_value result = nullptr;
8423         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8424         return result;
8425     }
8426     context->albumIds = deleteIds;
8427 
8428     napi_value result = nullptr;
8429     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8430     return result;
8431 }
8432 
JSDeletePhotoAlbumsExecute(napi_env env,void * data)8433 static void JSDeletePhotoAlbumsExecute(napi_env env, void *data)
8434 {
8435     MediaLibraryTracer tracer;
8436     tracer.Start("JSDeletePhotoAlbumsExecute");
8437 
8438     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
8439 
8440     CHECK_NULL_PTR_RETURN_VOID(context, "context is null");
8441     CHECK_IF_EQUAL(!context->albumIds.empty(), "albumIds is empty");
8442 
8443     int ret = E_OK;
8444     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
8445         context->predicates.In(PhotoAlbumColumns::ALBUM_ID, context->albumIds);
8446         string deleteAlbumUri = UFM_DELETE_PHOTO_ALBUM;
8447         Uri uri(deleteAlbumUri);
8448         ret = UserFileClient::Delete(uri, context->predicates);
8449     } else {
8450         DeleteAlbumsReqBody reqBody;
8451         reqBody.albumIds = context->albumIds;
8452         uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_DELETE_PHOTO_ALBUMS);
8453         ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
8454     }
8455 
8456     if (ret < 0) {
8457         context->SaveError(ret);
8458     } else {
8459         context->retVal = ret;
8460     }
8461 }
8462 
JSDeletePhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)8463 static void JSDeletePhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
8464 {
8465     MediaLibraryTracer tracer;
8466     tracer.Start("JSDeletePhotoAlbumsCompleteCallback");
8467 
8468     MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
8469     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
8470 
8471     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
8472     jsContext->status = false;
8473 
8474     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8475     if (context->error != ERR_DEFAULT) {
8476         context->HandleError(env, jsContext->error);
8477         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8478     } else {
8479         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
8480         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8481         jsContext->status = true;
8482     }
8483 
8484     tracer.Finish();
8485     if (context->work != nullptr) {
8486         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
8487                                                    context->work, *jsContext);
8488     }
8489     delete context;
8490 }
8491 
DeletePhotoAlbums(napi_env env,napi_callback_info info)8492 napi_value MediaLibraryNapi::DeletePhotoAlbums(napi_env env, napi_callback_info info)
8493 {
8494     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8495     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
8496     CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
8497 
8498     SetUserIdFromObjectInfo(asyncContext);
8499     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
8500         JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
8501 }
8502 
PhotoAccessDeletePhotoAlbums(napi_env env,napi_callback_info info)8503 napi_value MediaLibraryNapi::PhotoAccessDeletePhotoAlbums(napi_env env, napi_callback_info info)
8504 {
8505     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8506     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8507     CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
8508 
8509     SetUserIdFromObjectInfo(asyncContext);
8510     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
8511         JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
8512 }
8513 
GetAlbumFetchOption(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)8514 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
8515 {
8516     if (context->argc < (ARGS_ONE + hasCallback)) {
8517         NAPI_ERR_LOG("No arguments to parse");
8518         return nullptr;
8519     }
8520 
8521     // The index of fetchOption should always be the last arg besides callback
8522     uint32_t argIndex = context->argc - ARGS_ONE - hasCallback;
8523     if (argIndex >= NAPI_ARGC_MAX) {
8524         NAPI_ERR_LOG("argIndex ilegal");
8525         return nullptr;
8526     }
8527     napi_value fetchOption = context->argv[argIndex];
8528     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT, context), JS_INNER_FAIL);
8529     if (!context->uri.empty()) {
8530         if (context->uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != std::string::npos) {
8531             context->isAnalysisAlbum = PARAM1; // 1:is an analysis album
8532         }
8533     }
8534     napi_value result = nullptr;
8535     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8536     return result;
8537 }
8538 
GetAlbumIds(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)8539 static napi_value GetAlbumIds(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
8540 {
8541     if (context->argc < (ARGS_ONE + hasCallback)) {
8542         NAPI_ERR_LOG("No arguments to parse");
8543         return nullptr;
8544     }
8545     MediaLibraryNapiUtils::GetStringArrayFromInt32(env, context->argv[PARAM0], context->albumIds);
8546     if (context->albumIds.empty() || context->albumIds.size() > MAX_QUERY_ALBUM_LIMIT) {
8547         NAPI_ERR_LOG("the size of albumid is invalid");
8548         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8549         return nullptr;
8550     }
8551     napi_value result = nullptr;
8552     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8553     NAPI_INFO_LOG("GetAlbumIds: %{public}d", static_cast<int32_t>(context->albumIds.size()));
8554     context->predicates.In(PhotoAlbumColumns::ALBUM_ID, context->albumIds);
8555     return result;
8556 }
8557 
HandleOneArgAlbum(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)8558 static napi_value HandleOneArgAlbum(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
8559 {
8560     bool hasFetchOpt = false;
8561     CHECK_ARGS(env, MediaLibraryNapiUtils::hasFetchOpt(env, context->argv[PARAM0], hasFetchOpt), JS_INNER_FAIL);
8562     if (hasFetchOpt) {
8563         return GetAlbumFetchOption(env, context, hasCallback);
8564     } else {
8565         if (!MediaLibraryNapiUtils::IsSystemApp()) {
8566             NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
8567             return nullptr;
8568         }
8569         return GetAlbumIds(env, context, hasCallback);
8570     }
8571 }
8572 
ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> & context,const int32_t albumSubType)8573 static bool ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> &context, const int32_t albumSubType)
8574 {
8575     if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
8576         context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
8577         context->fetchColumn.insert(context->fetchColumn.end(),
8578             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
8579             PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
8580         MediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
8581         return false;
8582     } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8583         context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
8584         context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
8585         string onClause = PhotoAlbumColumns::ALBUM_NAME  + " = " + CITY_ID;
8586         context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
8587         context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
8588     }
8589     return true;
8590 }
8591 
ApplyTablePrefixToAlbumIdPredicates(DataSharePredicates & predicates)8592 static void ApplyTablePrefixToAlbumIdPredicates(DataSharePredicates& predicates)
8593 {
8594     constexpr int32_t fieldIdx = 0;
8595     auto& items = predicates.GetOperationList();
8596     string targetColumn = "AnalysisAlbum.album_id";
8597     std::vector<DataShare::OperationItem> tmpOperations = {};
8598     for (const DataShare::OperationItem& item : items) {
8599         if (item.singleParams.empty()) {
8600             tmpOperations.push_back(item);
8601             continue;
8602         }
8603         if (static_cast<string>(item.GetSingle(fieldIdx)) == PhotoAlbumColumns::ALBUM_ID) {
8604             DataShare::OperationItem tmpItem = item;
8605             tmpItem.singleParams[fieldIdx] = targetColumn;
8606             tmpOperations.push_back(tmpItem);
8607             continue;
8608         }
8609         tmpOperations.push_back(item);
8610     }
8611     predicates = DataSharePredicates(move(tmpOperations));
8612 }
8613 
AddHighlightAlbumPredicates(DataSharePredicates & predicates,int32_t albumSubType)8614 static void AddHighlightAlbumPredicates(DataSharePredicates& predicates, int32_t albumSubType)
8615 {
8616     vector<string> onClause = {
8617         ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
8618         HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
8619     };
8620     if (albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
8621         onClause = {
8622             ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
8623             HIGHLIGHT_ALBUM_TABLE + "." + AI_ALBUM_ID,
8624         };
8625     }
8626     predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
8627     predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
8628     ApplyTablePrefixToAlbumIdPredicates(predicates);
8629 }
8630 
ParseAlbumTypes(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context)8631 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context)
8632 {
8633     if (context->argc < ARGS_TWO) {
8634         NAPI_ERR_LOG("No arguments to parse");
8635         return nullptr;
8636     }
8637 
8638     /* Parse the first argument to photo album type */
8639     int32_t albumType;
8640     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
8641     if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
8642         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8643         return nullptr;
8644     }
8645     context->isAnalysisAlbum = (albumType == PhotoAlbumType::SMART) ? 1 : 0;
8646 
8647     /* Parse the second argument to photo album subType */
8648     int32_t albumSubType;
8649     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
8650     if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
8651         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8652         return nullptr;
8653     }
8654 
8655     if (!ParseLocationAlbumTypes(context, albumSubType)) {
8656         napi_value result = nullptr;
8657         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8658         return result;
8659     }
8660 
8661     context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
8662     if (albumSubType != ANY) {
8663         context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
8664     }
8665     if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8666         context->predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
8667     }
8668     if (albumSubType == PhotoAlbumSubType::HIGHLIGHT || albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
8669         context->isHighlightAlbum = albumSubType;
8670         AddHighlightAlbumPredicates(context->predicates, albumSubType);
8671     }
8672 
8673     napi_value result = nullptr;
8674     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8675     return result;
8676 }
8677 
RestrictAlbumSubtypeOptions(DataSharePredicates & predicates)8678 static void RestrictAlbumSubtypeOptions(DataSharePredicates &predicates)
8679 {
8680     if (!MediaLibraryNapiUtils::IsSystemApp()) {
8681         predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
8682             to_string(PhotoAlbumSubType::USER_GENERIC),
8683             to_string(PhotoAlbumSubType::FAVORITE),
8684             to_string(PhotoAlbumSubType::VIDEO),
8685             to_string(PhotoAlbumSubType::IMAGE),
8686         }));
8687     } else {
8688         predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
8689     }
8690 }
8691 
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8692 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
8693     unique_ptr<MediaLibraryAsyncContext> &context)
8694 {
8695     constexpr size_t minArgs = ARGS_ZERO;
8696     constexpr size_t maxArgs = ARGS_FOUR;
8697     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
8698         JS_ERR_PARAMETER_INVALID);
8699 
8700     bool hasCallback = false;
8701     CHECK_ARGS(env, MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
8702         JS_ERR_PARAMETER_INVALID);
8703     if (context->argc == ARGS_THREE) {
8704         napi_valuetype valueType = napi_undefined;
8705         if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
8706             (valueType == napi_undefined || valueType == napi_null)) {
8707             context->argc -= 1;
8708         }
8709     }
8710     switch (context->argc - hasCallback) {
8711         case ARGS_ZERO:
8712             break;
8713         case ARGS_ONE:
8714             CHECK_NULLPTR_RET(HandleOneArgAlbum(env, context, hasCallback));
8715             break;
8716         case ARGS_TWO:
8717             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
8718             break;
8719         case ARGS_THREE:
8720             CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
8721             CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
8722             break;
8723         default:
8724             return nullptr;
8725     }
8726     RestrictAlbumSubtypeOptions(context->predicates);
8727     if (context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
8728         context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
8729         CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
8730         AddDefaultPhotoAlbumColumns(context->fetchColumn);
8731         AddDefaultColumnsForNonAnalysisAlbums(*context);
8732         if (context->isHighlightAlbum) {
8733             context->fetchColumn.erase(std::remove(context->fetchColumn.begin(), context->fetchColumn.end(),
8734                 PhotoAlbumColumns::ALBUM_ID), context->fetchColumn.end());
8735             context->fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
8736             PhotoAlbumColumns::ALBUM_ID);
8737         }
8738     }
8739     napi_value result = nullptr;
8740     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8741     return result;
8742 }
8743 
GetPhotoAlbums(napi_env env,napi_callback_info info)8744 napi_value MediaLibraryNapi::GetPhotoAlbums(napi_env env, napi_callback_info info)
8745 {
8746     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8747     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
8748     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8749 
8750     SetUserIdFromObjectInfo(asyncContext);
8751     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
8752         JSGetPhotoAlbumsCompleteCallback);
8753 }
8754 
ReplaceFetchColumn(std::vector<std::string> & fetchColumn,const std::string & oldColumn,const std::string & newColumn)8755 static void ReplaceFetchColumn(std::vector<std::string> &fetchColumn,
8756     const std::string &oldColumn, const std::string &newColumn)
8757 {
8758     auto it = std::find(fetchColumn.begin(), fetchColumn.end(), oldColumn);
8759     if (it != fetchColumn.end()) {
8760         it->assign(newColumn);
8761     }
8762 }
8763 
AddNoSmartFetchColumns(std::vector<std::string> & fetchColumn)8764 static void AddNoSmartFetchColumns(std::vector<std::string> &fetchColumn)
8765 {
8766     AddDefaultPhotoAlbumColumns(fetchColumn);
8767     fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
8768     fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
8769     fetchColumn.push_back(PhotoAlbumColumns::ALBUM_LPATH);
8770     fetchColumn.push_back(PhotoAlbumColumns::ALBUM_DATE_ADDED);
8771 }
8772 
AddPhotoAlbumTypeFilter(DataSharePredicates & predicates,int32_t albumType,int32_t albumSubType)8773 static void AddPhotoAlbumTypeFilter(DataSharePredicates &predicates, int32_t albumType, int32_t albumSubType)
8774 {
8775     if (albumType != PhotoAlbumType::INVALID) {
8776         predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
8777     }
8778     if (albumSubType != PhotoAlbumSubType::ANY) {
8779         predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
8780         if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8781             predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
8782         }
8783     }
8784     RestrictAlbumSubtypeOptions(predicates);
8785 }
8786 
ParseArgsPahGetAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8787 static napi_value ParseArgsPahGetAlbums(napi_env env, napi_callback_info info,
8788     unique_ptr<MediaLibraryAsyncContext> &context)
8789 {
8790     napi_value result = nullptr;
8791     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8792     napi_status status = MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, ARGS_ZERO, ARGS_FOUR);
8793     CHECK_ARGS(env, status, JS_ERR_PARAMETER_INVALID);
8794 
8795     bool hasCallback = false;
8796     status = MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback);
8797     CHECK_ARGS(env, status, JS_ERR_PARAMETER_INVALID);
8798 
8799     context->photoAlbumType = PhotoAlbumType::INVALID;
8800     context->photoAlbumSubType = PhotoAlbumSubType::ANY;
8801     if (context->argc < ARGS_TWO) {
8802         bool hasFetchOpt = false;
8803         CHECK_ARGS(env, MediaLibraryNapiUtils::hasFetchOpt(env, context->argv[PARAM0], hasFetchOpt), JS_INNER_FAIL);
8804         if (!hasFetchOpt) {
8805             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8806             return nullptr;
8807         }
8808         CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
8809         CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
8810         if (context->isAnalysisAlbum) {
8811             context->photoAlbumType = PhotoAlbumType::SMART;
8812         }
8813         return result;
8814     }
8815 
8816     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], context->photoAlbumType));
8817     if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(context->photoAlbumType))) {
8818         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8819         return nullptr;
8820     }
8821 
8822     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], context->photoAlbumSubType));
8823     if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(context->photoAlbumSubType))) {
8824         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8825         return nullptr;
8826     }
8827 
8828     if ((context->argc - hasCallback) == ARGS_THREE) {
8829         CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
8830         if (context->photoAlbumSubType != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
8831             context->photoAlbumSubType != PhotoAlbumSubType::GEOGRAPHY_CITY) {
8832             CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
8833         }
8834     }
8835 
8836     return result;
8837 }
8838 
CallPahGetAlbums(MediaLibraryAsyncContext * context,int32_t & errCode)8839 static std::shared_ptr<DataShareResultSet> CallPahGetAlbums(MediaLibraryAsyncContext *context, int32_t &errCode)
8840 {
8841     if (context->businessCode != 0) {
8842         QueryAlbumsReqBody reqBody;
8843         QueryAlbumsRespBody respBody;
8844         reqBody.albumType = context->photoAlbumType;
8845         reqBody.albumSubType = context->photoAlbumSubType;
8846         reqBody.columns = context->fetchColumn;
8847         reqBody.predicates = context->predicates;
8848         errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
8849         if (errCode != 0) {
8850             NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
8851             return nullptr;
8852         }
8853         return respBody.resultSet;
8854     }
8855 
8856     if (context->photoAlbumType != PhotoAlbumType::SMART) {
8857         Uri uri(PAH_QUERY_PHOTO_ALBUM);
8858         AddNoSmartFetchColumns(context->fetchColumn);
8859         AddPhotoAlbumTypeFilter(context->predicates, context->photoAlbumType, context->photoAlbumSubType);
8860         return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
8861     }
8862 
8863     if (context->photoAlbumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
8864         Uri uri(PAH_QUERY_GEO_PHOTOS);
8865         MediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
8866         const auto &locations = PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS;
8867         context->fetchColumn.insert(context->fetchColumn.end(), locations.begin(), locations.end());
8868         return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
8869     }
8870 
8871     if (context->photoAlbumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8872         context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
8873         std::string onClause = PhotoAlbumColumns::ALBUM_NAME  + " = " + CITY_ID;
8874         context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
8875         context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
8876     } else {
8877         AddDefaultPhotoAlbumColumns(context->fetchColumn);
8878         if (context->photoAlbumSubType == PhotoAlbumSubType::HIGHLIGHT ||
8879             context->photoAlbumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
8880             AddHighlightAlbumPredicates(context->predicates, context->photoAlbumSubType);
8881             std::string highLightAlbumId = ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID +
8882                 " AS " + PhotoAlbumColumns::ALBUM_ID;
8883             ReplaceFetchColumn(context->fetchColumn, PhotoAlbumColumns::ALBUM_ID, highLightAlbumId);
8884         }
8885     }
8886 
8887     Uri uri(PAH_QUERY_ANA_PHOTO_ALBUM);
8888     AddPhotoAlbumTypeFilter(context->predicates, context->photoAlbumType, context->photoAlbumSubType);
8889     return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
8890 }
8891 
JSPahGetAlbumsExecute(napi_env env,void * data)8892 static void JSPahGetAlbumsExecute(napi_env env, void *data)
8893 {
8894     MediaLibraryTracer tracer;
8895     tracer.Start("JSPahGetAlbumsExecute");
8896 
8897     int errCode = 0;
8898     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8899     std::shared_ptr<DataShareResultSet> resultSet = CallPahGetAlbums(context, errCode);
8900     if (resultSet == nullptr) {
8901         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
8902         if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
8903             context->SaveError(errCode);
8904         } else {
8905             context->SaveError(E_HAS_DB_ERROR);
8906         }
8907         return;
8908     }
8909 
8910     context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
8911     context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
8912     context->fetchPhotoAlbumResult->SetHiddenOnly(false);
8913     context->fetchPhotoAlbumResult->SetLocationOnly(false);
8914     context->fetchPhotoAlbumResult->SetUserId(context->userId);
8915 }
8916 
PahGetAlbums(napi_env env,napi_callback_info info)8917 napi_value MediaLibraryNapi::PahGetAlbums(napi_env env, napi_callback_info info)
8918 {
8919     MediaLibraryTracer tracer;
8920     tracer.Start("PahGetAlbums");
8921 
8922     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8923     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8924     CHECK_NULLPTR_RET(ParseArgsPahGetAlbums(env, info, asyncContext));
8925     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_QUERY_PHOTO_ALBUMS);
8926     SetUserIdFromObjectInfo(asyncContext);
8927     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetAlbums", JSPahGetAlbumsExecute,
8928         JSGetPhotoAlbumsCompleteCallback);
8929 }
8930 
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)8931 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
8932 {
8933     MediaLibraryTracer tracer;
8934     tracer.Start("PhotoAccessGetPhotoAlbums");
8935 
8936     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8937     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8938     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8939 
8940     SetUserIdFromObjectInfo(asyncContext);
8941     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
8942         JSGetPhotoAlbumsCompleteCallback);
8943 }
8944 
PhotoAccessGetPhotoAlbumsByIds(napi_env env,napi_callback_info info)8945 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsByIds(napi_env env, napi_callback_info info)
8946 {
8947     MediaLibraryTracer tracer;
8948     tracer.Start("PhotoAccessGetPhotoAlbumsByIds");
8949 
8950     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8951     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8952     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8953 
8954     SetUserIdFromObjectInfo(asyncContext);
8955     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsByIdsExecute,
8956         JSGetPhotoAlbumsCompleteCallback);
8957 }
8958 
PhotoAccessGetPhotoAlbumsSync(napi_env env,napi_callback_info info)8959 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsSync(napi_env env, napi_callback_info info)
8960 {
8961     MediaLibraryTracer tracer;
8962     tracer.Start("PhotoAccessGetPhotoAlbumsSync");
8963 
8964     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8965     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8966     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8967     SetUserIdFromObjectInfo(asyncContext);
8968     return JSGetPhotoAlbumsExecuteSync(env, *asyncContext);
8969 }
8970 
CreatePositionTypeEnum(napi_env env)8971 napi_value MediaLibraryNapi::CreatePositionTypeEnum(napi_env env)
8972 {
8973     const int32_t startIdx = 1;
8974     return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
8975 }
8976 
CreatePhotoSubTypeEnum(napi_env env)8977 napi_value MediaLibraryNapi::CreatePhotoSubTypeEnum(napi_env env)
8978 {
8979     return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
8980 }
8981 
CreatePhotoPermissionTypeEnum(napi_env env)8982 napi_value MediaLibraryNapi::CreatePhotoPermissionTypeEnum(napi_env env)
8983 {
8984     return CreateNumberEnumProperty(env, photoPermissionTypeEnum, sPhotoPermissionType_);
8985 }
8986 
CreateHideSensitiveTypeEnum(napi_env env)8987 napi_value MediaLibraryNapi::CreateHideSensitiveTypeEnum(napi_env env)
8988 {
8989     return CreateNumberEnumProperty(env, hideSensitiveTypeEnum, sHideSensitiveType_);
8990 }
8991 
CreateDynamicRangeTypeEnum(napi_env env)8992 napi_value MediaLibraryNapi::CreateDynamicRangeTypeEnum(napi_env env)
8993 {
8994     return CreateNumberEnumProperty(env, dynamicRangeTypeEnum, sDynamicRangeType_);
8995 }
8996 
CheckTitleCompatible(MediaLibraryAsyncContext * context)8997 static bool CheckTitleCompatible(MediaLibraryAsyncContext* context)
8998 {
8999     if (!context->isCreateByComponent) {
9000         return true;
9001     }
9002     bool hasTitleParam = false;
9003     const string title = context->valuesBucket.Get(MediaColumn::MEDIA_TITLE, hasTitleParam);
9004     if (!hasTitleParam) {
9005         return true;
9006     }
9007     return MediaFileUtils::CheckTitleCompatible(title) == E_OK;
9008 }
9009 
CallPhotoAccessCreateAsset(MediaLibraryAsyncContext * context,std::string & outUri)9010 static int32_t CallPhotoAccessCreateAsset(MediaLibraryAsyncContext* context, std::string &outUri)
9011 {
9012     bool isValid = false;
9013     CreateAssetReqBody reqBody;
9014     reqBody.mediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
9015     if (context->needSystemApp) {
9016         reqBody.photoSubtype = context->valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
9017         string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
9018         string cameraShotKey = context->valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
9019         reqBody.displayName = displayName;
9020         reqBody.cameraShotKey = cameraShotKey;
9021     } else {
9022         string title = context->valuesBucket.Get(MediaColumn::MEDIA_TITLE, isValid);
9023         string extension = context->valuesBucket.Get(ASSET_EXTENTION, isValid);
9024         reqBody.title = title;
9025         reqBody.extension = extension;
9026     }
9027 
9028     CreateAssetRespBody respBody;
9029     int32_t errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
9030     if (errCode != 0) {
9031         NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
9032         return errCode;
9033     }
9034     outUri = respBody.outUri;
9035     return respBody.fileId;
9036 }
9037 
PhotoAccessCreateAssetExecute(napi_env env,void * data)9038 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
9039 {
9040     OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
9041     MediaLibraryTracer tracer;
9042     tracer.Start("JSCreateAssetExecute");
9043 
9044     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9045     if (!CheckDisplayNameParams(context)) {
9046         context->error = JS_E_DISPLAYNAME;
9047         return;
9048     }
9049     if (!CheckTitleCompatible(context)) {
9050         context->error = JS_E_DISPLAYNAME;
9051         return;
9052     }
9053     if ((context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) && (!CheckRelativePathParams(context))) {
9054         context->error = JS_E_RELATIVEPATH;
9055         return;
9056     }
9057 
9058     string outUri;
9059     int index = -EINVAL;
9060     if (context->businessCode != 0) {
9061         index = CallPhotoAccessCreateAsset(context, outUri);
9062     } else {
9063         string uri;
9064         GetCreateUri(context, uri);
9065         Uri createFileUri(uri);
9066         index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri, context->userId);
9067     }
9068     if (index < 0) {
9069         context->SaveError(index);
9070         NAPI_ERR_LOG("InsertExt fail, index: %{public}d.", index);
9071     } else {
9072         if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
9073             if (context->isCreateByComponent) {
9074                 context->uri = outUri;
9075             } else {
9076                 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
9077             }
9078         } else {
9079 #ifdef MEDIALIBRARY_COMPATIBILITY
9080             SetFileAssetByIdV9(index, "", context);
9081 #else
9082             getFileAssetById(index, "", context);
9083 #endif
9084         }
9085     }
9086     OHOS::QOS::ResetThreadQos();
9087 }
9088 
PhotoAccessGrantPhotoUriPermissionExecute(napi_env env,void * data)9089 static void PhotoAccessGrantPhotoUriPermissionExecute(napi_env env, void *data)
9090 {
9091     MediaLibraryTracer tracer;
9092     tracer.Start("PhotoAccessGrantPhotoUriPermissionExecute");
9093 
9094     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9095     if (context == nullptr) {
9096         NAPI_ERR_LOG("Async context is null");
9097         return;
9098     }
9099     GrantUriPermissionReqBody reqBody;
9100     bool isValid = false;
9101     reqBody.tokenId = context->valuesBucket.Get(AppUriPermissionColumn::TARGET_TOKENID, isValid);
9102     CHECK_IF_EQUAL(isValid, "tokenId is empty");
9103     reqBody.srcTokenId = context->valuesBucket.Get(AppUriPermissionColumn::SOURCE_TOKENID, isValid);
9104     CHECK_IF_EQUAL(isValid, "srcTokenId is empty");
9105     reqBody.fileId = context->valuesBucket.Get(AppUriPermissionColumn::FILE_ID, isValid);
9106     CHECK_IF_EQUAL(isValid, "fileId is empty");
9107     reqBody.permissionType = context->valuesBucket.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
9108     CHECK_IF_EQUAL(isValid, "permissionType is empty");
9109     reqBody.hideSensitiveType = context->valuesBucket.Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
9110     CHECK_IF_EQUAL(isValid, "hideSensitiveType is empty");
9111     reqBody.uriType = context->valuesBucket.Get(AppUriPermissionColumn::URI_TYPE, isValid);
9112     CHECK_IF_EQUAL(isValid, "uriType is empty");
9113 
9114     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GRANT_PHOTO_URI_PERMISSION);
9115     NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
9116     int32_t result = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
9117     NAPI_INFO_LOG("GrantPhotoUriPermission ret:%{public}d", result);
9118     if (result < 0) {
9119         context->SaveError(result);
9120         NAPI_ERR_LOG("GrantPhotoUriPermission fail, result: %{public}d.", result);
9121     } else {
9122         context->retVal = result;
9123     }
9124 }
9125 
PhotoAccessGrantPhotoUrisPermissionExecuteEx(MediaLibraryAsyncContext * context)9126 static void PhotoAccessGrantPhotoUrisPermissionExecuteEx(MediaLibraryAsyncContext *context)
9127 {
9128     if (context == nullptr) {
9129         NAPI_ERR_LOG("Async context is null");
9130         return;
9131     }
9132     GrantUrisPermissionReqBody reqBody;
9133     bool isValid = false;
9134     std::set<std::string> processedColumn;
9135     for (const auto& valueBucket : context->valuesBucketArray) {
9136         if (processedColumn.find(AppUriPermissionColumn::TARGET_TOKENID) == processedColumn.end()) {
9137             reqBody.tokenId = context->valuesBucket.Get(AppUriPermissionColumn::TARGET_TOKENID, isValid);
9138             CHECK_IF_EQUAL(isValid, "tokenId is empty");
9139             processedColumn.insert(AppUriPermissionColumn::TARGET_TOKENID);
9140         }
9141         if (processedColumn.find(AppUriPermissionColumn::SOURCE_TOKENID) == processedColumn.end()) {
9142             reqBody.srcTokenId = context->valuesBucket.Get(AppUriPermissionColumn::SOURCE_TOKENID, isValid);
9143             CHECK_IF_EQUAL(isValid, "srcTokenId is empty");
9144             processedColumn.insert(AppUriPermissionColumn::SOURCE_TOKENID);
9145         }
9146         if (processedColumn.find(AppUriPermissionColumn::PERMISSION_TYPE) == processedColumn.end()) {
9147             reqBody.permissionType = context->valuesBucket.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
9148             CHECK_IF_EQUAL(isValid, "permissionType is empty");
9149             processedColumn.insert(AppUriPermissionColumn::PERMISSION_TYPE);
9150         }
9151         if (processedColumn.find(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE) == processedColumn.end()) {
9152             reqBody.hideSensitiveType = context->valuesBucket.Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
9153             CHECK_IF_EQUAL(isValid, "hideSensitiveType is empty");
9154             processedColumn.insert(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE);
9155         }
9156         if (processedColumn.find(AppUriPermissionColumn::URI_TYPE) == processedColumn.end()) {
9157             reqBody.uriType = context->valuesBucket.Get(AppUriPermissionColumn::URI_TYPE, isValid);
9158             CHECK_IF_EQUAL(isValid, "uriType is empty");
9159             processedColumn.insert(AppUriPermissionColumn::URI_TYPE);
9160         }
9161         reqBody.fileIds.emplace_back(valueBucket.Get(AppUriPermissionColumn::FILE_ID, isValid));
9162     }
9163     NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
9164     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GRANT_PHOTO_URIS_PERMISSION);
9165     int32_t result = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
9166     NAPI_INFO_LOG("GrantPhotoUrisPermission ret:%{public}d", result);
9167     if (result < 0) {
9168         context->SaveError(result);
9169         NAPI_ERR_LOG("GrantPhotoUrisPermission fail, result: %{public}d.", result);
9170     } else {
9171         context->retVal = result;
9172     }
9173 }
9174 
PhotoAccessGrantPhotoUrisPermissionExecute(napi_env env,void * data)9175 static void PhotoAccessGrantPhotoUrisPermissionExecute(napi_env env, void *data)
9176 {
9177     MediaLibraryTracer tracer;
9178     tracer.Start("PhotoAccessGrantPhotoUrisPermissionExecute");
9179 
9180     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9181     if (context == nullptr) {
9182         NAPI_ERR_LOG("Async context is null");
9183         return;
9184     }
9185     if (context->businessCode != 0) {
9186         return PhotoAccessGrantPhotoUrisPermissionExecuteEx(context);
9187     }
9188 
9189     string uri = PAH_CREATE_APP_URI_PERMISSION;
9190     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
9191     Uri createUri(uri);
9192 
9193     int result = UserFileClient::BatchInsert(createUri, context->valuesBucketArray);
9194     if (result < 0) {
9195         context->SaveError(result);
9196         NAPI_ERR_LOG("BatchInsert fail, result: %{public}d.", result);
9197     } else {
9198         context->retVal = result;
9199     }
9200 }
9201 
PhotoAccessCancelPhotoUriPermissionExecute(napi_env env,void * data)9202 static void PhotoAccessCancelPhotoUriPermissionExecute(napi_env env, void *data)
9203 {
9204     MediaLibraryTracer tracer;
9205     tracer.Start("PhotoAccessCancelPhotoUriPermissionExecute");
9206 
9207     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9208     if (context == nullptr) {
9209         NAPI_ERR_LOG("Async context is null");
9210         return;
9211     }
9212 
9213     CancelUriPermissionReqBody reqBody;
9214     bool isValid = false;
9215     reqBody.tokenId = context->valuesBucket.Get(AppUriPermissionColumn::TARGET_TOKENID, isValid);
9216     CHECK_IF_EQUAL(isValid, "tokenId is empty");
9217     reqBody.srcTokenId = context->valuesBucket.Get(AppUriPermissionColumn::SOURCE_TOKENID, isValid);
9218     CHECK_IF_EQUAL(isValid, "srcTokenId is empty");
9219     reqBody.fileId = context->valuesBucket.Get(AppUriPermissionColumn::FILE_ID, isValid);
9220     CHECK_IF_EQUAL(isValid, "fileId is empty");
9221     reqBody.permissionType = context->valuesBucket.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
9222     CHECK_IF_EQUAL(isValid, "permissionType is empty");
9223     reqBody.uriType = context->valuesBucket.Get(AppUriPermissionColumn::URI_TYPE, isValid);
9224     CHECK_IF_EQUAL(isValid, "uriType is empty");
9225 
9226     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_CANCEL_PHOTO_URI_PERMISSION);
9227     NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
9228     int32_t result = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
9229     NAPI_INFO_LOG("CancelPhotoUriPermission ret:%{public}d", result);
9230     if (result < 0) {
9231         context->SaveError(result);
9232         NAPI_ERR_LOG("CancelPhotoUriPermission fail, result: %{public}d.", result);
9233     } else {
9234         context->retVal = result;
9235     }
9236 }
9237 
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)9238 napi_value MediaLibraryNapi::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
9239 {
9240     MediaLibraryTracer tracer;
9241     tracer.Start("PhotoAccessHelperCreatePhotoAsset");
9242 
9243     NAPI_INFO_LOG("enter");
9244 
9245     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9246     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9247     asyncContext->assetType = TYPE_PHOTO;
9248     NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
9249     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_PUBLIC_CREATE_ASSET);
9250     if (asyncContext->needSystemApp) {
9251         asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET);
9252     }
9253 
9254     SetUserIdFromObjectInfo(asyncContext);
9255     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
9256         PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
9257 }
9258 
PhotoAccessGrantPhotoUriPermission(napi_env env,napi_callback_info info)9259 napi_value MediaLibraryNapi::PhotoAccessGrantPhotoUriPermission(napi_env env, napi_callback_info info)
9260 {
9261     MediaLibraryTracer tracer;
9262     tracer.Start("PhotoAccessGrantPhotoUriPermission");
9263 
9264     NAPI_INFO_LOG("enter");
9265 
9266     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9267     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9268     asyncContext->assetType = TYPE_PHOTO;
9269     NAPI_ASSERT(env, ParseArgsGrantPhotoUriPermission(env, info, asyncContext), "Failed to parse js args");
9270 
9271     SetUserIdFromObjectInfo(asyncContext);
9272     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUriPermission",
9273         PhotoAccessGrantPhotoUriPermissionExecute, JSPhotoUriPermissionCallback);
9274 }
9275 
PhotoAccessGrantPhotoUrisPermission(napi_env env,napi_callback_info info)9276 napi_value MediaLibraryNapi::PhotoAccessGrantPhotoUrisPermission(napi_env env, napi_callback_info info)
9277 {
9278     MediaLibraryTracer tracer;
9279     tracer.Start("PhotoAccessGrantPhotoUrisPermission");
9280 
9281     NAPI_INFO_LOG("enter");
9282 
9283     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9284     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9285     asyncContext->assetType = TYPE_PHOTO;
9286     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GRANT_PHOTO_URIS_PERMISSION);
9287     NAPI_ASSERT(env, ParseArgsGrantPhotoUrisPermission(env, info, asyncContext), "Failed to parse js args");
9288 
9289     SetUserIdFromObjectInfo(asyncContext);
9290     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUrisPermission",
9291         PhotoAccessGrantPhotoUrisPermissionExecute, JSPhotoUriPermissionCallback);
9292 }
9293 
PhotoAccessCancelPhotoUriPermission(napi_env env,napi_callback_info info)9294 napi_value MediaLibraryNapi::PhotoAccessCancelPhotoUriPermission(napi_env env, napi_callback_info info)
9295 {
9296     MediaLibraryTracer tracer;
9297     tracer.Start("PhotoAccessCancelPhotoUriPermission");
9298 
9299     NAPI_INFO_LOG("enter");
9300 
9301     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9302     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9303     asyncContext->assetType = TYPE_PHOTO;
9304     NAPI_ASSERT(env, ParseArgsCancelPhotoUriPermission(env, info, asyncContext), "Failed to parse js args");
9305 
9306     SetUserIdFromObjectInfo(asyncContext);
9307     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessCancelPhotoUriPermission",
9308         PhotoAccessCancelPhotoUriPermissionExecute, JSPhotoUriPermissionCallback);
9309 }
9310 
CheckAlbumUri(napi_env env,OHOS::DataShare::DataShareValuesBucket & valueBucket,MediaLibraryAsyncContext * context)9311 static bool CheckAlbumUri(napi_env env, OHOS::DataShare::DataShareValuesBucket &valueBucket,
9312     MediaLibraryAsyncContext *context)
9313 {
9314     bool isValid = false;
9315     string ownerAlbumId = valueBucket.Get(PhotoColumn::PHOTO_OWNER_ALBUM_ID, isValid);
9316     if (!isValid || ownerAlbumId.empty()) {
9317         return false;
9318     }
9319     string queryUri = PAH_QUERY_PHOTO_ALBUM;
9320     Uri uri(queryUri);
9321     DataSharePredicates predicates;
9322     vector selectionArgs = { to_string(PhotoAlbumSubType::USER_GENERIC), to_string(PhotoAlbumSubType::SOURCE_GENERIC) };
9323     predicates.In(PhotoAlbumColumns::ALBUM_SUBTYPE, selectionArgs);
9324     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, ownerAlbumId);
9325     int errCode = 0;
9326     vector<string> columns;
9327     columns.push_back(MEDIA_COLUMN_COUNT_1);
9328     shared_ptr<DataShareResultSet> resultSet =
9329         UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
9330     if (resultSet == nullptr) {
9331         NAPI_ERR_LOG("resultSet is null, errCode: %{public}d", errCode);
9332         return false;
9333     }
9334     int err = resultSet->GoToFirstRow();
9335     if (err != NativeRdb::E_OK) {
9336         NAPI_ERR_LOG("Invalid albumuri, Failed GoToFirstRow %{public}d", err);
9337         resultSet->Close();
9338         return false;
9339     }
9340     int32_t count = 0;
9341     resultSet->GetInt(0, count);
9342     if (count == 0) {
9343         NAPI_ERR_LOG("Invalid albumuri!");
9344         resultSet->Close();
9345         return false;
9346     }
9347     resultSet->Close();
9348     return true;
9349 }
9350 
CallPhotoAccessCreateAssetForApp(MediaLibraryAsyncContext * context,const DataShareValuesBucket & valuesBucket,std::string & outUri)9351 static int32_t CallPhotoAccessCreateAssetForApp(MediaLibraryAsyncContext* context,
9352     const DataShareValuesBucket &valuesBucket, std::string &outUri)
9353 {
9354     bool isValid = false;
9355     CreateAssetForAppReqBody reqBody;
9356     reqBody.tokenId = static_cast<int64_t>(context->tokenId);
9357     reqBody.mediaType = valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
9358     reqBody.photoSubtype = valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
9359 
9360     string extension = valuesBucket.Get(ASSET_EXTENTION, isValid);
9361     string title = valuesBucket.Get(MediaColumn::MEDIA_TITLE, isValid);
9362     string appId = valuesBucket.Get(MEDIA_DATA_DB_OWNER_APPID, isValid);
9363     string bundleName = valuesBucket.Get(MEDIA_DATA_DB_OWNER_PACKAGE, isValid);
9364     string packageName = valuesBucket.Get(MEDIA_DATA_DB_PACKAGE_NAME, isValid);
9365     string ownerAlbumId = valuesBucket.Get(PhotoColumn::PHOTO_OWNER_ALBUM_ID, isValid);
9366     reqBody.title = title;
9367     reqBody.extension = extension;
9368     reqBody.bundleName = bundleName;
9369     reqBody.packageName = packageName;
9370     reqBody.appId = appId;
9371     reqBody.ownerAlbumId = ownerAlbumId;
9372 
9373     CreateAssetForAppRespBody respBody;
9374     int32_t errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
9375     if (errCode != 0) {
9376         NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
9377         return errCode;
9378     }
9379     outUri = respBody.outUri;
9380     return respBody.fileId;
9381 }
9382 
PhotoAccessAgentCreateAssetsExecute(napi_env env,void * data)9383 static void PhotoAccessAgentCreateAssetsExecute(napi_env env, void *data)
9384 {
9385     MediaLibraryTracer tracer;
9386     tracer.Start("JSCreateAssetExecute");
9387 
9388     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9389     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
9390 
9391     string uri;
9392     GetCreateUri(context, uri);
9393     if (context->isContainsAlbumUri) {
9394         bool isValid = CheckAlbumUri(env, context->valuesBucketArray[0], context);
9395         if (!isValid) {
9396             context->error = JS_ERR_PARAMETER_INVALID;
9397             return;
9398         }
9399     }
9400     if (context->tokenId != 0) {
9401         NAPI_INFO_LOG("tokenId: %{public}d", context->tokenId);
9402         MediaLibraryNapiUtils::UriAppendKeyValue(uri, TOKEN_ID, to_string(context->tokenId));
9403     }
9404     Uri createFileUri(uri);
9405     for (const auto& valuesBucket : context->valuesBucketArray) {
9406         bool inValid = false;
9407         string title = valuesBucket.Get(MediaColumn::MEDIA_TITLE, inValid);
9408         if (!context->isContainsAlbumUri && !title.empty() && MediaFileUtils::CheckTitleCompatible(title) != E_OK) {
9409             NAPI_ERR_LOG("Title contains invalid characters: %{private}s, skipping", title.c_str());
9410             context->uriArray.push_back(to_string(E_INVALID_DISPLAY_NAME));
9411             continue;
9412         }
9413         string outUri;
9414         int index = -EINVAL;
9415         if (context->businessCode != 0) {
9416             index = CallPhotoAccessCreateAssetForApp(context, valuesBucket, outUri);
9417         } else {
9418             index = UserFileClient::InsertExt(createFileUri, valuesBucket, outUri, context->userId);
9419         }
9420         if (index < 0) {
9421             if (index == E_PERMISSION_DENIED || index == -E_CHECK_SYSTEMAPP_FAIL) {
9422                 context->SaveError(index);
9423                 NAPI_ERR_LOG("PERMISSION_DENIED, index: %{public}d.", index);
9424                 return;
9425             }
9426 
9427             if (index == E_HAS_DB_ERROR) {
9428                 index = OHOS_INVALID_PARAM_CODE;
9429             }
9430             context->uriArray.push_back(to_string(index));
9431 
9432             NAPI_ERR_LOG("InsertExt fail, index: %{public}d title: %{public}s.", index, title.c_str());
9433         } else {
9434             context->uriArray.push_back(move(outUri));
9435         }
9436     }
9437 }
9438 
JSStartAssetAnalysisExecute(napi_env env,void * data)9439 static void JSStartAssetAnalysisExecute(napi_env env, void *data)
9440 {
9441     MediaLibraryTracer tracer;
9442     tracer.Start("JSStartAssetAnalysisExecute");
9443 
9444     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9445     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
9446 
9447     // 1. Start full analysis if need. 2. If uris are non-empty, start analysis for corresponding uris.
9448     if (!context->isFullAnalysis && context->uris.empty()) {
9449         NAPI_INFO_LOG("asset uris are empty");
9450         return;
9451     }
9452 
9453     context->taskId = ForegroundAnalysisMeta::GetIncTaskId();
9454     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::QUERY_START_ASSET_ANALYSIS);
9455     StartAssetAnalysisReqBody reqBody;
9456     StartAssetAnalysisRespBody respBody;
9457     std::vector<std::string> fileIds;
9458     for (const auto &uri : context->uris) {
9459         std::string fileId = MediaLibraryNapiUtils::GetFileIdFromUriString(uri);
9460         if (!fileId.empty()) {
9461             fileIds.push_back(fileId);
9462         }
9463     }
9464     if (!fileIds.empty()) {
9465         reqBody.predicates.In(PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::MEDIA_ID, fileIds);
9466     }
9467     int errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(businessCode, reqBody, respBody);
9468     if (respBody.resultSet != nullptr) {
9469         respBody.resultSet->Close();
9470     }
9471     if (errCode != E_OK) {
9472         context->SaveError(errCode);
9473         NAPI_ERR_LOG("Start assets analysis failed! errCode is = %{public}d", errCode);
9474     }
9475 }
9476 
ParseArgsCreateAgentCreateAssetsWithMode(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)9477 static napi_value ParseArgsCreateAgentCreateAssetsWithMode(napi_env env, napi_callback_info info,
9478     unique_ptr<MediaLibraryAsyncContext> &context)
9479 {
9480     /* Parse the arguments */
9481     BundleInfo bundleInfo;
9482     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO],
9483         bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
9484     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
9485         bundleInfo.packageName) == napi_ok, "Failed to get appName");
9486     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_TWO],
9487         bundleInfo.appId) == napi_ok, "Failed to get appId");
9488 
9489     napi_value result = nullptr;
9490     NAPI_CALL(env, napi_get_boolean(env, true, &result));
9491 
9492     vector<napi_value> napiValues;
9493     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_FIVE], napiValues));
9494     if (napiValues.empty()) {
9495         return result;
9496     }
9497 
9498     for (const auto& napiValue : napiValues) {
9499         CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context) == napi_ok,
9500             "Parse asset create config failed");
9501     }
9502 
9503     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
9504         == napi_ok, "Failed to get callback");
9505     return result;
9506 }
9507 
ParseArgsAgentCreateAssetsWithMode(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)9508 static napi_value ParseArgsAgentCreateAssetsWithMode(napi_env env, napi_callback_info info,
9509     unique_ptr<MediaLibraryAsyncContext> &context)
9510 {
9511     constexpr size_t minArgs = ARGS_SIX;
9512     constexpr size_t maxArgs = ARGS_SIX;
9513     NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
9514         napi_ok, "Failed to get object info");
9515 
9516     context->isCreateByComponent = false;
9517     context->isCreateByAgent = true;
9518     context->needSystemApp = true;
9519     if (!MediaLibraryNapiUtils::IsSystemApp()) {
9520         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
9521         return nullptr;
9522     }
9523 
9524     return ParseArgsCreateAgentCreateAssetsWithMode(env, info, context);
9525 }
9526 
PhotoAccessHelperAgentCreateAssetsWithMode(napi_env env,napi_callback_info info)9527 napi_value MediaLibraryNapi::PhotoAccessHelperAgentCreateAssetsWithMode(napi_env env, napi_callback_info info)
9528 {
9529     MediaLibraryTracer tracer;
9530     tracer.Start("PhotoAccessHelperAgentCreateAssetsWithMode");
9531 
9532     NAPI_INFO_LOG("enter");
9533     int32_t authorizationMode = -1;
9534     int32_t tokenId = -1;
9535     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9536     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET_FOR_APP_WITH_MODE);
9537     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9538     asyncContext->assetType = TYPE_PHOTO;
9539     NAPI_ASSERT(env, ParseArgsAgentCreateAssetsWithMode(env, info, asyncContext), "Failed to parse js args");
9540     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[ARGS_THREE], tokenId));
9541     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[ARGS_FOUR], authorizationMode));
9542     CHECK_COND_WITH_MESSAGE(env, authorizationMode == SaveType::SHORT_IMAGE_PERM, "authorizationMode is error");
9543 
9544     int ret = Security::AccessToken::AccessTokenKit::GrantPermissionForSpecifiedTime(
9545         tokenId, PERM_SHORT_TERM_WRITE_IMAGEVIDEO, SHORT_TERM_PERMISSION_DURATION_300S);
9546     if (ret != E_SUCCESS) {
9547         NapiError::ThrowError(env, OHOS_PERMISSION_DENIED_CODE, "This app have no short permission");
9548         return nullptr;
9549     }
9550 
9551     SetUserIdFromObjectInfo(asyncContext);
9552     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssetsWithMode",
9553         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9554 }
9555 
PhotoAccessStartAssetAnalysis(napi_env env,napi_callback_info info)9556 napi_value MediaLibraryNapi::PhotoAccessStartAssetAnalysis(napi_env env, napi_callback_info info)
9557 {
9558     MediaLibraryTracer tracer;
9559     tracer.Start("PhotoAccessStartAssetAnalysis");
9560 
9561     NAPI_INFO_LOG("enter");
9562     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9563     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9564     asyncContext->assetType = TYPE_PHOTO;
9565     CHECK_COND_WITH_MESSAGE(env, ParseArgsStartAssetAnalysis(env, info, asyncContext) != nullptr,
9566         "Failed to parse js args");
9567 
9568     SetUserIdFromObjectInfo(asyncContext);
9569     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessStartAssetAnalysis",
9570         JSStartAssetAnalysisExecute, JSStartAssetAnalysisCallback);
9571 }
9572 
PhotoAccessQueryExecute(napi_env env,void * data)9573 static void PhotoAccessQueryExecute(napi_env env, void *data)
9574 {
9575     MediaLibraryTracer tracer;
9576     tracer.Start("PhotoAccessQueryExecute");
9577     auto *context = static_cast<ResultSetAsyncContext *>(data);
9578     if (context == nullptr) {
9579         return;
9580     }
9581     context->queryRet = UserFileClient::QueryByStep(context->uri);
9582     if (context->queryRet == nullptr) {
9583         context->error = OHOS_PERMISSION_DENIED_CODE;
9584         context->errorMsg = "Permission denied";
9585         return;
9586     }
9587     int count = -1;
9588     context->queryRet->GetRowCount(count);
9589     if (count == -1) {
9590         context->error = JS_E_PARAM_INVALID;
9591         context->errorMsg = "Invalid sql";
9592         return;
9593     }
9594     return;
9595 }
9596 
PhotoAccessQueryCompleteCallback(napi_env env,napi_status status,void * data)9597 static void PhotoAccessQueryCompleteCallback(napi_env env, napi_status status, void *data)
9598 {
9599     MediaLibraryTracer tracer;
9600     tracer.Start("PhotoAccessQueryCompleteCallback");
9601     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
9602     jsContext->status = false;
9603     status = napi_get_undefined(env, &jsContext->data);
9604     if (status != napi_ok) {
9605         NAPI_INFO_LOG("Napi env error");
9606         return;
9607     }
9608     napi_get_undefined(env, &jsContext->error);
9609     napi_value errorObj;
9610     napi_create_object(env, &errorObj);
9611     auto *context = static_cast<ResultSetAsyncContext *>(data);
9612     if (context != nullptr) {
9613         if (context->error == ERR_DEFAULT && context->queryRet != nullptr) {
9614             jsContext->data = ResultSetNapi::CreateResultSetNapi(env, context->queryRet, *jsContext);
9615             if (jsContext->data == nullptr) {
9616                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, UFM_SYSCAP_BASE,
9617                                                              "CreateResultSet failed");
9618             } else {
9619                 jsContext->status = true;
9620                 context->queryRet = nullptr;
9621             }
9622         } else {
9623             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error, context->errorMsg);
9624         }
9625     } else {
9626         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, UFM_SYSCAP_BASE, "AsyncContext is nullptr");
9627     }
9628     tracer.Finish();
9629     if (context->work != nullptr) {
9630         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work,
9631                                                    *jsContext);
9632     }
9633     delete context;
9634     return;
9635 }
9636 
PhotoAccessQuery(napi_env env,napi_callback_info info)9637 napi_value MediaLibraryNapi::PhotoAccessQuery(napi_env env, napi_callback_info info)
9638 {
9639     MediaLibraryTracer tracer;
9640     tracer.Start("PhotoAccessQuery");
9641     unique_ptr<ResultSetAsyncContext> asyncContext = make_unique<ResultSetAsyncContext>();
9642     CHECK_COND_WITH_ERR_MESSAGE(
9643         env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->uri) == napi_ok,
9644         UFM_SYSCAP_BASE, "Failed to get resourceUrl from arguments or wrong param");
9645     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessQuery", PhotoAccessQueryExecute,
9646                                                       PhotoAccessQueryCompleteCallback);
9647 }
9648 
PhotoAccessHelperAgentCreateAssets(napi_env env,napi_callback_info info)9649 napi_value MediaLibraryNapi::PhotoAccessHelperAgentCreateAssets(napi_env env, napi_callback_info info)
9650 {
9651     MediaLibraryTracer tracer;
9652     tracer.Start("PhotoAccessHelperAgentCreateAssets");
9653 
9654     NAPI_INFO_LOG("enter");
9655     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9656     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET_FOR_APP);
9657     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9658     asyncContext->assetType = TYPE_PHOTO;
9659     asyncContext->needSystemApp = true;
9660     if (!MediaLibraryNapiUtils::IsSystemApp()) {
9661         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
9662         return nullptr;
9663     }
9664     NAPI_ASSERT(env, ParseArgsAgentCreateAssets(env, info, asyncContext), "Failed to parse js args");
9665 
9666     SetUserIdFromObjectInfo(asyncContext);
9667     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssets",
9668         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9669 }
9670 
CreateAssetsForAppWithAlbum(napi_env env,napi_callback_info info)9671 napi_value MediaLibraryNapi::CreateAssetsForAppWithAlbum(napi_env env, napi_callback_info info)
9672 {
9673     MediaLibraryTracer tracer;
9674     tracer.Start("CreateAssetsForAppWithAlbum");
9675 
9676     NAPI_INFO_LOG("enter");
9677     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9678     asyncContext->businessCode =
9679         static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET_FOR_APP_WITH_ALBUM);
9680     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9681     asyncContext->assetType = TYPE_PHOTO;
9682     asyncContext->needSystemApp = true;
9683     if (!MediaLibraryNapiUtils::IsSystemApp()) {
9684         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
9685         return nullptr;
9686     }
9687     NAPI_ASSERT(env, ParseArgsCreatePhotoAssetForAppWithAlbum(env, info, asyncContext), "Failed to parse js args");
9688 
9689     SetUserIdFromObjectInfo(asyncContext);
9690     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreateAssetsForAppWithAlbum",
9691         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9692 }
9693 
CreateAssetsHasPermission(napi_env env,napi_callback_info info)9694 napi_value MediaLibraryNapi::CreateAssetsHasPermission(napi_env env, napi_callback_info info)
9695 {
9696     MediaLibraryTracer tracer;
9697     tracer.Start("PhotoAccessHelperAgentCreateAssets");
9698 
9699     NAPI_INFO_LOG("enter");
9700     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9701     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_PUBLIC_CREATE_ASSET_FOR_APP);
9702     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9703     asyncContext->assetType = TYPE_PHOTO;
9704     NAPI_ASSERT(env, ParseArgsAgentCreateAssets(env, info, asyncContext), "Failed to parse js args");
9705 
9706     SetUserIdFromObjectInfo(asyncContext);
9707     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssets",
9708         PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9709 }
9710 
PhotoAccessHelperOnCallback(napi_env env,napi_callback_info info)9711 napi_value MediaLibraryNapi::PhotoAccessHelperOnCallback(napi_env env, napi_callback_info info)
9712 {
9713     MediaLibraryTracer tracer;
9714     tracer.Start("PhotoAccessHelperOnCallback");
9715     napi_value undefinedResult = nullptr;
9716     napi_get_undefined(env, &undefinedResult);
9717     size_t argc = ARGS_THREE;
9718     napi_value argv[ARGS_THREE] = {nullptr};
9719     napi_value thisVar = nullptr;
9720     GET_JS_ARGS(env, info, argc, argv, thisVar);
9721     if (argc == ARGS_TWO) {
9722         return JSOnCallback(env, info);
9723     }
9724     NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
9725     MediaLibraryNapi *obj = nullptr;
9726     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
9727     if (status == napi_ok && obj != nullptr) {
9728         napi_valuetype valueType = napi_undefined;
9729         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
9730             napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
9731             napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
9732             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9733             return undefinedResult;
9734         }
9735         char buffer[ARG_BUF_SIZE];
9736         size_t res = 0;
9737         if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
9738             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9739             return undefinedResult;
9740         }
9741         string uri = string(buffer);
9742         bool isDerived = false;
9743         if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
9744             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9745             return undefinedResult;
9746         }
9747         const int32_t refCount = 1;
9748         napi_ref cbOnRef = nullptr;
9749         napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
9750         tracer.Start("RegisterNotifyChange");
9751         if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
9752             obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
9753         } else {
9754             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9755             napi_delete_reference(env, cbOnRef);
9756             cbOnRef = nullptr;
9757             return undefinedResult;
9758         }
9759         tracer.Finish();
9760     }
9761     return undefinedResult;
9762 }
9763 
AddClientObserver(napi_env env,napi_ref ref,std::map<Notification::NotifyUriType,std::vector<std::shared_ptr<ClientObserver>>> & clientObservers,const Notification::NotifyUriType uriType)9764 int32_t MediaLibraryNapi::AddClientObserver(napi_env env, napi_ref ref,
9765     std::map<Notification::NotifyUriType, std::vector<std::shared_ptr<ClientObserver>>> &clientObservers,
9766     const Notification::NotifyUriType uriType)
9767 {
9768     auto iter = clientObservers.find(uriType);
9769     if (iter == clientObservers.end()) {
9770         shared_ptr<ClientObserver> clientObserver = make_shared<ClientObserver>(uriType, ref);
9771         clientObservers[uriType].push_back(clientObserver);
9772         return E_OK;
9773     }
9774     napi_value callback = nullptr;
9775     napi_status status = napi_get_reference_value(env, ref, &callback);
9776     if (status != napi_ok) {
9777         NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9778         return OHOS_INVALID_PARAM_CODE;
9779     }
9780 
9781     bool hasRegister = false;
9782     auto observers = iter->second;
9783     for (auto &observer : observers) {
9784         napi_value onCallback = nullptr;
9785         status = napi_get_reference_value(env, observer->ref_, &onCallback);
9786         if (status != napi_ok) {
9787             NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9788             return OHOS_INVALID_PARAM_CODE;
9789         }
9790         napi_strict_equals(env, callback, onCallback, &hasRegister);
9791         if (hasRegister) {
9792             NAPI_INFO_LOG("clientObserver hasRegister");
9793             return JS_E_PARAM_INVALID;
9794         }
9795     }
9796     if (!hasRegister) {
9797         shared_ptr<ClientObserver> clientObserver = make_shared<ClientObserver>(uriType, ref);
9798         clientObservers[uriType].push_back(clientObserver);
9799     }
9800     return E_OK;
9801 }
9802 
RegisterObserverExecute(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,const Notification::NotifyUriType uriType)9803 int32_t MediaLibraryNapi::RegisterObserverExecute(napi_env env, napi_ref ref, ChangeListenerNapi &listObj,
9804     const Notification::NotifyUriType uriType)
9805 {
9806     // 根据uri获取对应的 注册uri
9807     Notification::NotifyUriType registerUriType = Notification::NotifyUriType::INVALID;
9808     std::string registerUri = "";
9809     if (MediaLibraryNotifyUtils::GetNotifyTypeAndUri(uriType, registerUriType, registerUri) != E_OK) {
9810         return JS_E_PARAM_INVALID;
9811     }
9812 
9813     for (auto it = listObj.newObservers_.begin(); it != listObj.newObservers_.end(); it++) {
9814         Notification::NotifyUriType observerUri = (*it)->uriType_;
9815         if (observerUri == registerUriType) {
9816             //判断是否已有callback,没有则加入,有则返回false
9817             auto& clientObservers = (*it)->clientObservers_;
9818             return AddClientObserver(env, ref, clientObservers, uriType);
9819         }
9820     }
9821     // list 中没有,新建一个,并且服务端注册
9822     shared_ptr<MediaOnNotifyNewObserver> observer =
9823         make_shared<MediaOnNotifyNewObserver>(registerUriType, registerUri, env);
9824     Uri notifyUri(registerUri);
9825     int32_t ret = UserFileClient::RegisterObserverExtProvider(notifyUri,
9826         static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), false);
9827     if (ret != E_OK) {
9828         NAPI_ERR_LOG("failed to register observer, ret: %{public}d, uri: %{public}s", ret, registerUri.c_str());
9829         return ret;
9830     }
9831 
9832     shared_ptr<ClientObserver> clientObserver = make_shared<ClientObserver>(uriType, ref);
9833     observer->clientObservers_[uriType].push_back(clientObserver);
9834     listObj.newObservers_.push_back(observer);
9835     NAPI_INFO_LOG("success to register observer, ret: %{public}d, uri: %{public}s", ret, registerUri.c_str());
9836     return ret;
9837 }
9838 
PhotoAccessRegisterCallback(napi_env env,napi_callback_info info)9839 napi_value MediaLibraryNapi::PhotoAccessRegisterCallback(napi_env env, napi_callback_info info)
9840 {
9841     NAPI_INFO_LOG("enter PhotoAccessRegisterCallback");
9842     MediaLibraryTracer tracer;
9843     tracer.Start("PhotoAccessRegisterCallback");
9844     napi_value undefinedResult = nullptr;
9845     napi_get_undefined(env, &undefinedResult);
9846     size_t argc = ARGS_TWO;
9847     napi_value argv[ARGS_TWO] = {nullptr};
9848     napi_value thisVar = nullptr;
9849     GET_JS_ARGS(env, info, argc, argv, thisVar);
9850     if (argc != ARGS_TWO) {
9851         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requires 2 parameters.");
9852         return undefinedResult;
9853     }
9854 
9855     napi_valuetype valueType = napi_undefined;
9856     if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
9857         napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
9858         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9859         return undefinedResult;
9860     }
9861     char buffer[ARG_BUF_SIZE];
9862     size_t res = 0;
9863     if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
9864         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9865         return undefinedResult;
9866     }
9867     string type = string(buffer);
9868     Notification::NotifyUriType uriType = Notification::NotifyUriType::INVALID;
9869     if (MediaLibraryNotifyUtils::GetRegisterNotifyType(type, uriType) != E_OK) {
9870         NapiError::ThrowError(env, JS_E_PARAM_INVALID, "The scenario parameter verification fails.");
9871         return undefinedResult;
9872     }
9873 
9874     const int32_t refCount = 1;
9875     napi_ref cbOnRef = nullptr;
9876     napi_create_reference(env, argv[PARAM1], refCount, &cbOnRef);
9877     int32_t ret = RegisterObserverExecute(env, cbOnRef, *g_listObj, uriType);
9878     if (ret == E_OK) {
9879         NAPI_INFO_LOG("PhotoAccessRegisterCallback success");
9880     } else {
9881         NapiError::ThrowError(env, MediaLibraryNotifyUtils::ConvertToJsError(ret));
9882         napi_delete_reference(env, cbOnRef);
9883         return undefinedResult;
9884     }
9885     return undefinedResult;
9886 }
9887 
RemoveClientObserver(napi_env env,napi_ref ref,map<Notification::NotifyUriType,vector<shared_ptr<ClientObserver>>> & clientObservers,const Notification::NotifyUriType uriType)9888 int32_t MediaLibraryNapi::RemoveClientObserver(napi_env env, napi_ref ref,
9889     map<Notification::NotifyUriType, vector<shared_ptr<ClientObserver>>> &clientObservers,
9890     const Notification::NotifyUriType uriType)
9891 {
9892     if (clientObservers.find(uriType) == clientObservers.end()) {
9893         NAPI_ERR_LOG("invalid register uriType");
9894         return JS_E_PARAM_INVALID;
9895     }
9896     if (ref == nullptr) {
9897         NAPI_ERR_LOG("remove all client observers of uriType");
9898         clientObservers.erase(uriType);
9899         return E_OK;
9900     }
9901     napi_value offCallback = nullptr;
9902     napi_status status = napi_get_reference_value(env, ref, &offCallback);
9903     if (status != napi_ok) {
9904         NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9905         return OHOS_INVALID_PARAM_CODE;
9906     }
9907 
9908     bool hasRegister = false;
9909     for (auto iter = clientObservers[uriType].begin(); iter != clientObservers[uriType].end(); iter++) {
9910         napi_value onCallback = nullptr;
9911         status = napi_get_reference_value(env, (*iter)->ref_, &onCallback);
9912         if (status != napi_ok) {
9913             NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9914             return OHOS_INVALID_PARAM_CODE;
9915         }
9916         napi_strict_equals(env, offCallback, onCallback, &hasRegister);
9917         if (!hasRegister) {
9918             continue;
9919         }
9920 
9921         clientObservers[uriType].erase(iter);
9922         if (clientObservers[uriType].empty()) {
9923             clientObservers.erase(uriType);
9924         }
9925         return E_OK;
9926     }
9927     NAPI_ERR_LOG("failed to find observer");
9928     return JS_E_PARAM_INVALID;
9929 }
9930 
UnregisterObserverExecute(napi_env env,const Notification::NotifyUriType uriType,napi_ref ref,ChangeListenerNapi & listObj)9931 int32_t MediaLibraryNapi::UnregisterObserverExecute(napi_env env,
9932     const Notification::NotifyUriType uriType, napi_ref ref, ChangeListenerNapi &listObj)
9933 {
9934     if (listObj.newObservers_.size() == 0) {
9935         NAPI_ERR_LOG("listObj.newObservers_ size 0");
9936         return JS_E_PARAM_INVALID;
9937     }
9938 
9939     // 根据uri获取对应的 注册uri
9940     Notification::NotifyUriType registerUriType = Notification::NotifyUriType::INVALID;
9941     std::string registerUri = "";
9942     if (MediaLibraryNotifyUtils::GetNotifyTypeAndUri(uriType, registerUriType, registerUri) != E_OK) {
9943         return JS_E_PARAM_INVALID;
9944     }
9945 
9946     // 如果注册uri对应的newObserver不存在,无需解注册
9947     // 如果注册uri对应的newObserver存在
9948     // 参数:对应的newObserver的clientobserver中是否存在对应callback,存在,删除并且看看是否删除为空的对应的newObserver
9949     int32_t ret = JS_E_PARAM_INVALID;
9950     for (auto it = listObj.newObservers_.begin(); it != listObj.newObservers_.end(); it++) {
9951         Notification::NotifyUriType observerUri = (*it)->uriType_;
9952         if (observerUri != registerUriType) {
9953             continue;
9954         }
9955         auto& clientObservers = (*it)->clientObservers_;
9956 
9957         ret = RemoveClientObserver(env, ref, clientObservers, uriType);
9958         if (ret == E_OK && clientObservers.empty()) {
9959             ret = UserFileClient::UnregisterObserverExtProvider(Uri(registerUri),
9960                 static_cast<shared_ptr<DataShare::DataShareObserver>>(*it));
9961             if (ret != E_OK) {
9962                 NAPI_ERR_LOG("failed to unregister observer, ret: %{public}d, uri: %{public}s",
9963                     ret, registerUri.c_str());
9964                 return ret;
9965             }
9966             std::vector<shared_ptr<MediaOnNotifyNewObserver>>::iterator tmp = it;
9967             listObj.newObservers_.erase(tmp);
9968             NAPI_INFO_LOG("success to unregister observer, ret: %{public}d, uri: %{public}s", ret, registerUri.c_str());
9969         }
9970         return ret;
9971     }
9972     return ret;
9973 }
9974 
CheckUnregisterCallbackArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)9975 static napi_value CheckUnregisterCallbackArgs(napi_env env, napi_callback_info info,
9976     unique_ptr<MediaLibraryAsyncContext> &context)
9977 {
9978     napi_value thisVar = nullptr;
9979     context->argc = ARGS_TWO;
9980     GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
9981 
9982     if (context->argc < ARGS_ONE || context->argc > ARGS_TWO) {
9983         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requires one or two parameters.");
9984         return nullptr;
9985     }
9986 
9987     if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
9988         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9989         return nullptr;
9990     }
9991 
9992     napi_valuetype valueType = napi_undefined;
9993     if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
9994         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9995         return nullptr;
9996     }
9997 
9998     return thisVar;
9999 }
10000 
PhotoAccessUnregisterCallback(napi_env env,napi_callback_info info)10001 napi_value MediaLibraryNapi::PhotoAccessUnregisterCallback(napi_env env, napi_callback_info info)
10002 {
10003     NAPI_INFO_LOG("ento PhotoAccessUnregisterCallback");
10004     MediaLibraryTracer tracer;
10005     tracer.Start("PhotoAccessUnregisterCallback");
10006     napi_value undefinedResult = nullptr;
10007     napi_get_undefined(env, &undefinedResult);
10008     if (g_listObj == nullptr) {
10009         return undefinedResult;
10010     }
10011     unique_ptr<MediaLibraryAsyncContext> context = make_unique<MediaLibraryAsyncContext>();
10012     if (CheckUnregisterCallbackArgs(env, info, context) == nullptr) {
10013         return undefinedResult;
10014     }
10015     char buffer[ARG_BUF_SIZE];
10016     size_t res = 0;
10017     if (napi_get_value_string_utf8(env, context->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
10018         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
10019         return undefinedResult;
10020     }
10021     string type = string(buffer);
10022     Notification::NotifyUriType uriType = Notification::NotifyUriType::INVALID;
10023     if (MediaLibraryNotifyUtils::GetRegisterNotifyType(type, uriType) != E_OK) {
10024         NapiError::ThrowError(env, JS_E_PARAM_INVALID);
10025         return undefinedResult;
10026     }
10027     napi_valuetype valueType = napi_undefined;
10028     napi_ref cbOffRef = nullptr;
10029     if (context->argc == ARGS_TWO) {
10030         if (napi_typeof(env, context->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
10031             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
10032             return undefinedResult;
10033         }
10034         const int32_t refCount = 1;
10035         napi_create_reference(env, context->argv[PARAM1], refCount, &cbOffRef);
10036     }
10037     int32_t ret = UnregisterObserverExecute(env, uriType, cbOffRef, *g_listObj);
10038     if (ret != E_OK) {
10039         NapiError::ThrowError(env, MediaLibraryNotifyUtils::ConvertToJsError(ret));
10040     }
10041     if (cbOffRef != nullptr) {
10042         napi_delete_reference(env, cbOffRef);
10043     }
10044     return undefinedResult;
10045 }
10046 
PhotoAccessHelperOffCallback(napi_env env,napi_callback_info info)10047 napi_value MediaLibraryNapi::PhotoAccessHelperOffCallback(napi_env env, napi_callback_info info)
10048 {
10049     MediaLibraryTracer tracer;
10050     tracer.Start("PhotoAccessHelperOffCallback");
10051     napi_value undefinedResult = nullptr;
10052     napi_get_undefined(env, &undefinedResult);
10053 
10054     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
10055     napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
10056     MediaLibraryNapi *obj = nullptr;
10057     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
10058     if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
10059         return undefinedResult;
10060     }
10061     size_t res = 0;
10062     char buffer[ARG_BUF_SIZE];
10063     if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
10064         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10065         return undefinedResult;
10066     }
10067 
10068     string uri = string(buffer);
10069     napi_valuetype valueType = napi_undefined;
10070     if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
10071         if (asyncContext->argc == ARGS_TWO) {
10072             if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
10073                 return undefinedResult;
10074             }
10075             const int32_t refCount = 1;
10076             napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
10077         }
10078         obj->UnregisterChange(env, uri, *g_listObj);
10079         return undefinedResult;
10080     }
10081     napi_ref cbOffRef = nullptr;
10082     if (asyncContext->argc == ARGS_TWO) {
10083         if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
10084             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10085             return undefinedResult;
10086         }
10087         const int32_t refCount = 1;
10088         napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
10089     }
10090     tracer.Start("UnRegisterNotifyChange");
10091     obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
10092     return undefinedResult;
10093 }
10094 
ParseArgsPHAccessHelperTrash(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)10095 napi_value ParseArgsPHAccessHelperTrash(napi_env env, napi_callback_info info,
10096     unique_ptr<MediaLibraryAsyncContext> &context)
10097 {
10098     if (!MediaLibraryNapiUtils::IsSystemApp()) {
10099         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
10100         return nullptr;
10101     }
10102 
10103     vector<string> uris;
10104     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringArrayCallback(env, info, context, uris),
10105         JS_ERR_PARAMETER_INVALID);
10106     if (uris.empty()) {
10107         NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
10108         return nullptr;
10109     }
10110     for (const auto &uri : uris) {
10111         if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
10112             NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
10113             return nullptr;
10114         }
10115     }
10116     context->uris = uris;
10117 
10118     napi_value result = nullptr;
10119     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
10120     return result;
10121 }
10122 
PhotoAccessHelperTrashExecute(napi_env env,void * data)10123 static void PhotoAccessHelperTrashExecute(napi_env env, void *data)
10124 {
10125     MediaLibraryTracer tracer;
10126     tracer.Start("PhotoAccessHelperTrashExecute");
10127 
10128     auto *context = static_cast<MediaLibraryAsyncContext *>(data);
10129     CHECK_NULL_PTR_RETURN_VOID(context, "context is null");
10130     CHECK_IF_EQUAL(!context->uris.empty(), "uris is empty");
10131 
10132     TrashPhotosReqBody reqBody;
10133     reqBody.uris = context->uris;
10134     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYS_TRASH_PHOTOS);
10135     int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
10136     if (changedRows < 0) {
10137         context->SaveError(changedRows);
10138         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
10139     }
10140 }
10141 
PhotoAccessHelperTrashAsset(napi_env env,napi_callback_info info)10142 napi_value MediaLibraryNapi::PhotoAccessHelperTrashAsset(napi_env env, napi_callback_info info)
10143 {
10144     NAPI_INFO_LOG("enter");
10145     napi_value ret = nullptr;
10146     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
10147     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
10148     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
10149     CHECK_NULLPTR_RET(ParseArgsPHAccessHelperTrash(env, info, asyncContext));
10150 
10151     SetUserIdFromObjectInfo(asyncContext);
10152     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperTrashAsset",
10153         PhotoAccessHelperTrashExecute, JSTrashAssetCompleteCallback);
10154 }
10155 
ParseArgsSetHidden(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)10156 napi_value ParseArgsSetHidden(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
10157 {
10158     if (!MediaLibraryNapiUtils::IsSystemApp()) {
10159         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
10160         return nullptr;
10161     }
10162     napi_value result = nullptr;
10163     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
10164 
10165     constexpr size_t minArgs = ARGS_ONE;
10166     constexpr size_t maxArgs = ARGS_THREE;
10167     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
10168         JS_ERR_PARAMETER_INVALID);
10169 
10170     /* Parse the first argument */
10171     vector<napi_value> napiValues;
10172     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM0], napiValues));
10173     if (napiValues.empty()) {
10174         return result;
10175     }
10176     napi_valuetype valueType = napi_undefined;
10177     vector<string> uris;
10178     CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_ERR_PARAMETER_INVALID);
10179     if (valueType == napi_string) {
10180         // The input should be an array of asset uri.
10181         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetStringArray(env, napiValues, uris));
10182     } else if (valueType == napi_object) {
10183         // The input should be an array of asset object.
10184         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uris));
10185     }
10186     if (uris.empty()) {
10187         return result;
10188     }
10189     bool hiddenState = false;
10190     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[PARAM1], hiddenState),
10191         JS_ERR_PARAMETER_INVALID);
10192     context->predicates.In(MediaColumn::MEDIA_ID, uris);
10193     context->valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, static_cast<int32_t>(hiddenState));
10194     return result;
10195 }
10196 
SetHiddenExecute(napi_env env,void * data)10197 static void SetHiddenExecute(napi_env env, void *data)
10198 {
10199     MediaLibraryTracer tracer;
10200     tracer.Start("SetHiddenExecute");
10201 
10202     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10203     string hideUri = PAH_HIDE_PHOTOS;
10204     MediaLibraryNapiUtils::UriAppendKeyValue(hideUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
10205     Uri uri(hideUri);
10206     int32_t changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
10207     if (changedRows < 0) {
10208         context->SaveError(changedRows);
10209         NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
10210     }
10211 }
10212 
SetHiddenCompleteCallback(napi_env env,napi_status status,void * data)10213 static void SetHiddenCompleteCallback(napi_env env, napi_status status, void *data)
10214 {
10215     MediaLibraryTracer tracer;
10216     tracer.Start("SetHiddenCompleteCallback");
10217 
10218     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10219     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
10220     jsContext->status = false;
10221     if (context->error == ERR_DEFAULT) {
10222         jsContext->status = true;
10223         napi_get_undefined(env, &jsContext->error);
10224         napi_get_undefined(env, &jsContext->data);
10225     } else {
10226         napi_get_undefined(env, &jsContext->data);
10227         context->HandleError(env, jsContext->error);
10228     }
10229     if (context->work != nullptr) {
10230         tracer.Finish();
10231         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
10232             context->work, *jsContext);
10233     }
10234 
10235     delete context;
10236 }
10237 
SetHidden(napi_env env,napi_callback_info info)10238 napi_value MediaLibraryNapi::SetHidden(napi_env env, napi_callback_info info)
10239 {
10240     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
10241     CHECK_NULLPTR_RET(ParseArgsSetHidden(env, info, asyncContext));
10242 
10243     SetUserIdFromObjectInfo(asyncContext);
10244     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "SetHidden",
10245         SetHiddenExecute, SetHiddenCompleteCallback);
10246 }
10247 
ParseArgsPahGetHiddenAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)10248 napi_value ParseArgsPahGetHiddenAlbums(napi_env env, napi_callback_info info,
10249     unique_ptr<MediaLibraryAsyncContext> &context)
10250 {
10251     if (!MediaLibraryNapiUtils::IsSystemApp()) {
10252         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
10253         return nullptr;
10254     }
10255     napi_value result = nullptr;
10256     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
10257     napi_status status = MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, ARGS_ONE, ARGS_THREE);
10258     CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10259 
10260     int32_t fetchMode = 0;
10261     status = MediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode);
10262     CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10263     if (fetchMode != HiddenPhotosDisplayMode::ASSETS_MODE && fetchMode != HiddenPhotosDisplayMode::ALBUMS_MODE) {
10264         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid fetch mode: " + to_string(fetchMode));
10265         return nullptr;
10266     }
10267 
10268     bool hasCallback = false;
10269     status = MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback);
10270     CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10271     if ((context->argc - hasCallback) == ARGS_TWO) {
10272         status = MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ALBUM_FETCH_OPT, context);
10273         CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10274     }
10275 
10276     CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
10277     context->hiddenAlbumFetchMode = fetchMode;
10278     return result;
10279 }
10280 
CallPahGetHiddenAlbums(MediaLibraryAsyncContext * context,int32_t & errCode)10281 static std::shared_ptr<DataShareResultSet> CallPahGetHiddenAlbums(MediaLibraryAsyncContext *context, int32_t &errCode)
10282 {
10283     if (context->businessCode != 0) {
10284         QueryAlbumsReqBody reqBody;
10285         QueryAlbumsRespBody respBody;
10286         reqBody.columns = context->fetchColumn;
10287         reqBody.predicates = context->predicates;
10288         reqBody.hiddenAlbumFetchMode = context->hiddenAlbumFetchMode;
10289         errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
10290         if (errCode != 0) {
10291             NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
10292             return nullptr;
10293         }
10294         return respBody.resultSet;
10295     }
10296 
10297     Uri uri(PAH_QUERY_HIDDEN_ALBUM);
10298     AddDefaultPhotoAlbumColumns(context->fetchColumn);
10299     if (context->hiddenAlbumFetchMode == ALBUMS_MODE) {
10300         context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COUNT);
10301         context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COVER);
10302         context->predicates.EqualTo(PhotoAlbumColumns::CONTAINS_HIDDEN, to_string(1));
10303     } else {
10304         context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::HIDDEN);
10305     }
10306     return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
10307 }
10308 
JSPahGetHiddenAlbumsExecute(napi_env env,void * data)10309 static void JSPahGetHiddenAlbumsExecute(napi_env env, void *data)
10310 {
10311     MediaLibraryTracer tracer;
10312     tracer.Start("JSPahGetHiddenAlbumsExecute");
10313 
10314     int32_t errCode = 0;
10315     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10316     std::shared_ptr<DataShareResultSet> resultSet = CallPahGetHiddenAlbums(context, errCode);
10317     if (resultSet == nullptr) {
10318         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
10319         if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
10320             context->SaveError(errCode);
10321         } else {
10322             context->SaveError(E_HAS_DB_ERROR);
10323         }
10324         return;
10325     }
10326     context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
10327     context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
10328     context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenAlbumFetchMode == ALBUMS_MODE);
10329     context->fetchPhotoAlbumResult->SetLocationOnly(false);
10330     context->fetchPhotoAlbumResult->SetUserId(context->userId);
10331 }
10332 
PahGetHiddenAlbums(napi_env env,napi_callback_info info)10333 napi_value MediaLibraryNapi::PahGetHiddenAlbums(napi_env env, napi_callback_info info)
10334 {
10335     auto asyncContext = make_unique<MediaLibraryAsyncContext>();
10336     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
10337     CHECK_NULLPTR_RET(ParseArgsPahGetHiddenAlbums(env, info, asyncContext));
10338     asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_QUERY_HIDDEN_ALBUMS);
10339 
10340     SetUserIdFromObjectInfo(asyncContext);
10341     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetHiddenAlbums",
10342         JSPahGetHiddenAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
10343 }
10344 
JSApplyChanges(napi_env env,napi_callback_info info)10345 napi_value MediaLibraryNapi::JSApplyChanges(napi_env env, napi_callback_info info)
10346 {
10347     size_t argc = ARGS_TWO;
10348     napi_value argv[ARGS_TWO] = { 0 };
10349     napi_value thisVar = nullptr;
10350     napi_valuetype valueType;
10351     MediaLibraryNapi* mediaLibraryNapi;
10352     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
10353     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&mediaLibraryNapi)), JS_INNER_FAIL);
10354     CHECK_COND_WITH_MESSAGE(env, mediaLibraryNapi != nullptr, "Failed to get object info");
10355 
10356     CHECK_COND_WITH_MESSAGE(env, argc >= ARGS_ONE && argc <= ARGS_TWO, "Number of args is invalid");
10357     CHECK_ARGS(env, napi_typeof(env, argv[PARAM0], &valueType), JS_INNER_FAIL);
10358     CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
10359 
10360     MediaChangeRequestNapi* obj;
10361     CHECK_ARGS(env, napi_unwrap(env, argv[PARAM0], reinterpret_cast<void**>(&obj)), JS_INNER_FAIL);
10362     CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "MediaChangeRequestNapi object is null");
10363     return obj->ApplyChanges(env, info);
10364 }
10365 
initRequest(OHOS::AAFwk::Want & request,shared_ptr<DeleteCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10366 static napi_value initRequest(OHOS::AAFwk::Want &request, shared_ptr<DeleteCallback> &callback,
10367                               napi_env env, napi_value args[], size_t argsLen)
10368 {
10369     if (argsLen < ARGS_THREE) {
10370         return nullptr;
10371     }
10372     napi_value result = nullptr;
10373     napi_create_object(env, &result);
10374     request.SetElementName(DELETE_UI_PACKAGE_NAME, DELETE_UI_EXT_ABILITY_NAME);
10375     request.SetParam(DELETE_UI_EXTENSION_TYPE, DELETE_UI_REQUEST_TYPE);
10376 
10377     size_t nameRes = 0;
10378     char nameBuffer[ARG_BUF_SIZE];
10379     if (napi_get_value_string_utf8(env, args[ARGS_ONE], nameBuffer, ARG_BUF_SIZE, &nameRes) != napi_ok) {
10380         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10381         return nullptr;
10382     }
10383     string appName = string(nameBuffer);
10384     request.SetParam(DELETE_UI_APPNAME, appName);
10385 
10386     vector<string> uris;
10387     uint32_t len = 0;
10388     CHECK_ARGS(env, napi_get_array_length(env, args[ARGS_TWO], &len), JS_ERR_PARAMETER_INVALID);
10389     char uriBuffer[ARG_BUF_SIZE];
10390     for (uint32_t i = 0; i < len; i++) {
10391         napi_value uri = nullptr;
10392         CHECK_ARGS(env, napi_get_element(env, args[ARGS_TWO], i, &uri), JS_ERR_PARAMETER_INVALID);
10393         if (uri == nullptr) {
10394             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10395             return nullptr;
10396         }
10397         size_t uriRes = 0;
10398         CHECK_ARGS(env, napi_get_value_string_utf8(env, uri, uriBuffer, ARG_BUF_SIZE, &uriRes),
10399                    JS_ERR_PARAMETER_INVALID);
10400         uris.push_back(string(uriBuffer));
10401     }
10402     request.SetParam(DELETE_UI_URIS, uris);
10403     callback->SetUris(uris);
10404     callback->SetFunc(args[ARGS_THREE]);
10405     return result;
10406 }
10407 
CreateDeleteRequest(napi_env env,napi_callback_info info)10408 napi_value MediaLibraryNapi::CreateDeleteRequest(napi_env env, napi_callback_info info)
10409 {
10410 #ifdef HAS_ACE_ENGINE_PART
10411     size_t argc = ARGS_FOUR;
10412     napi_value args[ARGS_FOUR] = {nullptr};
10413     napi_value thisVar = nullptr;
10414     napi_value result = nullptr;
10415     napi_create_object(env, &result);
10416     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
10417     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10418     NAPI_ASSERT(env, context != nullptr, "context == nullptr");
10419 
10420     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10421         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10422     NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
10423 
10424     auto uiContent = abilityContext->GetUIContent();
10425     NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
10426 
10427     auto callback = std::make_shared<DeleteCallback>(env, uiContent);
10428     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10429         ([callback](auto arg) { callback->OnRelease(arg); }),
10430         ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
10431         ([callback](auto arg) { callback->OnReceive(arg); }),
10432         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
10433     };
10434     OHOS::Ace::ModalUIExtensionConfig config;
10435     config.isProhibitBack = true;
10436     OHOS::AAFwk::Want request;
10437     napi_value initRequestResult = initRequest(request, callback, env, args, sizeof(args));
10438     NAPI_ASSERT(env, initRequestResult != nullptr, "initRequest fail");
10439 
10440     int32_t sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
10441     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10442 
10443     callback->SetSessionId(sessionId);
10444     return result;
10445 #else
10446     NapiError::ThrowError(env, JS_INNER_FAIL, "ace_engine is not support");
10447     return nullptr;
10448 #endif
10449 }
10450 
10451 #ifdef HAS_ACE_ENGINE_PART
ParseString(const napi_env & env,const napi_value & value,std::string & result)10452 static bool ParseString(const napi_env &env, const napi_value &value, std::string &result)
10453 {
10454     size_t size = 0;
10455 
10456     CHECK_COND_RET(napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok, false,
10457         "Failed to get string length.");
10458 
10459     result.reserve(size + 1);
10460     result.resize(size);
10461 
10462     CHECK_COND_RET(napi_get_value_string_utf8(env, value, result.data(), size + 1, &size) == napi_ok, false,
10463         "Failed to get string value.");
10464 
10465     return true;
10466 }
10467 
ParseAndSetFileUriArray(const napi_env & env,OHOS::AAFwk::Want & want,const napi_value & value)10468 static bool ParseAndSetFileUriArray(const napi_env &env, OHOS::AAFwk::Want &want, const napi_value &value)
10469 {
10470     uint32_t len = 0;
10471     CHECK_COND_RET(napi_get_array_length(env, value, &len) == napi_ok, false, "Failed to get array length.");
10472     if (len > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
10473         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Array size over 100.");
10474         return false;
10475     }
10476 
10477     vector<string> srcFileUris;
10478     for (uint32_t i = 0; i < len; ++i) {
10479         napi_value element = nullptr;
10480         CHECK_COND_RET(napi_get_element(env, value, i, &element) == napi_ok, false, "Failed to get array element.");
10481         if (element == nullptr) {
10482             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get array element.");
10483             return false;
10484         }
10485 
10486         string srcFileUri;
10487         if (!ParseString(env, element, srcFileUri)) {
10488             return false;
10489         }
10490         NAPI_INFO_LOG("srcFileUri is %{public}s.", srcFileUri.c_str());
10491         AppFileService::ModuleFileUri::FileUri fileUri(srcFileUri);
10492         std::string realUriPath = fileUri.ToString();
10493         NAPI_INFO_LOG("realUriPath is %{public}s.", realUriPath.c_str());
10494 
10495         srcFileUris.emplace_back(realUriPath);
10496     }
10497 
10498     want.SetParam(CONFIRM_BOX_SRC_FILE_URIS, srcFileUris);
10499 
10500     return true;
10501 }
10502 
IsNeedParseProperty(const napi_env & env,const napi_value & value,const string & key,napi_value & property,napi_valuetype & needType)10503 static bool IsNeedParseProperty(const napi_env &env, const napi_value &value, const string &key, napi_value &property,
10504     napi_valuetype &needType)
10505 {
10506     bool hasProp = false;
10507     napi_valuetype valueType = napi_undefined;
10508 
10509     CHECK_COND_RET(napi_has_named_property(env, value, key.c_str(), &hasProp) == napi_ok, false,
10510         "Failed to check named property.");
10511     if (hasProp) {
10512         CHECK_COND_RET(napi_get_named_property(env, value, key.c_str(), &property) == napi_ok, false,
10513             "Failed to get named property.");
10514         CHECK_COND_RET(napi_typeof(env, property, &valueType) == napi_ok, false, "Failed to get value type.");
10515 
10516         return ((valueType != napi_undefined) && (valueType != napi_null) && (valueType == needType));
10517     }
10518 
10519     return hasProp;
10520 }
10521 
ParseConfigObject(const napi_env & env,const napi_value & value,PhotoCreationConfig & config)10522 static bool ParseConfigObject(const napi_env &env, const napi_value &value, PhotoCreationConfig &config)
10523 {
10524     napi_value property = nullptr;
10525     napi_valuetype type = napi_undefined;
10526 
10527     // title: optional
10528     type = napi_string;
10529     if (IsNeedParseProperty(env, value, TITLE, property, type)) {
10530         NAPI_INFO_LOG("With title.");
10531         if (!ParseString(env, property, config.title)) {
10532             return false;
10533         }
10534     }
10535 
10536     // fileNameExtension: mandatory
10537     CHECK_COND_RET(IsNeedParseProperty(env, value, EXTENSION, property, type), false, "Lack param fileNameExtension.");
10538     if (!ParseString(env, property, config.fileNameExtension)) {
10539         return false;
10540     }
10541 
10542     // photoType: mandatory
10543     type = napi_number;
10544     CHECK_COND_RET(IsNeedParseProperty(env, value, PHOTO_TYPE, property, type), false, "Lack param photoType.");
10545     CHECK_COND_RET(napi_get_value_int32(env, property, &(config.photoType)) == napi_ok, false,
10546         "Failed to get number type.");
10547     CHECK_COND_RET(((config.photoType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) || (
10548         (config.photoType) == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO))), false,
10549         "Param photoType is not valid.");
10550 
10551     // subtype: optional
10552     if (IsNeedParseProperty(env, value, PHOTO_SUB_TYPE, property, type)) {
10553         NAPI_INFO_LOG("With subtype.");
10554         CHECK_COND_RET(napi_get_value_int32(env, property, &(config.subtype)) == napi_ok, false,
10555             "Failed to get number type.");
10556         CHECK_COND_RET(((config.subtype == static_cast<int32_t>(PhotoSubType::DEFAULT)) || (
10557             (config.subtype) == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO))), false,
10558             "Param subtype is not valid.");
10559     }
10560 
10561     return true;
10562 }
10563 
ParseAndSetConfigArray(const napi_env & env,OHOS::AAFwk::Want & want,const napi_value & value)10564 static bool ParseAndSetConfigArray(const napi_env &env, OHOS::AAFwk::Want &want, const napi_value &value)
10565 {
10566     uint32_t len = 0;
10567     CHECK_COND_RET(napi_get_array_length(env, value, &len) == napi_ok, false, "Failed to get array length.");
10568     if (len > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
10569         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Array size over 100.");
10570         return false;
10571     }
10572 
10573     vector<string> titleList;
10574     vector<string> extensionList;
10575     vector<int32_t> photoTypeList;
10576     vector<int32_t> photoSubTypeList;
10577 
10578     for (uint32_t i = 0; i < len; ++i) {
10579         napi_value element = nullptr;
10580         CHECK_COND_RET(napi_get_element(env, value, i, &element) == napi_ok, false, "Failed to get array element.");
10581         if (element == nullptr) {
10582             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get array element.");
10583             return false;
10584         }
10585 
10586         PhotoCreationConfig config;
10587         if (!ParseConfigObject(env, element, config)) {
10588             return false;
10589         }
10590 
10591         titleList.emplace_back(config.title);
10592         extensionList.emplace_back(config.fileNameExtension);
10593         photoTypeList.emplace_back(config.photoType);
10594         photoSubTypeList.emplace_back(config.subtype);
10595     }
10596 
10597     // separate Array<PhotoCreationConfig> into Array<string> + Array<string> + Array<number> + Array<number>
10598     want.SetParam(CONFIRM_BOX_TITLE_ARRAY, titleList);
10599     want.SetParam(CONFIRM_BOX_EXTENSION_ARRAY, extensionList);
10600     want.SetParam(CONFIRM_BOX_PHOTO_TYPE_ARRAY, photoTypeList);
10601     want.SetParam(CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY, photoSubTypeList);
10602 
10603     return true;
10604 }
10605 
InitConfirmRequest(OHOS::AAFwk::Want & want,shared_ptr<ConfirmCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10606 static bool InitConfirmRequest(OHOS::AAFwk::Want &want, shared_ptr<ConfirmCallback> &callback,
10607                                napi_env env, napi_value args[], size_t argsLen)
10608 {
10609     if (argsLen < ARGS_SEVEN) {
10610         return false;
10611     }
10612 
10613     want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
10614     want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
10615     want.AddFlags(Want::FLAG_AUTH_READ_URI_PERMISSION);
10616 
10617     // second param: Array<string>
10618     if (!ParseAndSetFileUriArray(env, want, args[PARAM1])) {
10619         return false;
10620     }
10621 
10622     // third param: Array<PhotoCreationConfig>
10623     if (!ParseAndSetConfigArray(env, want, args[PARAM2])) {
10624         return false;
10625     }
10626 
10627     // fourth param: string
10628     string bundleName;
10629     if (!ParseString(env, args[PARAM3], bundleName)) {
10630         return false;
10631     }
10632     want.SetParam(CONFIRM_BOX_BUNDLE_NAME, bundleName);
10633 
10634     // fifth param: string
10635     string appName;
10636     if (!ParseString(env, args[PARAM4], appName)) {
10637         return false;
10638     }
10639     want.SetParam(CONFIRM_BOX_APP_NAME, appName);
10640 
10641     // sixth param: string
10642     string appId;
10643     if (!ParseString(env, args[PARAM5], appId)) {
10644         return false;
10645     }
10646     want.SetParam(CONFIRM_BOX_APP_ID, appId);
10647 
10648     // seventh param: function
10649     callback->SetFunc(args[PARAM6]);
10650 
10651     return true;
10652 }
10653 #endif
10654 
ShowAssetsCreationDialog(napi_env env,napi_callback_info info)10655 napi_value MediaLibraryNapi::ShowAssetsCreationDialog(napi_env env, napi_callback_info info)
10656 {
10657 #ifdef HAS_ACE_ENGINE_PART
10658     size_t argc = ARGS_SEVEN;
10659     napi_value args[ARGS_SEVEN] = {nullptr};
10660     napi_value thisVar = nullptr;
10661     napi_value result = nullptr;
10662     napi_create_object(env, &result);
10663     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), OHOS_INVALID_PARAM_CODE);
10664 
10665     // first param: context, check whether context is abilityContext from stage mode
10666     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10667     NAPI_ASSERT(env, context != nullptr, "Context is null.");
10668 
10669     std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10670         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10671     NAPI_ASSERT(env, abilityContext != nullptr, "AbilityContext is null.");
10672 
10673     // get uiContent from abilityContext, this api should be called after loadContent, otherwise uiContent is nullptr
10674     auto uiContent = abilityContext->GetUIContent();
10675     NAPI_ASSERT(env, uiContent != nullptr, "UiContent is null.");
10676 
10677     // set want
10678     OHOS::AAFwk::Want want;
10679     auto callback = std::make_shared<ConfirmCallback>(env, uiContent);
10680     NAPI_ASSERT(env, InitConfirmRequest(want, callback, env, args, sizeof(args)), "Parse input fail.");
10681 
10682     // regist callback and config
10683     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10684         [callback](int32_t releaseCode) {
10685             callback->OnRelease(releaseCode);
10686         },
10687         [callback](int32_t resultCode, const AAFwk::Want &result) {
10688             callback->OnResult(resultCode, result);
10689         },
10690         [callback](const AAFwk::WantParams &receive) {
10691             callback->OnReceive(receive);
10692         },
10693         [callback](int32_t code, const std::string &name, const std::string &message) {
10694             callback->OnError(code, name, name);
10695         },
10696     };
10697     OHOS::Ace::ModalUIExtensionConfig config;
10698     config.isProhibitBack = true;
10699 
10700     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
10701     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10702 
10703     NAPI_INFO_LOG("SessionId is %{public}d.", sessionId);
10704 
10705     callback->SetSessionId(sessionId);
10706     return result;
10707 #else
10708     NapiError::ThrowError(env, JS_INNER_FAIL, "ace_engine is not support");
10709     return nullptr;
10710 #endif
10711 }
10712 
CheckShortTermPermission(napi_env env,napi_callback_info info)10713 napi_value MediaLibraryNapi::CheckShortTermPermission(napi_env env, napi_callback_info info)
10714 {
10715     AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
10716     int res = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_SHORT_TERM_WRITE_IMAGEVIDEO);
10717     napi_value result = nullptr;
10718     CHECK_ARGS(env, napi_get_boolean(env, res == PermissionState::PERMISSION_GRANTED, &result), JS_INNER_FAIL);
10719     return result;
10720 }
10721 
InitShortTermRequest(OHOS::AAFwk::Want & want,shared_ptr<ShortTermCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10722 static bool InitShortTermRequest(OHOS::AAFwk::Want &want, shared_ptr<ShortTermCallback> &callback,
10723                                  napi_env env, napi_value args[], size_t argsLen)
10724 {
10725     if (argsLen < ARGS_SIX) {
10726         return false;
10727     }
10728 
10729     want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
10730     want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
10731 
10732     if (args[PARAM1] == nullptr) {
10733         return false;
10734     }
10735 
10736     PhotoCreationConfig config;
10737     napi_value element = args[PARAM1];
10738     if (!ParseConfigObject(env, element, config)) {
10739         return false;
10740     }
10741     want.SetParam(SHORT_TERM_TAG, true);
10742     want.SetParam(SHORT_TERM_TITLE, config.title);
10743     want.SetParam(SHORT_TERM_EXTENSION, config.fileNameExtension);
10744     want.SetParam(SHORT_TERM_PHOTO_TYPE, config.photoType);
10745     want.SetParam(SHORT_TERM_PHOTO_SUB_TYPE, config.subtype);
10746 
10747     string bundleName;
10748     if (!ParseString(env, args[PARAM2], bundleName)) {
10749         return false;
10750     }
10751     want.SetParam(CONFIRM_BOX_BUNDLE_NAME, bundleName);
10752 
10753     string appName;
10754     if (!ParseString(env, args[PARAM3], appName)) {
10755         return false;
10756     }
10757     want.SetParam(CONFIRM_BOX_APP_NAME, appName);
10758 
10759     string appId;
10760     if (!ParseString(env, args[PARAM4], appId)) {
10761         return false;
10762     }
10763     want.SetParam(CONFIRM_BOX_APP_ID, appId);
10764 
10765     callback->SetFunc(args[PARAM5]);
10766     return true;
10767 }
10768 
CreateAssetWithShortTermPermission(napi_env env,napi_callback_info info)10769 napi_value MediaLibraryNapi::CreateAssetWithShortTermPermission(napi_env env, napi_callback_info info)
10770 {
10771     NAPI_INFO_LOG("CreateAssetWithShortTermPermission enter");
10772     size_t argc = ARGS_SIX;
10773     napi_value args[ARGS_SIX] = {nullptr};
10774     napi_value thisVar = nullptr;
10775     napi_value result = nullptr;
10776     napi_create_object(env, &result);
10777     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
10778     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10779     NAPI_ASSERT(env, context != nullptr, "context == nullptr");
10780 
10781     shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10782         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10783     NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
10784 
10785     auto uiContent = abilityContext->GetUIContent();
10786     NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
10787 
10788     OHOS::AAFwk::Want want;
10789     shared_ptr<ShortTermCallback> callback = make_shared<ShortTermCallback>(env, uiContent);
10790     NAPI_ASSERT(env, InitShortTermRequest(want, callback, env, args, sizeof(args)), "parse short term param fail");
10791 
10792     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10793         ([callback](auto arg) { callback->OnRelease(arg); }),
10794         ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
10795         ([callback](auto arg) { callback->OnReceive(arg); }),
10796         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
10797     };
10798     OHOS::Ace::ModalUIExtensionConfig config;
10799     config.isProhibitBack = true;
10800     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
10801     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10802     callback->SetSessionId(sessionId);
10803     return result;
10804 }
10805 
InitRequestPhotoUrisReadPermissionRequest(OHOS::AAFwk::Want & want,shared_ptr<RequestPhotoUrisReadPermissionCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10806 static bool InitRequestPhotoUrisReadPermissionRequest(OHOS::AAFwk::Want &want,
10807     shared_ptr<RequestPhotoUrisReadPermissionCallback> &callback, napi_env env, napi_value args[], size_t argsLen)
10808 {
10809     NAPI_INFO_LOG("InitRequestPhotoUrisReadPermission enter.");
10810     if (argsLen < ARGS_FOUR) {
10811         return false;
10812     }
10813 
10814     std::string targetType = "photoPicker";
10815     want.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
10816     std::string requestPhotoUrisTag = "requestPhotoUrisPage";
10817     want.SetParam(TARGET_PAGE, requestPhotoUrisTag);
10818 
10819      // second param: Array<string>
10820     if (!ParseAndSetFileUriArray(env, want, args[PARAM1])) {
10821         NAPI_ERR_LOG("FileUriArray check failed.");
10822         return false;
10823     }
10824 
10825     string appName;
10826     if (!ParseString(env, args[PARAM2], appName)) {
10827         NAPI_ERR_LOG("appName check failed.");
10828         return false;
10829     }
10830     want.SetParam(CONFIRM_BOX_APP_NAME, appName);
10831 
10832     callback->SetFunc(args[PARAM3]);
10833     return true;
10834 }
10835 
RequestPhotoUrisReadPermission(napi_env env,napi_callback_info info)10836 napi_value MediaLibraryNapi::RequestPhotoUrisReadPermission(napi_env env, napi_callback_info info)
10837 {
10838     NAPI_INFO_LOG("RequestPhotoUrisReadPermission enter");
10839     size_t argc = ARGS_FOUR;
10840     napi_value args[ARGS_FOUR] = {nullptr};
10841     napi_value thisVar = nullptr;
10842     napi_value result = nullptr;
10843     napi_create_object(env, &result);
10844     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
10845 
10846     // first param: context, check whether context is abilityContext from stage mode
10847     Ace::UIContent *uiContent = nullptr;
10848     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10849     NAPI_ASSERT(env, context != nullptr, "Context is null.");
10850 
10851     shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10852         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10853     if (abilityContext == nullptr) {
10854         auto uiExtensionContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
10855         if (uiExtensionContext == nullptr) {
10856             NAPI_ERR_LOG("Fail to convert to abilityContext or uiExtensionContext");
10857             return nullptr;
10858         }
10859         uiContent = uiExtensionContext->GetUIContent();
10860     } else {
10861         // get uiContent from abilityContext
10862         uiContent = abilityContext->GetUIContent();
10863     }
10864     NAPI_ASSERT(env, uiContent != nullptr, "UiContent is null.");
10865 
10866     // set want
10867     OHOS::AAFwk::Want want;
10868     shared_ptr<RequestPhotoUrisReadPermissionCallback> callback =
10869         make_shared<RequestPhotoUrisReadPermissionCallback>(env, uiContent);
10870     NAPI_ASSERT(env, InitRequestPhotoUrisReadPermissionRequest(want, callback, env, args, sizeof(args)),
10871             "Parse RequestPhotoUrisReadPermission input fail.");
10872 
10873     // regist callback and config
10874     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10875         ([callback](auto arg) { callback->OnRelease(arg); }),
10876         ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
10877         ([callback](auto arg) { callback->OnReceive(arg); }),
10878         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
10879     };
10880     OHOS::Ace::ModalUIExtensionConfig config;
10881     config.isProhibitBack = true;
10882     NAPI_INFO_LOG("RequestPhotoUrisReadPermission regist callback and config success.");
10883 
10884     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
10885     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10886     callback->SetSessionId(sessionId);
10887     return result;
10888 }
10889 
10890 
StartPhotoPickerExecute(napi_env env,void * data)10891 static void StartPhotoPickerExecute(napi_env env, void *data)
10892 {
10893     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10894     while (!context->pickerCallBack->ready) {
10895         std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
10896     }
10897 }
10898 
StartPhotoPickerAsyncCallbackComplete(napi_env env,napi_status status,void * data)10899 static void StartPhotoPickerAsyncCallbackComplete(napi_env env, napi_status status, void *data)
10900 {
10901     NAPI_INFO_LOG("StartPhotoPickerAsyncCallbackComplete start");
10902     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10903     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
10904 
10905     auto jsContext = make_unique<JSAsyncContextOutput>();
10906     jsContext->status = false;
10907     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
10908     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_ERR_PARAMETER_INVALID);
10909     napi_value result = nullptr;
10910     napi_create_object(env, &result);
10911     napi_value resultCode = nullptr;
10912     napi_create_int32(env, context->pickerCallBack->resultCode, &resultCode);
10913     status = napi_set_named_property(env, result, "resultCode", resultCode);
10914     if (status != napi_ok) {
10915         NAPI_ERR_LOG("napi_set_named_property resultCode failed");
10916     }
10917     const vector<string> &uris = context->pickerCallBack->uris;
10918     napi_value jsUris = nullptr;
10919     napi_create_array_with_length(env, uris.size(), &jsUris);
10920     napi_value jsUri = nullptr;
10921     for (size_t i = 0; i < uris.size(); i++) {
10922         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, uris[i].c_str(),
10923             NAPI_AUTO_LENGTH, &jsUri), JS_INNER_FAIL);
10924         if ((jsUri == nullptr) || (napi_set_element(env, jsUris, i, jsUri) != napi_ok)) {
10925             NAPI_ERR_LOG("failed to set uri array");
10926             break;
10927         }
10928     }
10929     if (napi_set_named_property(env, result, "uris", jsUris) != napi_ok) {
10930         NAPI_ERR_LOG("napi_set_named_property uris failed");
10931     }
10932     napi_value isOrigin = nullptr;
10933     napi_get_boolean(env, context->pickerCallBack->isOrigin, &isOrigin);
10934     status = napi_set_named_property(env, result, "isOrigin", isOrigin);
10935     if (status != napi_ok) {
10936         NAPI_ERR_LOG("napi_set_named_property isOrigin failed");
10937     }
10938     if (result != nullptr) {
10939         jsContext->data = result;
10940         jsContext->status = true;
10941     } else {
10942         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
10943             "failed to create js object");
10944     }
10945     if (context->work != nullptr) {
10946         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
10947             context->work, *jsContext);
10948     }
10949     delete context;
10950 }
10951 
GetSubWindowUIContent(napi_env env,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)10952 Ace::UIContent *GetSubWindowUIContent(napi_env env, unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
10953 {
10954     bool present = false;
10955     napi_status status = napi_has_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &present);
10956     if (status != napi_ok || !present) {
10957         return nullptr;
10958     }
10959     napi_value paramValue;
10960     status = napi_get_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &paramValue);
10961     CHECK_COND_RET(status == napi_ok, nullptr, "failed to get named property of parameters");
10962     present = false;
10963     status = napi_has_named_property(env, paramValue, "subWindowName", &present);
10964     if (status != napi_ok || !present) {
10965         return nullptr;
10966     }
10967     napi_value subWindowName;
10968     status = napi_get_named_property(env, paramValue, "subWindowName", &subWindowName);
10969     CHECK_COND_RET(status == napi_ok, nullptr, "failed to get named property of subWindowName");
10970     char buffer[ARG_BUF_SIZE];
10971     size_t res = 0;
10972     status = napi_get_value_string_utf8(env, subWindowName, buffer, ARG_BUF_SIZE, &res);
10973     if (status != napi_ok) {
10974         NAPI_ERR_LOG("failed to get the value of subWindow name");
10975         return nullptr;
10976     }
10977     auto currentWindow = Rosen::Window::Find(string(buffer));
10978     if (currentWindow == nullptr) {
10979         NAPI_ERR_LOG("GetSubWindowUIContent failed to find context by subWindow name");
10980         return nullptr;
10981     }
10982     return currentWindow->GetUIContent();
10983 }
10984 
IsPcPicker(napi_env env,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)10985 static bool IsPcPicker(napi_env env, unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
10986 {
10987     bool present = false;
10988     napi_status status = napi_has_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &present);
10989     if (status != napi_ok || !present) {
10990         return false;
10991     }
10992     napi_value paramValue;
10993     status = napi_get_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &paramValue);
10994     CHECK_COND_RET(status == napi_ok, false, "failed to get named property of parameters");
10995     present = false;
10996     status = napi_has_named_property(env, paramValue, "isPc", &present);
10997     if (status != napi_ok || !present) {
10998         return false;
10999     }
11000     napi_value isPc;
11001     status = napi_get_named_property(env, paramValue, "isPc", &isPc);
11002     CHECK_COND_RET(status == napi_ok, false, "failed to get named property of isPc");
11003     bool isPcPicker;
11004     napi_get_value_bool(env, isPc, &isPcPicker);
11005     return isPcPicker;
11006 }
11007 
GetUIContent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)11008 Ace::UIContent *GetUIContent(napi_env env, napi_callback_info info,
11009     unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
11010 {
11011     NAPI_INFO_LOG("GetUIContent start");
11012     if (!IsPcPicker(env, AsyncContext)) {
11013         NAPI_INFO_LOG("GetUIContent is not from PcPicker");
11014         Ace::UIContent *uiContent = GetSubWindowUIContent(env, AsyncContext);
11015         if (uiContent != nullptr) {
11016             NAPI_INFO_LOG("GetSubWindowUIContent success");
11017             return uiContent;
11018         }
11019     }
11020 
11021     bool isStageMode = false;
11022     napi_status status = AbilityRuntime::IsStageContext(env, AsyncContext->argv[ARGS_ZERO], isStageMode);
11023     if (status != napi_ok || !isStageMode) {
11024         NAPI_ERR_LOG("is not StageMode context, status: %{public}d, isStageMode: %{public}d",
11025             status, static_cast<int32_t>(isStageMode));
11026         return nullptr;
11027     }
11028     auto context = AbilityRuntime::GetStageModeContext(env, AsyncContext->argv[ARGS_ZERO]);
11029     if (context == nullptr) {
11030         NAPI_ERR_LOG("Failed to get native stage context instance");
11031         return nullptr;
11032     }
11033     auto abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
11034     if (abilityContext == nullptr) {
11035         auto uiExtensionContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
11036         if (uiExtensionContext == nullptr) {
11037             NAPI_ERR_LOG("Fail to convert to abilityContext or uiExtensionContext");
11038             return nullptr;
11039         }
11040         return uiExtensionContext->GetUIContent();
11041     }
11042     return abilityContext->GetUIContent();
11043 }
11044 
StartPickerExtension(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)11045 static napi_value StartPickerExtension(napi_env env, napi_callback_info info,
11046     unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
11047 {
11048     NAPI_INFO_LOG("StartPickerExtension start");
11049     Ace::UIContent *uiContent = GetUIContent(env, info, AsyncContext);
11050     if (uiContent == nullptr) {
11051         NAPI_ERR_LOG("get uiContent failed");
11052         return nullptr;
11053     }
11054     AAFwk::Want request;
11055     AppExecFwk::UnwrapWant(env, AsyncContext->argv[ARGS_ONE], request);
11056     std::string targetType = "photoPicker";
11057     request.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
11058     AsyncContext->pickerCallBack = make_shared<PickerCallBack>();
11059     auto callback = std::make_shared<ModalUICallback>(uiContent, AsyncContext->pickerCallBack.get());
11060     Ace::ModalUIExtensionCallbacks extensionCallback = {
11061         ([callback](auto arg) { callback->OnRelease(arg); }),
11062         ([callback](auto arg1, auto arg2) { callback->OnResultForModal(arg1, arg2); }),
11063         ([callback](auto arg) { callback->OnReceive(arg); }),
11064         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
11065         std::bind(&ModalUICallback::OnDestroy, callback),
11066     };
11067     Ace::ModalUIExtensionConfig config;
11068     config.isWindowModeFollowHost = true;
11069     config.isProhibitBack = true;
11070     int sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
11071     if (sessionId == 0) {
11072         NAPI_ERR_LOG("create modalUIExtension failed");
11073         return nullptr;
11074     }
11075     callback->SetSessionId(sessionId);
11076     napi_value result = nullptr;
11077     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
11078     return result;
11079 }
11080 
11081 template <class AsyncContext>
AsyncContextSetStaticObjectInfo(napi_env env,napi_callback_info info,AsyncContext & asyncContext,const size_t minArgs,const size_t maxArgs)11082 static napi_status AsyncContextSetStaticObjectInfo(napi_env env, napi_callback_info info,
11083     AsyncContext &asyncContext, const size_t minArgs, const size_t maxArgs)
11084 {
11085     NAPI_INFO_LOG("AsyncContextSetStaticObjectInfo start");
11086     napi_value thisVar = nullptr;
11087     asyncContext->argc = maxArgs;
11088     CHECK_STATUS_RET(napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]), &thisVar,
11089         nullptr), "Failed to get cb info");
11090     CHECK_COND_RET(((asyncContext->argc >= minArgs) && (asyncContext->argc <= maxArgs)), napi_invalid_arg,
11091         "Number of args is invalid");
11092     if (minArgs > 0) {
11093         CHECK_COND_RET(asyncContext->argv[ARGS_ZERO] != nullptr, napi_invalid_arg, "Argument list is empty");
11094     }
11095     CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamCallback(env, asyncContext), "Failed to get callback param!");
11096     return napi_ok;
11097 }
11098 
ParseArgsStartPhotoPicker(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11099 static napi_value ParseArgsStartPhotoPicker(napi_env env, napi_callback_info info,
11100     unique_ptr<MediaLibraryAsyncContext> &context)
11101 {
11102     NAPI_INFO_LOG("ParseArgsStartPhotoPicker start");
11103     constexpr size_t minArgs = ARGS_TWO;
11104     constexpr size_t maxArgs = ARGS_THREE;
11105     CHECK_ARGS(env, AsyncContextSetStaticObjectInfo(env, info, context, minArgs, maxArgs),
11106         JS_ERR_PARAMETER_INVALID);
11107     NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, context));
11108     CHECK_NULLPTR_RET(StartPickerExtension(env, info, context));
11109     napi_value result = nullptr;
11110     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
11111     return result;
11112 }
11113 
PhotoAccessGetSupportedPhotoFormatsExec(MediaLibraryAsyncContext * context)11114 static void PhotoAccessGetSupportedPhotoFormatsExec(MediaLibraryAsyncContext *context)
11115 {
11116     CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
11117     if (context->photoType == MEDIA_TYPE_IMAGE || context->photoType == MEDIA_TYPE_VIDEO) {
11118         context->mediaTypeNames = MediaFileUtils::GetAllTypes(context->photoType);
11119     } else {
11120         context->SaveError(E_FAIL);
11121     }
11122 }
11123 
GetSupportedPhotoFormatsAsyncCallbadkComplete(napi_env env,napi_status status,void * data)11124 static void GetSupportedPhotoFormatsAsyncCallbadkComplete(napi_env env, napi_status status, void *data)
11125 {
11126     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11127     CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
11128     auto jsContext = make_unique<JSAsyncContextOutput>();
11129     CHECK_IF_EQUAL(jsContext != nullptr, "jsContext is nullptr");
11130     napi_value mediaValue;
11131     napi_value resultTypes;
11132     napi_create_array(env, &resultTypes);
11133     int count = 0;
11134     jsContext->status = false;
11135     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
11136     if (context->error != ERR_DEFAULT) {
11137         context->HandleError(env, jsContext->error);
11138     } else {
11139         for (const auto &type_out : context->mediaTypeNames) {
11140             CHECK_ARGS_RET_VOID(
11141                 env, napi_create_string_utf8(env, type_out.c_str(), NAPI_AUTO_LENGTH, &mediaValue),
11142                 JS_INNER_FAIL);
11143             CHECK_ARGS_RET_VOID(
11144                 env, napi_set_element(env, resultTypes, count++, mediaValue), JS_INNER_FAIL);
11145         }
11146         jsContext->status = true;
11147         jsContext->data = resultTypes;
11148     }
11149     if (context->work != nullptr) {
11150         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11151             context->work, *jsContext);
11152     }
11153     delete context;
11154 }
11155 
PhotoAccessGetSupportedPhotoFormats(napi_env env,napi_callback_info info)11156 napi_value MediaLibraryNapi::PhotoAccessGetSupportedPhotoFormats(napi_env env, napi_callback_info info)
11157 {
11158     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11159     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->photoType),
11160         JS_ERR_PARAMETER_INVALID);
11161 
11162     SetUserIdFromObjectInfo(asyncContext);
11163     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSupportedPhotoFormats",
11164         [](napi_env env, void *data) {
11165             auto context = static_cast<MediaLibraryAsyncContext*>(data);
11166             PhotoAccessGetSupportedPhotoFormatsExec(context);
11167         },
11168         reinterpret_cast<CompleteCallback>(GetSupportedPhotoFormatsAsyncCallbadkComplete));
11169 }
11170 
StartPhotoPicker(napi_env env,napi_callback_info info)11171 napi_value MediaLibraryNapi::StartPhotoPicker(napi_env env, napi_callback_info info)
11172 {
11173     NAPI_INFO_LOG("StartPhotoPicker start");
11174     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11175     auto pickerCallBack = make_shared<PickerCallBack>();
11176     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
11177     ParseArgsStartPhotoPicker(env, info, asyncContext);
11178 
11179     SetUserIdFromObjectInfo(asyncContext);
11180     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "StrartPhotoPicker",
11181         StartPhotoPickerExecute, StartPhotoPickerAsyncCallbackComplete);
11182 }
11183 
PhotoAccessHelperSetForceHideSensitiveType(napi_env env,napi_callback_info info)11184 napi_value MediaLibraryNapi::PhotoAccessHelperSetForceHideSensitiveType(napi_env env, napi_callback_info info)
11185 {
11186     MediaLibraryTracer tracer;
11187     tracer.Start("PhotoAccessHelperSetForceHideSensitiveType");
11188 
11189     NAPI_INFO_LOG("enter");
11190 
11191     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11192     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
11193     asyncContext->assetType = TYPE_PHOTO;
11194     NAPI_ASSERT(env, ParseArgsGrantPhotoUrisForForceSensitive(env, info, asyncContext), "Failed to parse js args");
11195 
11196     SetUserIdFromObjectInfo(asyncContext);
11197     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUrisPermission",
11198         PhotoAccessGrantPhotoUrisPermissionExecute, JSPhotoUriPermissionCallback);
11199 }
11200 
PhotoAccessGetSharedPhotoAssets(napi_env env,napi_callback_info info)11201 napi_value MediaLibraryNapi::PhotoAccessGetSharedPhotoAssets(napi_env env, napi_callback_info info)
11202 {
11203     MediaLibraryTracer tracer;
11204     tracer.Start("PhotoAccessGetSharedPhotoAssets");
11205     unique_ptr<MediaLibraryAsyncContext> asyncContext =
11206         make_unique<MediaLibraryAsyncContext>();
11207     asyncContext->assetType = TYPE_PHOTO;
11208     CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
11209 
11210     MediaLibraryAsyncContext* context =
11211         static_cast<MediaLibraryAsyncContext*>((asyncContext.get()));
11212     string queryUri = PAH_QUERY_PHOTO;
11213     MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
11214 
11215     Uri uri(queryUri);
11216     shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
11217         context->predicates, context->fetchColumn);
11218     CHECK_NULLPTR_RET(resultSet);
11219 
11220     napi_value jsFileArray = 0;
11221     napi_create_array(env, &jsFileArray);
11222 
11223     int count = 0;
11224     int err = resultSet->GoToFirstRow();
11225     if (err != napi_ok) {
11226         NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
11227         return jsFileArray;
11228     }
11229     do {
11230         napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet, true);
11231         napi_set_element(env, jsFileArray, count++, item);
11232     } while (!resultSet->GoToNextRow());
11233     resultSet->Close();
11234     return jsFileArray;
11235 }
11236 
InitDefaultAlbumNameRequest(OHOS::AAFwk::Want & want,shared_ptr<DefaultAlbumNameCallback> & callback,napi_env env,napi_value args[],size_t argsLen)11237 static bool InitDefaultAlbumNameRequest(OHOS::AAFwk::Want &want, shared_ptr<DefaultAlbumNameCallback> &callback,
11238                                         napi_env env, napi_value args[], size_t argsLen)
11239 {
11240     if (argsLen < ARGS_TWO) {
11241         return false;
11242     }
11243 
11244     want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_DEFAULT_ALBUM_NAME_ABILITY_NAME);
11245     want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
11246 
11247     callback->SetFunc(args[PARAM1]);
11248     return true;
11249 }
11250 
GetPhotoPickerComponentDefaultAlbumName(napi_env env,napi_callback_info info)11251 napi_value MediaLibraryNapi::GetPhotoPickerComponentDefaultAlbumName(napi_env env, napi_callback_info info)
11252 {
11253     NAPI_INFO_LOG("GetPhotoPickerComponentDefaultAlbumName enter");
11254     size_t argc = ARGS_TWO;
11255     napi_value args[ARGS_TWO] = {nullptr};
11256     napi_value thisVar = nullptr;
11257     napi_value result = nullptr;
11258     napi_create_object(env, &result);
11259     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
11260     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
11261     NAPI_ASSERT(env, context != nullptr, "context == nullptr");
11262 
11263     shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
11264         OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
11265     NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
11266 
11267     auto uiContent = abilityContext->GetUIContent();
11268     NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
11269 
11270     OHOS::AAFwk::Want want;
11271     shared_ptr<DefaultAlbumNameCallback> callback = make_shared<DefaultAlbumNameCallback>(env, uiContent);
11272     NAPI_ASSERT(env, InitDefaultAlbumNameRequest(want, callback, env, args, sizeof(args)),
11273         "parse default album name param fail");
11274 
11275     OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
11276         ([callback](auto arg) { callback->OnRelease(arg); }),
11277         ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
11278         ([callback](auto arg) { callback->OnReceive(arg); }),
11279         ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
11280     };
11281     OHOS::Ace::ModalUIExtensionConfig config;
11282     config.isProhibitBack = true;
11283     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
11284     NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
11285     callback->SetSessionId(sessionId);
11286     return result;
11287 }
11288 
CheckOrderStyle(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,OrderStyleType & orderStyle)11289 static napi_value CheckOrderStyle(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context,
11290     OrderStyleType &orderStyle)
11291 {
11292     CHECK_COND_RET(context->argc >= ARGS_ONE, nullptr, "No arguments to check order style");
11293 
11294     int32_t albumOrderStyle;
11295     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumOrderStyle));
11296     double doubleArg;
11297     CHECK_COND_RET(MediaLibraryNapiUtils::GetDouble(env, context->argv[PARAM0], doubleArg) == napi_ok, nullptr,
11298         "Failed to get orderStyle");
11299     CHECK_ARGS_WITH_MEG(env, doubleArg == static_cast<double>(albumOrderStyle), JS_E_PARAM_INVALID,
11300         "orderStyle is not an integer");
11301 
11302     if (!PhotoAlbum::CheckOrderStyleType(static_cast<OrderStyleType>(albumOrderStyle))) {
11303         NapiError::ThrowError(env, JS_E_PARAM_INVALID, "orderStyle is an invalid parameter");
11304         return nullptr;
11305     }
11306 
11307     napi_value result = nullptr;
11308     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11309     orderStyle = static_cast<OrderStyleType>(albumOrderStyle);
11310     return result;
11311 }
11312 
ParseArgsGetPhotoAlbumsWithoutSubtype(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11313 static napi_value ParseArgsGetPhotoAlbumsWithoutSubtype(napi_env env, napi_callback_info info,
11314     unique_ptr<MediaLibraryAsyncContext> &context)
11315 {
11316     if (!MediaLibraryNapiUtils::IsSystemApp()) {
11317         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system app");
11318         return nullptr;
11319     }
11320 
11321     constexpr size_t minArgs = ARGS_ZERO;
11322     constexpr size_t maxArgs = ARGS_ONE;
11323     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
11324         JS_E_PARAM_INVALID);
11325 
11326     if (context->argc == maxArgs) {
11327         napi_valuetype valueType = napi_undefined;
11328         if (napi_typeof(env, context->argv[PARAM1], &valueType) == napi_ok &&
11329             (valueType == napi_undefined || valueType == napi_null)) {
11330             context->argc -= 1;
11331         }
11332     }
11333 
11334     if (context->argc == maxArgs) {
11335         auto status =
11336             MediaLibraryNapiUtils::GetFetchOption(env, context->argv[maxArgs - 1], ALBUM_FETCH_OPT, context);
11337         CHECK_ARGS(env, status, JS_E_INNER_FAIL);
11338     }
11339     RestrictAlbumSubtypeOptions(context->predicates);
11340 
11341     CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_E_INNER_FAIL);
11342     AddNoSmartFetchColumns(context->fetchColumn);
11343 
11344     napi_value result = nullptr;
11345     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11346     return result;
11347 }
11348 
JSGetPhotoAlbumsWithoutSubtypeExecute(napi_env env,void * data)11349 static void JSGetPhotoAlbumsWithoutSubtypeExecute(napi_env env, void *data)
11350 {
11351     MediaLibraryTracer tracer;
11352     tracer.Start("JSGetPhotoAlbumsWithoutSubtypeExecute");
11353 
11354     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11355     GetPhotoAlbumObjectReqBody reqBody;
11356     GetPhotoAlbumObjectRespBody respBody;
11357     shared_ptr<DataShareResultSet> resultSet;
11358     reqBody.predicates = context->predicates;
11359     reqBody.columns = context->fetchColumn;
11360     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GET_PHOTO_ALBUMS);
11361 
11362     int32_t errCode = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
11363     resultSet = respBody.resultSet;
11364     if (resultSet == nullptr) {
11365         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
11366         if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
11367             context->SaveError(errCode);
11368         } else {
11369             context->SaveError(E_INNER_FAIL);
11370         }
11371         return;
11372     }
11373 
11374     context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
11375     context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
11376     context->fetchPhotoAlbumResult->SetUserId(context->userId);
11377 }
11378 
GetNapiPhotoAlbumResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)11379 static void GetNapiPhotoAlbumResult(napi_env env, MediaLibraryAsyncContext *context,
11380     unique_ptr<JSAsyncContextOutput> &jsContext)
11381 {
11382     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
11383     if (fileResult == nullptr) {
11384         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_E_INNER_FAIL);
11385         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
11386             "Failed to create js object for Fetch Photo Album Result");
11387         return;
11388     }
11389     jsContext->data = fileResult;
11390     jsContext->status = true;
11391     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_E_INNER_FAIL);
11392 }
11393 
GetPhotoAlbumsWithoutSubtypeCompleteCallback(napi_env env,napi_status status,void * data)11394 static void GetPhotoAlbumsWithoutSubtypeCompleteCallback(napi_env env, napi_status status, void *data)
11395 {
11396     MediaLibraryTracer tracer;
11397     tracer.Start("GetPhotoAlbumsWithoutSubtypeCompleteCallback");
11398 
11399     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11400     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
11401     jsContext->status = false;
11402     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_E_INNER_FAIL);
11403     if (context->error != ERR_DEFAULT  || context->fetchPhotoAlbumResult == nullptr) {
11404         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_E_INNER_FAIL);
11405         context->HandleError(env, jsContext->error);
11406     } else {
11407         GetNapiPhotoAlbumResult(env, context, jsContext);
11408     }
11409 
11410     tracer.Finish();
11411     if (context->work != nullptr) {
11412         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11413                                                    context->work, *jsContext);
11414     }
11415     delete context;
11416 }
11417 
PhotoAccessGetPhotoAlbumsWithoutSubtype(napi_env env,napi_callback_info info)11418 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsWithoutSubtype(napi_env env, napi_callback_info info)
11419 {
11420     MediaLibraryTracer tracer;
11421     tracer.Start("PhotoAccessGetPhotoAlbumsWithoutSubtype");
11422 
11423     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11424     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
11425     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbumsWithoutSubtype(env, info, asyncContext));
11426 
11427     SetUserIdFromObjectInfo(asyncContext);
11428     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbumsWithoutSubtype",
11429         JSGetPhotoAlbumsWithoutSubtypeExecute, GetPhotoAlbumsWithoutSubtypeCompleteCallback);
11430 }
11431 
AddDefaultAlbumOrderColumns(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,vector<string> & fetchColumns,const OrderStyleType & orderStyle)11432 static napi_value AddDefaultAlbumOrderColumns(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context,
11433     vector<string> &fetchColumns, const OrderStyleType &orderStyle)
11434 {
11435     auto validFetchColumns = (orderStyle == OrderStyleType::MIX) ?
11436         PhotoAlbumColumns::DEFAULT_FETCH_ORDER_COLUMNS_STYLE1 : PhotoAlbumColumns::DEFAULT_FETCH_ORDER_COLUMNS_STYLE2;
11437     for (const auto &column : fetchColumns) {
11438         if (!AlbumOrder::IsAlbumOrderColumn(orderStyle, column)) {
11439             NAPI_ERR_LOG("AlbumOrder does not contain this column: %{public}s, orderStyle: %{public}d",
11440                 column.c_str(), static_cast<int32_t>(orderStyle));
11441             return nullptr;
11442         }
11443     }
11444     fetchColumns.assign(validFetchColumns.begin(), validFetchColumns.end());
11445 
11446     napi_value result = nullptr;
11447     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11448     return result;
11449 }
11450 
ParseArgsGetPhotoAlbumOrder(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11451 static napi_value ParseArgsGetPhotoAlbumOrder(napi_env env, napi_callback_info info,
11452     unique_ptr<MediaLibraryAsyncContext> &context)
11453 {
11454     if (!MediaLibraryNapiUtils::IsSystemApp()) {
11455         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system app");
11456         return nullptr;
11457     }
11458 
11459     constexpr size_t minArgs = ARGS_ONE;
11460     constexpr size_t maxArgs = ARGS_TWO;
11461     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
11462         JS_E_PARAM_INVALID);
11463 
11464     if (context->argc == maxArgs) {
11465         napi_valuetype valueType = napi_undefined;
11466         if (napi_typeof(env, context->argv[PARAM1], &valueType) == napi_ok &&
11467             (valueType == napi_undefined || valueType == napi_null)) {
11468             context->argc -= 1;
11469         }
11470     }
11471 
11472     OrderStyleType orderStyle;
11473     CHECK_ARGS_WITH_MEG(env, CheckOrderStyle(env, context, orderStyle), JS_E_PARAM_INVALID,
11474         "Failed to check orderStyle");
11475 
11476     if (context->argc == maxArgs) {
11477         auto status =
11478             MediaLibraryNapiUtils::GetFetchOption(env, context->argv[maxArgs - 1], ALBUM_FETCH_OPT, context);
11479         CHECK_ARGS(env, status, JS_E_INNER_FAIL);
11480     }
11481     RestrictAlbumSubtypeOptions(context->predicates);
11482 
11483     CHECK_ARGS_WITH_MEG(env, AddDefaultAlbumOrderColumns(env, context, context->fetchColumn, orderStyle),
11484         JS_E_PARAM_INVALID, "Failed to add default columns");
11485 
11486     napi_value result = nullptr;
11487     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11488     return result;
11489 }
11490 
11491 
JSGetPhotoAlbumOrderExecute(napi_env env,void * data)11492 static void JSGetPhotoAlbumOrderExecute(napi_env env, void *data)
11493 {
11494     MediaLibraryTracer tracer;
11495     tracer.Start("JSGetPhotoAlbumOrderExecute");
11496 
11497     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11498     GetPhotoAlbumObjectReqBody reqBody;
11499     GetPhotoAlbumObjectRespBody respBody;
11500     shared_ptr<DataShareResultSet> resultSet;
11501     reqBody.predicates = context->predicates;
11502     reqBody.columns = context->fetchColumn;
11503     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GET_PHOTO_ALBUM_ORDER);
11504 
11505     int32_t errCode = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
11506     resultSet = respBody.resultSet;
11507     if (resultSet == nullptr) {
11508         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
11509         if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
11510             context->SaveError(errCode);
11511         } else {
11512             context->SaveError(E_INNER_FAIL);
11513         }
11514         return;
11515     }
11516 
11517     context->fetchAlbumOrderResult = make_unique<FetchResult<AlbumOrder>>(move(resultSet));
11518 }
11519 
GetNapiAlbumOrderResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)11520 static void GetNapiAlbumOrderResult(napi_env env, MediaLibraryAsyncContext *context,
11521     unique_ptr<JSAsyncContextOutput> &jsContext)
11522 {
11523     if (context->fetchAlbumOrderResult == nullptr) {
11524         NAPI_ERR_LOG("No fetch album order result found!");
11525         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
11526             "Failed to obtain Fetch AlbumOrder Result");
11527         return;
11528     }
11529     napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumOrderResult));
11530     if (fileResult == nullptr) {
11531         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
11532             "Failed to create js object for Fetch File Result");
11533     } else {
11534         jsContext->data = fileResult;
11535         jsContext->status = true;
11536         napi_get_undefined(env, &jsContext->error);
11537     }
11538 }
11539 
GetAlbumOrderCallbackComplete(napi_env env,napi_status status,void * data)11540 static void GetAlbumOrderCallbackComplete(napi_env env, napi_status status, void *data)
11541 {
11542     MediaLibraryTracer tracer;
11543     tracer.Start("GetAlbumOrderCallbackComplete");
11544 
11545     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11546     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
11547 
11548     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
11549     jsContext->status = false;
11550     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_E_INNER_FAIL);
11551 
11552     if (context->error != ERR_DEFAULT) {
11553         context->HandleError(env, jsContext->error);
11554     } else {
11555         GetNapiAlbumOrderResult(env, context, jsContext);
11556     }
11557 
11558     tracer.Finish();
11559     if (context->work != nullptr) {
11560         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11561                                                    context->work, *jsContext);
11562     }
11563     delete context;
11564 }
11565 
PhotoAccessGetPhotoAlbumOrder(napi_env env,napi_callback_info info)11566 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumOrder(napi_env env, napi_callback_info info)
11567 {
11568     MediaLibraryTracer tracer;
11569     tracer.Start("PhotoAccessGetPhotoAlbumOrder");
11570 
11571     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11572     CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbumOrder(env, info, asyncContext));
11573 
11574     SetUserIdFromObjectInfo(asyncContext);
11575     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbumOrder",
11576         JSGetPhotoAlbumOrderExecute, GetAlbumOrderCallbackComplete);
11577 }
11578 
HandleAlbumOrderParam(AlbumOrderNapi * obj,DataShareValuesBucket & valuesBucket,OrderStyleType orderStyle,AlbumOrderParam param)11579 static napi_status HandleAlbumOrderParam(AlbumOrderNapi *obj, DataShareValuesBucket &valuesBucket,
11580     OrderStyleType orderStyle, AlbumOrderParam param)
11581 {
11582     int32_t index = static_cast<int32_t>(orderStyle);
11583     auto iter = PhotoAlbumColumns::ORDER_COLUMN_STYLE_MAP.find(param);
11584     if (iter != PhotoAlbumColumns::ORDER_COLUMN_STYLE_MAP.end()) {
11585         size_t len = iter->second.size();
11586         CHECK_COND_RET(index >= 0 && static_cast<size_t>(index) < len, napi_invalid_arg,
11587             "The orderStyle has exceeded the length of the column array, unable to find the real column name");
11588 
11589         string columnName = iter->second[index];
11590         switch (param) {
11591             case AlbumOrderParam::ALBUM_ORDER:
11592                 valuesBucket.Put(columnName, obj->GetAlbumOrder());
11593                 break;
11594             case AlbumOrderParam::ORDER_SECTION:
11595                 valuesBucket.Put(columnName, obj->GetOrderSection());
11596                 break;
11597             case AlbumOrderParam::ORDER_TYPE:
11598                 valuesBucket.Put(columnName, obj->GetOrderType());
11599                 break;
11600             case AlbumOrderParam::ORDER_STATUS:
11601                 valuesBucket.Put(columnName, obj->GetOrderStatus());
11602                 break;
11603             default:
11604                 break;
11605         }
11606     }
11607     return napi_ok;
11608 }
11609 
TransAlbumOrderToBuckets(AlbumOrderNapi * obj,DataShare::DataShareValuesBucket & values,OrderStyleType orderStyle)11610 static napi_status TransAlbumOrderToBuckets(AlbumOrderNapi *obj, DataShare::DataShareValuesBucket &values,
11611     OrderStyleType orderStyle)
11612 {
11613     for (int i = static_cast<int32_t>(AlbumOrderParam::ALBUM_ORDER);
11614         i <= static_cast<int32_t>(AlbumOrderParam::ORDER_STATUS); i++) {
11615         AlbumOrderParam param = static_cast<AlbumOrderParam>(i);
11616         CHECK_COND_RET(HandleAlbumOrderParam(obj, values, orderStyle, param) == napi_ok, napi_invalid_arg,
11617             "orderStyle cannot be mapped to the actual rdb columnName");
11618     }
11619     return napi_ok;
11620 }
11621 
ParseAlbumOrderArray(napi_env env,napi_value arg,OrderStyleType orderStyle,vector<DataShare::DataShareValuesBucket> & dataShareValuesBuckets)11622 static napi_value ParseAlbumOrderArray(napi_env env, napi_value arg, OrderStyleType orderStyle,
11623     vector<DataShare::DataShareValuesBucket> &dataShareValuesBuckets)
11624 {
11625     bool isArray = false;
11626     CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_E_INNER_FAIL);
11627     CHECK_ARGS_WITH_MEG(env, isArray == true, JS_E_PARAM_INVALID, "Failed to check array type");
11628 
11629     uint32_t len = 0;
11630     CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_E_INNER_FAIL);
11631     CHECK_ARGS_WITH_MEG(env, len > 0, JS_E_PARAM_INVALID, "Failed to check array length");
11632 
11633     for (uint32_t i = 0; i < len; i++) {
11634         napi_value orderData = nullptr;
11635         CHECK_ARGS(env, napi_get_element(env, arg, i, &orderData), JS_E_INNER_FAIL);
11636         CHECK_ARGS_WITH_MEG(env, orderData != nullptr, JS_E_PARAM_INVALID, "Failed to get album order element");
11637 
11638         AlbumOrderNapi *obj = nullptr;
11639         DataShareValuesBucket valuesBucket;
11640         CHECK_ARGS(env, napi_unwrap(env, orderData, reinterpret_cast<void **>(&obj)), JS_E_INNER_FAIL);
11641         CHECK_ARGS_WITH_MEG(env, obj != nullptr, JS_E_PARAM_INVALID, "Failed to get albumOrder napi object");
11642 
11643         if (obj->GetAlbumId() <= 0) {
11644             NAPI_ERR_LOG("Skip invalid album order, albumId: %{public}d", obj->GetAlbumId());
11645             continue;
11646         }
11647         valuesBucket.Put(PhotoAlbumColumns::ALBUM_ID, obj->GetAlbumId());
11648         CHECK_ARGS_WITH_MEG(env, TransAlbumOrderToBuckets(obj, valuesBucket, orderStyle) == napi_ok,
11649             JS_E_PARAM_INVALID, "Transform albumOrder to datasharvaluebucket failed");
11650 
11651         dataShareValuesBuckets.emplace_back(valuesBucket);
11652     }
11653 
11654     napi_value result = nullptr;
11655     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11656     return result;
11657 }
11658 
ParseArgsSetPhotoAlbumOrder(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11659 static napi_value ParseArgsSetPhotoAlbumOrder(napi_env env, napi_callback_info info,
11660     unique_ptr<MediaLibraryAsyncContext> &context)
11661 {
11662     if (!MediaLibraryNapiUtils::IsSystemApp()) {
11663         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system app");
11664         return nullptr;
11665     }
11666 
11667     napi_value result = nullptr;
11668     constexpr size_t minArgs = ARGS_TWO;
11669     constexpr size_t maxArgs = ARGS_TWO;
11670     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
11671         JS_E_PARAM_INVALID);
11672 
11673     OrderStyleType orderStyle;
11674     CHECK_ARGS_WITH_MEG(env, CheckOrderStyle(env, context, orderStyle), JS_E_PARAM_INVALID,
11675         "Failed to check orderStyle");
11676     context->orderStyle = static_cast<int32_t>(orderStyle);
11677 
11678     CHECK_NULLPTR_RET(ParseAlbumOrderArray(env, context->argv[PARAM1], orderStyle, context->valuesBucketArray));
11679 
11680     CHECK_ARGS_WITH_MEG(env, !context->valuesBucketArray.empty(), JS_E_PARAM_INVALID,
11681         "Albumorder array is empty");
11682     CHECK_ARGS_WITH_MEG(env, context->valuesBucketArray.size() <= MAX_SET_ORDER_ARRAY_SIZE, JS_E_PARAM_INVALID,
11683         "Exceeded the maximum batch input quantity, can not update album order");
11684 
11685     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11686     return result;
11687 }
11688 
TransValueBucketToReqBody(const std::vector<OHOS::DataShare::DataShareValuesBucket> & valuesBucketArray,const int32_t & orderStyle,SetPhotoAlbumOrderReqBody & reqBody)11689 static void TransValueBucketToReqBody(const std::vector<OHOS::DataShare::DataShareValuesBucket> &valuesBucketArray,
11690     const int32_t &orderStyle, SetPhotoAlbumOrderReqBody &reqBody)
11691 {
11692     reqBody.albumOrderColumn = PhotoAlbumColumns::ALBUM_ORDER_COLUMNS[orderStyle];
11693     reqBody.orderSectionColumn = PhotoAlbumColumns::ALBUM_ORDER_SECTION_COLUMNS[orderStyle];
11694     reqBody.orderTypeColumn = PhotoAlbumColumns::ALBUM_ORDER_TYPE_COLUMNS[orderStyle];
11695     reqBody.orderStatusColumn = PhotoAlbumColumns::ALBUM_ORDER_STATUS_COLUMNS[orderStyle];
11696 
11697     bool isValid = false;
11698     for (const auto& valueBucket : valuesBucketArray) {
11699         reqBody.albumIds.emplace_back(valueBucket.Get(PhotoAlbumColumns::ALBUM_ID, isValid));
11700         reqBody.albumOrders.emplace_back(valueBucket.Get(reqBody.albumOrderColumn, isValid));
11701         reqBody.orderSection.emplace_back(valueBucket.Get(reqBody.orderSectionColumn, isValid));
11702         reqBody.orderType.emplace_back(valueBucket.Get(reqBody.orderTypeColumn, isValid));
11703         reqBody.orderStatus.emplace_back(valueBucket.Get(reqBody.orderStatusColumn, isValid));
11704     }
11705 }
11706 
JSSetPhotoAlbumOrderExecute(napi_env env,void * data)11707 static void JSSetPhotoAlbumOrderExecute(napi_env env, void *data)
11708 {
11709     MediaLibraryTracer tracer;
11710     tracer.Start("JSSetPhotoAlbumOrderExecute");
11711 
11712     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11713     SetPhotoAlbumOrderReqBody reqBody;
11714     TransValueBucketToReqBody(context->valuesBucketArray, context->orderStyle, reqBody);
11715 
11716     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SET_PHOTO_ALBUM_ORDER);
11717     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
11718     if (ret < 0) {
11719         context->SaveError(ret);
11720         NAPI_ERR_LOG("set photo album order failed, err: %{public}d", ret);
11721     }
11722 }
11723 
JSSetAlbumOrderCompleteCallback(napi_env env,napi_status status,void * data)11724 static void JSSetAlbumOrderCompleteCallback(napi_env env, napi_status status, void *data)
11725 {
11726     MediaLibraryTracer tracer;
11727     tracer.Start("JSSetAlbumOrderCompleteCallback");
11728 
11729     auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11730     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
11731     jsContext->status = false;
11732     if (context->error == ERR_DEFAULT) {
11733         jsContext->status = true;
11734         napi_get_undefined(env, &jsContext->error);
11735         napi_get_undefined(env, &jsContext->data);
11736     } else {
11737         napi_get_undefined(env, &jsContext->data);
11738         context->HandleError(env, jsContext->error);
11739     }
11740     if (context->work != nullptr) {
11741         tracer.Finish();
11742         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11743             context->work, *jsContext);
11744     }
11745     delete context;
11746 }
11747 
PhotoAccessSetPhotoAlbumOrder(napi_env env,napi_callback_info info)11748 napi_value MediaLibraryNapi::PhotoAccessSetPhotoAlbumOrder(napi_env env, napi_callback_info info)
11749 {
11750     MediaLibraryTracer tracer;
11751     tracer.Start("PhotoAccessSetPhotoAlbumOrder");
11752 
11753     unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11754     CHECK_NULLPTR_RET(ParseArgsSetPhotoAlbumOrder(env, info, asyncContext));
11755 
11756     SetUserIdFromObjectInfo(asyncContext);
11757     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "SetPhotoAlbumOrder",
11758         JSSetPhotoAlbumOrderExecute, JSSetAlbumOrderCompleteCallback);
11759 }
11760 
GetUserId()11761 int32_t MediaLibraryNapi::GetUserId()
11762 {
11763     return userId_;
11764 }
11765 
SetUserId(const int32_t & userId)11766 void MediaLibraryNapi::SetUserId(const int32_t &userId)
11767 {
11768     userId_ = userId;
11769 }
11770 } // namespace Media
11771 } // namespace OHOS
11772