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