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