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