1 /*
2 * Copyright (C) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define MLOG_TAG "MediaLibraryNapi"
17 #define ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE "ability.want.params.uiExtensionTargetType"
18
19 #include "media_library_napi.h"
20
21 #include <fcntl.h>
22 #include <functional>
23 #include <sys/sendfile.h>
24
25 #include "access_token.h"
26 #include "accesstoken_kit.h"
27 #include "ability_context.h"
28 #include "album_order_napi.h"
29 #include "confirm_callback.h"
30 #include "context.h"
31 #include "default_album_name_callback.h"
32 #include "directory_ex.h"
33 #include "file_ex.h"
34 #include "hitrace_meter.h"
35 #include "ipc_skeleton.h"
36 #include "location_column.h"
37 #include "locale_config.h"
38 #include "media_device_column.h"
39 #include "media_directory_type_column.h"
40 #include "media_file_asset_columns.h"
41 #include "media_change_request_napi.h"
42 #include "media_column.h"
43 #include "media_app_uri_permission_column.h"
44 #include "media_app_uri_sensitive_column.h"
45 #include "media_file_uri.h"
46 #include "media_file_utils.h"
47 #include "media_smart_album_column.h"
48 #include "media_smart_map_column.h"
49 #include "medialibrary_client_errno.h"
50 #include "medialibrary_data_manager.h"
51 #include "medialibrary_db_const.h"
52 #include "medialibrary_errno.h"
53 #include "medialibrary_napi_enum_comm.h"
54 #include "medialibrary_napi_log.h"
55 #include "medialibrary_peer_info.h"
56 #include "medialibrary_tracer.h"
57 #include "modal_ui_callback.h"
58 #include "modal_ui_extension_config.h"
59 #include "napi_base_context.h"
60 #include "napi_common_want.h"
61 #include "photo_album_column.h"
62 #include "photo_album_napi.h"
63 #include "result_set_utils.h"
64 #include "safe_map.h"
65 #include "search_column.h"
66 #include "short_term_callback.h"
67 #include "request_photo_uris_read_permission_callback.h"
68 #include "smart_album_napi.h"
69 #include "story_album_column.h"
70 #include "string_ex.h"
71 #include "string_wrapper.h"
72 #include "userfile_client.h"
73 #include "uv.h"
74 #include "vision_total_column.h"
75 #include "file_asset_napi.h"
76 #include "form_map.h"
77 #include "media_facard_photos_column.h"
78 #include "rdb_utils.h"
79 #ifdef HAS_ACE_ENGINE_PART
80 #include "ui_content.h"
81 #endif
82 #include "ui_extension_context.h"
83 #include "want.h"
84 #include "js_native_api.h"
85 #include "js_native_api_types.h"
86 #include "delete_callback.h"
87 #include "window.h"
88 #include "permission_utils.h"
89 #include "userfilemgr_uri.h"
90 #include "user_photography_info_column.h"
91 #include "foreground_analysis_meta.h"
92 #include "smart_album_column.h"
93 #include "album_operation_uri.h"
94 #include "data_secondary_directory_uri.h"
95 #include "user_define_ipc_client.h"
96 #include "form_info_vo.h"
97 #include "medialibrary_business_code.h"
98 #include "create_asset_vo.h"
99 #include "create_album_vo.h"
100 #include "delete_albums_vo.h"
101 #include "trash_photos_vo.h"
102 #include "file_uri.h"
103 #include "grant_photo_uri_permission_vo.h"
104 #include "grant_photo_uris_permission_vo.h"
105 #include "cancel_photo_uri_permission_vo.h"
106 #include "start_thumbnail_creation_task_vo.h"
107 #include "stop_thumbnail_creation_task_vo.h"
108 #include "get_index_construct_progress_vo.h"
109 #include "get_assets_vo.h"
110 #include "query_albums_vo.h"
111 #include "get_albums_by_ids_vo.h"
112 #include "start_asset_analysis_vo.h"
113 #include "get_photo_index_vo.h"
114 #include "query_result_vo.h"
115 #include "get_analysis_process_vo.h"
116 #include "get_photo_album_object_vo.h"
117 #include "set_photo_album_order_vo.h"
118 #include "result_set_napi.h"
119
120 #include "parcel.h"
121 #include "medialibrary_notify_utils.h"
122 #include "qos.h"
123 #include "vision_ocr_column.h"
124 #include "vision_video_label_column.h"
125 #include "vision_label_column.h"
126 #include "vision_image_face_column.h"
127
128 using namespace std;
129 using namespace OHOS::AppExecFwk;
130 using namespace OHOS::NativeRdb;
131 using namespace OHOS::DataShare;
132 using namespace OHOS::Security::AccessToken;
133
134 namespace OHOS {
135 namespace Media {
136 using ChangeType = AAFwk::ChangeInfo::ChangeType;
137 thread_local unique_ptr<ChangeListenerNapi> g_listObj = nullptr;
138 const int32_t SECOND_ENUM = 2;
139 const int32_t THIRD_ENUM = 3;
140 const int32_t FORMID_MAX_LEN = 19;
141 const int32_t SLEEP_TIME = 10;
142 const int64_t MAX_INT64 = 9223372036854775807;
143 const int32_t MAX_QUERY_LIMIT = 150;
144 const int32_t MAX_CREATE_ASSET_LIMIT = 500;
145 const int32_t MAX_QUERY_ALBUM_LIMIT = 500;
146 const int32_t MAX_LEN_LIMIT = 9999;
147 constexpr uint32_t CONFIRM_BOX_ARRAY_MAX_LENGTH = 100;
148 const string DATE_FUNCTION = "DATE(";
149 const size_t MAX_SET_ORDER_ARRAY_SIZE = 1000;
150
151 static const std::unordered_map<int32_t, std::string> NEED_COMPATIBLE_COLUMN_MAP = {
152 {ANALYSIS_LABEL, FEATURE},
153 {ANALYSIS_FACE, FEATURES},
154 {ANALYSIS_VIDEO_LABEL, VIDEO_PART_FEATURE},
155 {ANALYSIS_OCR, OCR_TEXT_MSG}
156 };
157
158 mutex MediaLibraryNapi::sUserFileClientMutex_;
159 mutex MediaLibraryNapi::sOnOffMutex_;
160 string ChangeListenerNapi::trashAlbumUri_;
161 static SafeMap<int32_t, std::shared_ptr<ThumbnailBatchGenerateObserver>> thumbnailGenerateObserverMap;
162 static SafeMap<int32_t, std::shared_ptr<ThumbnailGenerateHandler>> thumbnailGenerateHandlerMap;
163 static std::atomic<int32_t> requestIdCounter_ = 0;
164 static std::atomic<int32_t> requestIdCallback_ = 0;
165 static map<string, ListenerType> ListenerTypeMaps = {
166 {"audioChange", AUDIO_LISTENER},
167 {"videoChange", VIDEO_LISTENER},
168 {"imageChange", IMAGE_LISTENER},
169 {"fileChange", FILE_LISTENER},
170 {"albumChange", ALBUM_LISTENER},
171 {"deviceChange", DEVICE_LISTENER},
172 {"remoteFileChange", REMOTEFILE_LISTENER}
173 };
174
175 const std::string SUBTYPE = "subType";
176 const std::string PAH_SUBTYPE = "subtype";
177 const std::string CAMERA_SHOT_KEY = "cameraShotKey";
178 const std::map<std::string, std::string> PHOTO_CREATE_OPTIONS_PARAM = {
179 { SUBTYPE, PhotoColumn::PHOTO_SUBTYPE },
180 { CAMERA_SHOT_KEY, PhotoColumn::CAMERA_SHOT_KEY },
181 { PAH_SUBTYPE, PhotoColumn::PHOTO_SUBTYPE }
182
183 };
184
185 const std::string TITLE = "title";
186 const std::map<std::string, std::string> CREATE_OPTIONS_PARAM = {
187 { TITLE, MediaColumn::MEDIA_TITLE }
188 };
189
190 const std::map<int32_t, std::string> FOREGROUND_ANALYSIS_ASSETS_MAP = {
191 { ANALYSIS_SEARCH_INDEX, PAH_QUERY_ANA_FOREGROUND }
192 };
193
194 const std::string EXTENSION = "fileNameExtension";
195 const std::string PHOTO_TYPE = "photoType";
196 const std::string PHOTO_SUB_TYPE = "subtype";
197 const std::string SHORT_TERM_TAG = "shortTerm";
198 const std::string SHORT_TERM_TITLE = "title";
199 const std::string SHORT_TERM_EXTENSION = "extension";
200 const std::string SHORT_TERM_PHOTO_TYPE = "photoType";
201 const std::string SHORT_TERM_PHOTO_SUB_TYPE = "photoSubType";
202 const std::string CONFIRM_BOX_PACKAGE_NAME = "com.ohos.photos";
203 const std::string CONFIRM_BOX_EXT_ABILITY_NAME = "SaveUIExtensionAbility";
204 const std::string CONFIRM_BOX_EXT_DEFAULT_ALBUM_NAME_ABILITY_NAME = "DefaultAlbumNameUIExtensionAbility";
205 const std::string CONFIRM_BOX_EXTENSION_TYPE = "ability.want.params.uiExtensionType";
206 const std::string CONFIRM_BOX_REQUEST_TYPE = "sysDialog/common";
207 const std::string CONFIRM_BOX_SRC_FILE_URIS = "ability.params.stream";
208 const std::string CONFIRM_BOX_TITLE_ARRAY = "titleArray";
209 const std::string CONFIRM_BOX_EXTENSION_ARRAY = "extensionArray";
210 const std::string CONFIRM_BOX_PHOTO_TYPE_ARRAY = "photoTypeArray";
211 const std::string CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY = "photoSubTypeArray";
212 const std::string CONFIRM_BOX_BUNDLE_NAME = "bundleName";
213 const std::string CONFIRM_BOX_APP_NAME = "appName";
214 const std::string CONFIRM_BOX_APP_ID = "appId";
215 const std::string TARGET_PAGE = "targetPage";
216 const std::string TOKEN_ID = "tokenId";
217
218 const std::string LANGUAGE_ZH = "zh-Hans";
219 const std::string LANGUAGE_EN = "en-Latn-US";
220 const std::string LANGUAGE_ZH_TR = "zh-Hant";
221
222 thread_local napi_ref MediaLibraryNapi::sConstructor_ = nullptr;
223 thread_local napi_ref MediaLibraryNapi::sMediaTypeEnumRef_ = nullptr;
224 thread_local napi_ref MediaLibraryNapi::sKeyFrameThumbnailTypeRef_ = nullptr;
225 thread_local napi_ref MediaLibraryNapi::sDirectoryEnumRef_ = nullptr;
226 thread_local napi_ref MediaLibraryNapi::sVirtualAlbumTypeEnumRef_ = nullptr;
227 thread_local napi_ref MediaLibraryNapi::sFileKeyEnumRef_ = nullptr;
228 thread_local napi_ref MediaLibraryNapi::sPrivateAlbumEnumRef_ = nullptr;
229 thread_local napi_ref MediaLibraryNapi::sDeliveryModeEnumRef_ = nullptr;
230 thread_local napi_ref MediaLibraryNapi::sSourceModeEnumRef_ = nullptr;
231 thread_local napi_ref MediaLibraryNapi::sCompatibleModeEnumRef_ = nullptr;
232 thread_local napi_ref MediaLibraryNapi::sPositionTypeEnumRef_ = nullptr;
233 thread_local napi_ref MediaLibraryNapi::sPhotoSubType_ = nullptr;
234 thread_local napi_ref MediaLibraryNapi::sPhotoPermissionType_ = nullptr;
235 thread_local napi_ref MediaLibraryNapi::sHideSensitiveType_ = nullptr;
236 thread_local napi_ref MediaLibraryNapi::sDynamicRangeType_ = nullptr;
237 thread_local napi_ref MediaLibraryNapi::sHiddenPhotosDisplayModeEnumRef_ = nullptr;
238 thread_local napi_ref MediaLibraryNapi::sAuthorizationModeEnumRef_ = nullptr;
239 using CompleteCallback = napi_async_complete_callback;
240 using Context = MediaLibraryAsyncContext* ;
241
242 thread_local napi_ref MediaLibraryNapi::userFileMgrConstructor_ = nullptr;
243 thread_local napi_ref MediaLibraryNapi::photoAccessHelperConstructor_ = nullptr;
244 thread_local napi_ref MediaLibraryNapi::sUserFileMgrFileKeyEnumRef_ = nullptr;
245 thread_local napi_ref MediaLibraryNapi::sAudioKeyEnumRef_ = nullptr;
246 thread_local napi_ref MediaLibraryNapi::sImageVideoKeyEnumRef_ = nullptr;
247 thread_local napi_ref MediaLibraryNapi::sPhotoKeysEnumRef_ = nullptr;
248 thread_local napi_ref MediaLibraryNapi::sAlbumKeyEnumRef_ = nullptr;
249 thread_local napi_ref MediaLibraryNapi::sAlbumType_ = nullptr;
250 thread_local napi_ref MediaLibraryNapi::sAlbumSubType_ = nullptr;
251 thread_local napi_ref MediaLibraryNapi::sNotifyType_ = nullptr;
252 thread_local napi_ref MediaLibraryNapi::sDefaultChangeUriRef_ = nullptr;
253 thread_local napi_ref MediaLibraryNapi::sAnalysisType_ = nullptr;
254 thread_local napi_ref MediaLibraryNapi::sRequestPhotoTypeEnumRef_ = nullptr;
255 thread_local napi_ref MediaLibraryNapi::sResourceTypeEnumRef_ = nullptr;
256 thread_local napi_ref MediaLibraryNapi::sHighlightAlbumInfoType_ = nullptr;
257 thread_local napi_ref MediaLibraryNapi::sHighlightUserActionType_ = nullptr;
258 thread_local napi_ref MediaLibraryNapi::sMovingPhotoEffectModeEnumRef_ = nullptr;
259 thread_local napi_ref MediaLibraryNapi::sImageFileTypeEnumEnumRef_ = nullptr;
260 thread_local napi_ref MediaLibraryNapi::sCloudEnhancementTaskStageEnumRef_ = nullptr;
261 thread_local napi_ref MediaLibraryNapi::sCloudEnhancementStateEnumRef_ = nullptr;
262 thread_local napi_ref MediaLibraryNapi::sSupportedWatermarkTypeEnumRef_ = nullptr;
263 thread_local napi_ref MediaLibraryNapi::sVideoEnhancementTypeEnumRef_ = nullptr;
264 thread_local napi_ref MediaLibraryNapi::sCloudMediaDownloadTypeEnumRef_ = nullptr;
265 thread_local napi_ref MediaLibraryNapi::sCloudMediaRetainTypeEnumRef_ = nullptr;
266 thread_local napi_ref MediaLibraryNapi::sCloudMediaAssetTaskStatusEnumRef_ = nullptr;
267 thread_local napi_ref MediaLibraryNapi::sCloudMediaTaskPauseCauseEnumRef_ = nullptr;
268 thread_local napi_ref MediaLibraryNapi::sNotifyChangeTypeEnumRef_ = nullptr;
269 thread_local napi_ref MediaLibraryNapi::sThumbnailChangeStatusEnumRef_ = nullptr;
270 thread_local napi_ref MediaLibraryNapi::sStrongAssociationTypeEnumRef_ = nullptr;
271
272 constexpr int32_t DEFAULT_REFCOUNT = 1;
273 constexpr int32_t DEFAULT_ALBUM_COUNT = 1;
MediaLibraryNapi()274 MediaLibraryNapi::MediaLibraryNapi()
275 : env_(nullptr) {}
276
277 MediaLibraryNapi::~MediaLibraryNapi() = default;
278
MediaLibraryNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)279 void MediaLibraryNapi::MediaLibraryNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
280 {
281 MediaLibraryNapi *mediaLibrary = reinterpret_cast<MediaLibraryNapi*>(nativeObject);
282 if (mediaLibrary != nullptr) {
283 delete mediaLibrary;
284 mediaLibrary = nullptr;
285 }
286 }
287
Init(napi_env env,napi_value exports)288 napi_value MediaLibraryNapi::Init(napi_env env, napi_value exports)
289 {
290 napi_property_descriptor media_library_properties[] = {
291 DECLARE_NAPI_FUNCTION("getPublicDirectory", JSGetPublicDirectory),
292 DECLARE_NAPI_FUNCTION("getFileAssets", JSGetFileAssets),
293 DECLARE_NAPI_FUNCTION("getAlbums", JSGetAlbums),
294 DECLARE_NAPI_FUNCTION("createAsset", JSCreateAsset),
295 DECLARE_NAPI_FUNCTION("deleteAsset", JSDeleteAsset),
296 DECLARE_NAPI_FUNCTION("on", JSOnCallback),
297 DECLARE_NAPI_FUNCTION("off", JSOffCallback),
298 DECLARE_NAPI_FUNCTION("release", JSRelease),
299 DECLARE_NAPI_FUNCTION("getSmartAlbum", JSGetSmartAlbums),
300 DECLARE_NAPI_FUNCTION("getPrivateAlbum", JSGetPrivateAlbum),
301 DECLARE_NAPI_FUNCTION("createSmartAlbum", JSCreateSmartAlbum),
302 DECLARE_NAPI_FUNCTION("deleteSmartAlbum", JSDeleteSmartAlbum),
303 DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
304 DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
305 DECLARE_NAPI_FUNCTION("storeMediaAsset", JSStoreMediaAsset),
306 DECLARE_NAPI_FUNCTION("startImagePreview", JSStartImagePreview),
307 };
308 napi_property_descriptor static_prop[] = {
309 DECLARE_NAPI_STATIC_FUNCTION("getMediaLibrary", GetMediaLibraryNewInstance),
310 DECLARE_NAPI_STATIC_FUNCTION("getMediaLibraryAsync", GetMediaLibraryNewInstanceAsync),
311 DECLARE_NAPI_PROPERTY("MediaType", CreateMediaTypeEnum(env)),
312 DECLARE_NAPI_PROPERTY("FileKey", CreateFileKeyEnum(env)),
313 DECLARE_NAPI_PROPERTY("DirectoryType", CreateDirectoryTypeEnum(env)),
314 DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
315 };
316 napi_value ctorObj;
317 napi_status status = napi_define_class(env, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
318 MediaLibraryNapiConstructor, nullptr,
319 sizeof(media_library_properties) / sizeof(media_library_properties[PARAM0]),
320 media_library_properties, &ctorObj);
321 if (status == napi_ok) {
322 int32_t refCount = 1;
323 if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
324 status = napi_set_named_property(env, exports, MEDIA_LIB_NAPI_CLASS_NAME.c_str(), ctorObj);
325 if (status == napi_ok && napi_define_properties(env, exports,
326 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop) == napi_ok) {
327 return exports;
328 }
329 }
330 }
331 return nullptr;
332 }
333
UserFileMgrInit(napi_env env,napi_value exports)334 napi_value MediaLibraryNapi::UserFileMgrInit(napi_env env, napi_value exports)
335 {
336 NapiClassInfo info = {
337 USERFILE_MGR_NAPI_CLASS_NAME,
338 &userFileMgrConstructor_,
339 MediaLibraryNapiConstructor,
340 {
341 DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
342 DECLARE_NAPI_FUNCTION("getAudioAssets", JSGetAudioAssets),
343 DECLARE_NAPI_FUNCTION("getPhotoAlbums", JSGetPhotoAlbums),
344 DECLARE_NAPI_FUNCTION("createPhotoAsset", UserFileMgrCreatePhotoAsset),
345 DECLARE_NAPI_FUNCTION("createAudioAsset", UserFileMgrCreateAudioAsset),
346 DECLARE_NAPI_FUNCTION("delete", UserFileMgrTrashAsset),
347 DECLARE_NAPI_FUNCTION("on", UserFileMgrOnCallback),
348 DECLARE_NAPI_FUNCTION("off", UserFileMgrOffCallback),
349 DECLARE_NAPI_FUNCTION("getPrivateAlbum", UserFileMgrGetPrivateAlbum),
350 DECLARE_NAPI_FUNCTION("getActivePeers", JSGetActivePeers),
351 DECLARE_NAPI_FUNCTION("getAllPeers", JSGetAllPeers),
352 DECLARE_NAPI_FUNCTION("release", JSRelease),
353 DECLARE_NAPI_FUNCTION("createAlbum", CreatePhotoAlbum),
354 DECLARE_NAPI_FUNCTION("deleteAlbums", DeletePhotoAlbums),
355 DECLARE_NAPI_FUNCTION("getAlbums", GetPhotoAlbums),
356 DECLARE_NAPI_FUNCTION("getPhotoIndex", JSGetPhotoIndex), DECLARE_NAPI_FUNCTION("setHidden", SetHidden),
357 }
358 };
359 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
360
361 const vector<napi_property_descriptor> staticProps = {
362 DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgr", GetUserFileMgr),
363 DECLARE_NAPI_STATIC_FUNCTION("getUserFileMgrAsync", GetUserFileMgrAsync),
364 DECLARE_NAPI_PROPERTY("FileType", CreateMediaTypeUserFileEnum(env)),
365 DECLARE_NAPI_PROPERTY("FileKey", UserFileMgrCreateFileKeyEnum(env)),
366 DECLARE_NAPI_PROPERTY("AudioKey", CreateAudioKeyEnum(env)),
367 DECLARE_NAPI_PROPERTY("ImageVideoKey", CreateImageVideoKeyEnum(env)),
368 DECLARE_NAPI_PROPERTY("AlbumKey", CreateAlbumKeyEnum(env)),
369 DECLARE_NAPI_PROPERTY("PrivateAlbumType", CreatePrivateAlbumTypeEnum(env)),
370 DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
371 DECLARE_NAPI_PROPERTY("AlbumSubType", CreateAlbumSubTypeEnum(env)),
372 DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
373 DECLARE_NAPI_PROPERTY("PhotoSubType", CreatePhotoSubTypeEnum(env)),
374 DECLARE_NAPI_PROPERTY("ThumbnailType", CreateKeyFrameThumbnailTypeEnum(env)),
375 DECLARE_NAPI_PROPERTY("PhotoPermissionType", CreatePhotoPermissionTypeEnum(env)),
376 DECLARE_NAPI_PROPERTY("HideSensitiveType", CreateHideSensitiveTypeEnum(env)),
377 DECLARE_NAPI_PROPERTY("DynamicRangeType", CreateDynamicRangeTypeEnum(env)),
378 DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
379 DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env)),
380 DECLARE_NAPI_PROPERTY("HiddenPhotosDisplayMode", CreateHiddenPhotosDisplayModeEnum(env)),
381 DECLARE_NAPI_PROPERTY("RequestPhotoType", CreateRequestPhotoTypeEnum(env))
382 };
383 MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
384 return exports;
385 }
386
PhotoAccessHelperInit(napi_env env,napi_value exports)387 napi_value MediaLibraryNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
388 {
389 NapiClassInfo info = { PHOTOACCESSHELPER_NAPI_CLASS_NAME, &photoAccessHelperConstructor_,
390 MediaLibraryNapiConstructor,
391 {
392 DECLARE_NAPI_FUNCTION("getAssets", PhotoAccessGetPhotoAssets),
393 DECLARE_NAPI_FUNCTION("getBurstAssets", PhotoAccessGetBurstAssets),
394 DECLARE_WRITABLE_NAPI_FUNCTION("createAsset", PhotoAccessHelperCreatePhotoAsset),
395 DECLARE_NAPI_FUNCTION("registerChange", PhotoAccessHelperOnCallback),
396 DECLARE_NAPI_FUNCTION("unRegisterChange", PhotoAccessHelperOffCallback),
397 DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperTrashAsset),
398 DECLARE_NAPI_FUNCTION("release", JSRelease),
399 DECLARE_NAPI_FUNCTION("createAlbum", PhotoAccessCreatePhotoAlbum),
400 DECLARE_NAPI_FUNCTION("deleteAlbums", PhotoAccessDeletePhotoAlbums),
401 DECLARE_NAPI_FUNCTION("getAlbums", PahGetAlbums),
402 DECLARE_NAPI_FUNCTION("getAlbumsByIds", PhotoAccessGetPhotoAlbumsByIds),
403 DECLARE_NAPI_FUNCTION("getPhotoIndex", PhotoAccessGetPhotoIndex),
404 DECLARE_NAPI_FUNCTION("getIndexConstructProgress", PhotoAccessGetIndexConstructProgress),
405 DECLARE_NAPI_FUNCTION("setHidden", SetHidden),
406 DECLARE_NAPI_FUNCTION("getHiddenAlbums", PahGetHiddenAlbums),
407 DECLARE_WRITABLE_NAPI_FUNCTION("applyChanges", JSApplyChanges),
408 DECLARE_NAPI_FUNCTION("saveFormInfo", PhotoAccessSaveFormInfo),
409 DECLARE_NAPI_FUNCTION("saveGalleryFormInfo", PhotoAccessSaveGalleryFormInfo),
410 DECLARE_NAPI_FUNCTION("removeFormInfo", PhotoAccessRemoveFormInfo),
411 DECLARE_NAPI_FUNCTION("removeGalleryFormInfo", PhotoAccessRemoveGalleryFormInfo),
412 DECLARE_NAPI_FUNCTION("updateGalleryFormInfo", PhotoAccessUpdateGalleryFormInfo),
413 DECLARE_NAPI_FUNCTION("getAssetsSync", PhotoAccessGetPhotoAssetsSync),
414 DECLARE_NAPI_FUNCTION("getAlbumsSync", PhotoAccessGetPhotoAlbumsSync),
415 DECLARE_NAPI_FUNCTION("getFileAssetsInfo", PhotoAccessGetFileAssetsInfo),
416 DECLARE_NAPI_FUNCTION("startCreateThumbnailTask", PhotoAccessStartCreateThumbnailTask),
417 DECLARE_NAPI_FUNCTION("stopCreateThumbnailTask", PhotoAccessStopCreateThumbnailTask),
418 DECLARE_NAPI_FUNCTION("startThumbnailCreationTask", PhotoAccessStartCreateThumbnailTask),
419 DECLARE_NAPI_FUNCTION("stopThumbnailCreationTask", PhotoAccessStopCreateThumbnailTask),
420 DECLARE_NAPI_FUNCTION("createAssetsForApp", PhotoAccessHelperAgentCreateAssets),
421 DECLARE_NAPI_FUNCTION("createAssetsHasPermission", CreateAssetsHasPermission),
422 DECLARE_NAPI_FUNCTION("grantPhotoUriPermission", PhotoAccessGrantPhotoUriPermission),
423 DECLARE_NAPI_FUNCTION("grantPhotoUrisPermission", PhotoAccessGrantPhotoUrisPermission),
424 DECLARE_NAPI_FUNCTION("cancelPhotoUriPermission", PhotoAccessCancelPhotoUriPermission),
425 DECLARE_NAPI_FUNCTION("createAssetsForAppWithMode", PhotoAccessHelperAgentCreateAssetsWithMode),
426 DECLARE_NAPI_FUNCTION("getDataAnalysisProgress", PhotoAccessHelperGetDataAnalysisProgress),
427 DECLARE_NAPI_FUNCTION("getSharedPhotoAssets", PhotoAccessGetSharedPhotoAssets),
428 DECLARE_NAPI_FUNCTION("getSupportedPhotoFormats", PhotoAccessGetSupportedPhotoFormats),
429 DECLARE_NAPI_FUNCTION("setForceHideSensitiveType", PhotoAccessHelperSetForceHideSensitiveType),
430 DECLARE_NAPI_FUNCTION("getAnalysisData", PhotoAccessHelperGetAnalysisData),
431 DECLARE_NAPI_FUNCTION("createAssetsForAppWithAlbum", CreateAssetsForAppWithAlbum),
432 DECLARE_NAPI_FUNCTION("startAssetAnalysis", PhotoAccessStartAssetAnalysis),
433 DECLARE_NAPI_FUNCTION("query", PhotoAccessQuery),
434 DECLARE_NAPI_FUNCTION("on", PhotoAccessRegisterCallback),
435 DECLARE_NAPI_FUNCTION("off", PhotoAccessUnregisterCallback),
436 DECLARE_NAPI_FUNCTION("getPhotoAlbums", PhotoAccessGetPhotoAlbumsWithoutSubtype),
437 DECLARE_NAPI_FUNCTION("getPhotoAlbumOrder", PhotoAccessGetPhotoAlbumOrder),
438 DECLARE_NAPI_FUNCTION("setPhotoAlbumOrder", PhotoAccessSetPhotoAlbumOrder),
439 }
440 };
441 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
442
443 const vector<napi_property_descriptor> staticProps = {
444 DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelper", GetPhotoAccessHelper),
445 DECLARE_NAPI_STATIC_FUNCTION("startPhotoPicker", StartPhotoPicker),
446 DECLARE_NAPI_STATIC_FUNCTION("getPhotoAccessHelperAsync", GetPhotoAccessHelperAsync),
447 DECLARE_NAPI_STATIC_FUNCTION("createDeleteRequest", CreateDeleteRequest),
448 DECLARE_NAPI_STATIC_FUNCTION("showAssetsCreationDialog", ShowAssetsCreationDialog),
449 DECLARE_NAPI_STATIC_FUNCTION("checkShortTermPermission", CheckShortTermPermission),
450 DECLARE_NAPI_STATIC_FUNCTION("createAssetWithShortTermPermission", CreateAssetWithShortTermPermission),
451 DECLARE_NAPI_PROPERTY("ThumbnailType", CreateKeyFrameThumbnailTypeEnum(env)),
452 DECLARE_NAPI_STATIC_FUNCTION("requestPhotoUrisReadPermission", RequestPhotoUrisReadPermission),
453 DECLARE_NAPI_PROPERTY("PhotoType", CreateMediaTypeUserFileEnum(env)),
454 DECLARE_NAPI_PROPERTY("AlbumKeys", CreateAlbumKeyEnum(env)),
455 DECLARE_NAPI_PROPERTY("AlbumType", CreateAlbumTypeEnum(env)),
456 DECLARE_NAPI_PROPERTY("PhotoKeys", CreatePhotoKeysEnum(env)),
457 DECLARE_NAPI_PROPERTY("AlbumSubtype", CreateAlbumSubTypeEnum(env)),
458 DECLARE_NAPI_PROPERTY("PositionType", CreatePositionTypeEnum(env)),
459 DECLARE_NAPI_PROPERTY("PhotoSubtype", CreatePhotoSubTypeEnum(env)),
460 DECLARE_NAPI_PROPERTY("PhotoPermissionType", CreatePhotoPermissionTypeEnum(env)),
461 DECLARE_NAPI_PROPERTY("HideSensitiveType", CreateHideSensitiveTypeEnum(env)),
462 DECLARE_NAPI_PROPERTY("NotifyType", CreateNotifyTypeEnum(env)),
463 DECLARE_NAPI_PROPERTY("DefaultChangeUri", CreateDefaultChangeUriEnum(env)),
464 DECLARE_NAPI_PROPERTY("HiddenPhotosDisplayMode", CreateHiddenPhotosDisplayModeEnum(env)),
465 DECLARE_NAPI_PROPERTY("AnalysisType", CreateAnalysisTypeEnum(env)),
466 DECLARE_NAPI_PROPERTY("RequestPhotoType", CreateRequestPhotoTypeEnum(env)),
467 DECLARE_NAPI_PROPERTY("ResourceType", CreateResourceTypeEnum(env)),
468 DECLARE_NAPI_PROPERTY("DeliveryMode", CreateDeliveryModeEnum(env)),
469 DECLARE_NAPI_PROPERTY("SourceMode", CreateSourceModeEnum(env)),
470 DECLARE_NAPI_PROPERTY("CompatibleMode", CreateCompatibleModeEnum(env)),
471 DECLARE_NAPI_PROPERTY("HighlightAlbumInfoType", CreateHighlightAlbumInfoTypeEnum(env)),
472 DECLARE_NAPI_PROPERTY("HighlightUserActionType", CreateHighlightUserActionTypeEnum(env)),
473 DECLARE_NAPI_PROPERTY("MovingPhotoEffectMode", CreateMovingPhotoEffectModeEnum(env)),
474 DECLARE_NAPI_PROPERTY("ImageFileType", CreateImageFileTypeEnum(env)),
475 DECLARE_NAPI_PROPERTY("CloudEnhancementTaskStage", CreateCloudEnhancementTaskStageEnum(env)),
476 DECLARE_NAPI_PROPERTY("CloudEnhancementState", CreateCloudEnhancementStateEnum(env)),
477 DECLARE_NAPI_PROPERTY("AuthorizationMode", CreateAuthorizationModeEnum(env)),
478 DECLARE_NAPI_PROPERTY("WatermarkType", CreateSupportedWatermarkTypeEnum(env)),
479 DECLARE_NAPI_PROPERTY("VideoEnhancementType", CreateVideoEnhancementTypeEnum(env)),
480 DECLARE_NAPI_PROPERTY("CloudMediaDownloadType", CreateCloudMediaDownloadTypeEnum(env)),
481 DECLARE_NAPI_PROPERTY("CloudMediaRetainType", CreateCloudMediaRetainTypeEnum(env)),
482 DECLARE_NAPI_PROPERTY("CloudMediaAssetTaskStatus", CreateCloudMediaAssetTaskStatusEnum(env)),
483 DECLARE_NAPI_PROPERTY("CloudMediaTaskPauseCause", CreateCloudMediaTaskPauseCauseEnum(env)),
484 DECLARE_NAPI_STATIC_FUNCTION("getPhotoPickerComponentDefaultAlbumName",
485 GetPhotoPickerComponentDefaultAlbumName),
486 DECLARE_NAPI_PROPERTY("NotifyChangeType", CreateNotifyChangeTypeEnum(env)),
487 DECLARE_NAPI_PROPERTY("ThumbnailChangeStatus", CreateThumbnailChangeStatusEnum(env)),
488 DECLARE_NAPI_PROPERTY("StrongAssociationType", CreateStrongAssociationTypeEnum(env)),
489 };
490 MediaLibraryNapiUtils::NapiAddStaticProps(env, exports, staticProps);
491 return exports;
492 }
493
CheckWhetherAsync(napi_env env,napi_callback_info info,bool & isAsync)494 static napi_status CheckWhetherAsync(napi_env env, napi_callback_info info, bool &isAsync)
495 {
496 isAsync = false;
497 size_t argc = ARGS_TWO;
498 napi_value argv[ARGS_TWO] = {0};
499 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
500 if (status != napi_ok) {
501 NAPI_ERR_LOG("Error while obtaining js environment information");
502 return status;
503 }
504
505 if (argc == ARGS_ONE) {
506 return napi_ok;
507 } else if (argc == ARGS_TWO) {
508 napi_valuetype valueType = napi_undefined;
509 status = napi_typeof(env, argv[ARGS_ONE], &valueType);
510 if (status != napi_ok) {
511 NAPI_ERR_LOG("Error while obtaining js environment information");
512 return status;
513 }
514 if (valueType == napi_number) {
515 return napi_ok;
516 }
517 if (valueType == napi_boolean) {
518 isAsync = true;
519 }
520 status = napi_get_value_bool(env, argv[ARGS_ONE], &isAsync);
521 return status;
522 } else {
523 NAPI_ERR_LOG("argc %{public}d, is invalid", static_cast<int>(argc));
524 return napi_invalid_arg;
525 }
526 }
527
ParseUserIdFormCbInfo(napi_env env,napi_callback_info info)528 static int32_t ParseUserIdFormCbInfo(napi_env env, napi_callback_info info)
529 {
530 size_t argc = ARGS_TWO;
531 napi_value argv[ARGS_TWO] = {0};
532 napi_status status;
533 int userId = -1;
534 status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
535 if (status == napi_ok) {
536 napi_valuetype valueType = napi_undefined;
537 status = napi_typeof(env, argv[ARGS_ONE], &valueType);
538 if (status == napi_ok && valueType == napi_number) {
539 napi_get_value_int32(env, argv[ARGS_ONE], &userId);
540 }
541 }
542 return userId;
543 }
544
SetUserIdFromObjectInfo(unique_ptr<MediaLibraryAsyncContext> & asyncContext)545 static void SetUserIdFromObjectInfo(unique_ptr<MediaLibraryAsyncContext> &asyncContext)
546 {
547 if (asyncContext == nullptr || asyncContext->objectInfo == nullptr) {
548 NAPI_ERR_LOG("objectInfo is nullptr");
549 return;
550 }
551 asyncContext->userId = asyncContext->objectInfo->GetUserId();
552 }
553
554 // Constructor callback
MediaLibraryNapiConstructor(napi_env env,napi_callback_info info)555 napi_value MediaLibraryNapi::MediaLibraryNapiConstructor(napi_env env, napi_callback_info info)
556 {
557 napi_status status;
558 napi_value result = nullptr;
559 napi_value thisVar = nullptr;
560 MediaLibraryTracer tracer;
561 tracer.Start("MediaLibraryNapiConstructor");
562 int32_t userId = ParseUserIdFormCbInfo(env, info);
563 UserFileClient::SetUserId(userId);
564
565 NAPI_CALL(env, napi_get_undefined(env, &result));
566 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
567 if (status != napi_ok || thisVar == nullptr) {
568 NAPI_ERR_LOG("Error while obtaining js environment information, status: %{public}d", status);
569 return result;
570 }
571 unique_ptr<MediaLibraryNapi> obj = make_unique<MediaLibraryNapi>();
572 if (obj == nullptr) {
573 return result;
574 }
575 obj->env_ = env;
576 obj->SetUserId(userId);
577 // Initialize the ChangeListener object
578 if (g_listObj == nullptr) {
579 g_listObj = make_unique<ChangeListenerNapi>(env);
580 }
581 bool isAsync = false;
582 NAPI_CALL(env, CheckWhetherAsync(env, info, isAsync));
583 if (!isAsync) {
584 unique_lock<mutex> helperLock(sUserFileClientMutex_);
585 if (!UserFileClient::IsValid(obj->GetUserId())) {
586 UserFileClient::Init(env, info, obj->GetUserId());
587 if (!UserFileClient::IsValid(obj->GetUserId())) {
588 NAPI_ERR_LOG("UserFileClient creation failed");
589 helperLock.unlock();
590 return result;
591 }
592 }
593 helperLock.unlock();
594 }
595 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
596 MediaLibraryNapi::MediaLibraryNapiDestructor, nullptr, nullptr);
597 if (status == napi_ok) {
598 obj.release();
599 return thisVar;
600 } else {
601 NAPI_ERR_LOG("Failed to wrap the native media lib client object with JS, status: %{public}d", status);
602 }
603 return result;
604 }
605
CheckWhetherInitSuccess(napi_env env,napi_value value,bool checkIsValid,const int32_t userId=-1)606 static bool CheckWhetherInitSuccess(napi_env env, napi_value value, bool checkIsValid, const int32_t userId = -1)
607 {
608 napi_value propertyNames;
609 uint32_t propertyLength;
610 napi_valuetype valueType = napi_undefined;
611 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
612 if (valueType != napi_object) {
613 return false;
614 }
615
616 NAPI_CALL_BASE(env, napi_get_property_names(env, value, &propertyNames), false);
617 NAPI_CALL_BASE(env, napi_get_array_length(env, propertyNames, &propertyLength), false);
618 if (propertyLength == 0) {
619 return false;
620 }
621 if (checkIsValid && (!UserFileClient::IsValid(userId))) {
622 NAPI_ERR_LOG("UserFileClient is not valid");
623 return false;
624 }
625 return true;
626 }
627
CreateNewInstance(napi_env env,napi_callback_info info,napi_ref ref,bool isAsync=false)628 static napi_value CreateNewInstance(napi_env env, napi_callback_info info, napi_ref ref,
629 bool isAsync = false)
630 {
631 constexpr size_t ARG_CONTEXT = 1;
632 size_t argc = ARG_CONTEXT;
633 napi_value argv[ARGS_TWO] = {0};
634
635 napi_value thisVar = nullptr;
636 napi_value ctor = nullptr;
637 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
638 NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
639 if (isAsync) {
640 argc = ARGS_TWO;
641 NAPI_CALL(env, napi_get_boolean(env, true, &argv[ARGS_ONE]));
642 argv[ARGS_ONE] = argv[ARG_CONTEXT];
643 }
644 int32_t userId = -1;
645 if (argc > 1 && !isAsync) {
646 argc = ARGS_TWO;
647 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
648 NAPI_CALL(env, napi_get_reference_value(env, ref, &ctor));
649 napi_valuetype valueType = napi_undefined;
650 napi_typeof(env, argv[ARGS_ONE], &valueType);
651 if (valueType == napi_number) {
652 NAPI_CALL(env, napi_get_value_int32(env, argv[ARGS_ONE], &userId));
653 if (userId != -1 && !MediaLibraryNapiUtils::IsSystemApp()) {
654 NAPI_ERR_LOG("CreateNewInstance failed, target is not system app");
655 return nullptr;
656 }
657 UserFileClient::SetUserId(userId);
658 NAPI_INFO_LOG("CreateNewInstance for other user is %{public}d", userId);
659 }
660 }
661
662 napi_value result = nullptr;
663 NAPI_CALL(env, napi_new_instance(env, ctor, argc, argv, &result));
664 if (!CheckWhetherInitSuccess(env, result, !isAsync, userId)) {
665 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
666 NAPI_CALL(env, napi_get_undefined(env, &result));
667 }
668 return result;
669 }
670
GetMediaLibraryNewInstance(napi_env env,napi_callback_info info)671 napi_value MediaLibraryNapi::GetMediaLibraryNewInstance(napi_env env, napi_callback_info info)
672 {
673 MediaLibraryTracer tracer;
674 tracer.Start("getMediaLibrary");
675
676 napi_value result = nullptr;
677 napi_value ctor;
678 size_t argc = ARGS_ONE;
679 napi_value argv[ARGS_ONE] = {0};
680 napi_value thisVar = nullptr;
681 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
682 napi_status status = napi_get_reference_value(env, sConstructor_, &ctor);
683 if (status == napi_ok) {
684 status = napi_new_instance(env, ctor, argc, argv, &result);
685 if (status == napi_ok) {
686 if (CheckWhetherInitSuccess(env, result, true)) {
687 return result;
688 } else {
689 NAPI_ERR_LOG("Init MediaLibrary Instance is failed");
690 }
691 } else {
692 NAPI_ERR_LOG("New instance could not be obtained status: %{public}d", status);
693 }
694 } else {
695 NAPI_ERR_LOG("status = %{public}d", status);
696 }
697
698 napi_get_undefined(env, &result);
699 return result;
700 }
701
GetMediaLibraryAsyncExecute(napi_env env,void * data)702 static void GetMediaLibraryAsyncExecute(napi_env env, void *data)
703 {
704 MediaLibraryTracer tracer;
705 tracer.Start("GetMediaLibraryAsyncExecute");
706
707 MediaLibraryInitContext *asyncContext = static_cast<MediaLibraryInitContext *>(data);
708 if (asyncContext == nullptr) {
709 NAPI_ERR_LOG("Async context is null");
710 return;
711 }
712
713 asyncContext->error = ERR_DEFAULT;
714 unique_lock<mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
715 if (!UserFileClient::IsValid()) {
716 UserFileClient::Init(asyncContext->token_, true);
717 if (!UserFileClient::IsValid()) {
718 NAPI_ERR_LOG("UserFileClient creation failed");
719 asyncContext->error = ERR_INVALID_OUTPUT;
720 helperLock.unlock();
721 return;
722 }
723 }
724 helperLock.unlock();
725 }
726
GetMediaLibraryAsyncComplete(napi_env env,napi_status status,void * data)727 static void GetMediaLibraryAsyncComplete(napi_env env, napi_status status, void *data)
728 {
729 MediaLibraryInitContext *context = static_cast<MediaLibraryInitContext *>(data);
730 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
731 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
732 jsContext->status = false;
733
734 napi_value result = nullptr;
735 if (napi_get_reference_value(env, context->resultRef_, &result) != napi_ok) {
736 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
737 "Get result from context ref failed");
738 }
739 napi_valuetype valueType;
740 if (napi_typeof(env, result, &valueType) != napi_ok || valueType != napi_object) {
741 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
742 "Get result type failed " + to_string((int) valueType));
743 }
744
745 if (context->error == ERR_DEFAULT) {
746 jsContext->data = result;
747 jsContext->status = true;
748 napi_get_undefined(env, &jsContext->error);
749 } else {
750 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
751 "Failed to get MediaLibrary");
752 napi_get_undefined(env, &jsContext->data);
753 }
754
755 if (context->work != nullptr) {
756 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
757 context->work, *jsContext);
758 }
759 napi_delete_reference(env, context->resultRef_);
760 context->resultRef_ = nullptr;
761 delete context;
762 }
763
GetMediaLibraryNewInstanceAsync(napi_env env,napi_callback_info info)764 napi_value MediaLibraryNapi::GetMediaLibraryNewInstanceAsync(napi_env env, napi_callback_info info)
765 {
766 MediaLibraryTracer tracer;
767 tracer.Start("getMediaLibraryAsync");
768
769 unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
770 if (asyncContext == nullptr) {
771 NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
772 return nullptr;
773 }
774 asyncContext->argc = ARGS_TWO;
775 napi_value thisVar = nullptr;
776 NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
777 &thisVar, nullptr));
778
779 napi_value result = CreateNewInstance(env, info, sConstructor_, true);
780 napi_valuetype valueType;
781 NAPI_CALL(env, napi_typeof(env, result, &valueType));
782 if (valueType == napi_undefined) {
783 NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
784 return nullptr;
785 }
786 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
787 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
788
789 bool isStage = false;
790 NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
791 if (isStage) {
792 asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
793 } else {
794 asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
795 }
796
797 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
798 GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
799 }
800
GetUserFileMgr(napi_env env,napi_callback_info info)801 napi_value MediaLibraryNapi::GetUserFileMgr(napi_env env, napi_callback_info info)
802 {
803 MediaLibraryTracer tracer;
804 tracer.Start("getUserFileManager");
805
806 if (!MediaLibraryNapiUtils::IsSystemApp()) {
807 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
808 return nullptr;
809 }
810
811 return CreateNewInstance(env, info, userFileMgrConstructor_);
812 }
813
GetUserFileMgrAsync(napi_env env,napi_callback_info info)814 napi_value MediaLibraryNapi::GetUserFileMgrAsync(napi_env env, napi_callback_info info)
815 {
816 MediaLibraryTracer tracer;
817 tracer.Start("getUserFileManagerAsync");
818
819 if (!MediaLibraryNapiUtils::IsSystemApp()) {
820 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get userFileManger instance");
821 return nullptr;
822 }
823
824 unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
825 if (asyncContext == nullptr) {
826 NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
827 return nullptr;
828 }
829 asyncContext->argc = ARGS_TWO;
830 napi_value thisVar = nullptr;
831 NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
832 &thisVar, nullptr));
833
834 napi_value result = CreateNewInstance(env, info, userFileMgrConstructor_, true);
835 napi_valuetype valueType;
836 NAPI_CALL(env, napi_typeof(env, result, &valueType));
837 if (valueType == napi_undefined) {
838 NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
839 return nullptr;
840 }
841 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
842 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
843
844 bool isStage = false;
845 NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
846 if (isStage) {
847 asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
848 } else {
849 asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
850 }
851
852 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetUserFileMgrAsync",
853 GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
854 }
855
GetPhotoAccessHelper(napi_env env,napi_callback_info info)856 napi_value MediaLibraryNapi::GetPhotoAccessHelper(napi_env env, napi_callback_info info)
857 {
858 MediaLibraryTracer tracer;
859 tracer.Start("GetPhotoAccessHelper");
860
861 return CreateNewInstance(env, info, photoAccessHelperConstructor_);
862 }
863
GetPhotoAccessHelperAsync(napi_env env,napi_callback_info info)864 napi_value MediaLibraryNapi::GetPhotoAccessHelperAsync(napi_env env, napi_callback_info info)
865 {
866 MediaLibraryTracer tracer;
867 tracer.Start("GetPhotoAccessHelperAsync");
868
869 unique_ptr<MediaLibraryInitContext> asyncContext = make_unique<MediaLibraryInitContext>();
870 if (asyncContext == nullptr) {
871 NapiError::ThrowError(env, E_FAIL, "Failed to allocate memory for asyncContext");
872 return nullptr;
873 }
874 asyncContext->argc = ARGS_TWO;
875 napi_value thisVar = nullptr;
876 NAPI_CALL(env, napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]),
877 &thisVar, nullptr));
878
879 napi_value result = CreateNewInstance(env, info, photoAccessHelperConstructor_, true);
880 napi_valuetype valueType;
881 NAPI_CALL(env, napi_typeof(env, result, &valueType));
882 if (valueType == napi_undefined) {
883 NapiError::ThrowError(env, E_FAIL, "Failed to get userFileMgr instance");
884 return nullptr;
885 }
886 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, asyncContext));
887 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &asyncContext->resultRef_));
888
889 bool isStage = false;
890 NAPI_CALL(env, UserFileClient::CheckIsStage(env, info, isStage));
891 if (isStage) {
892 asyncContext->token_ = UserFileClient::ParseTokenInStageMode(env, info);
893 } else {
894 asyncContext->token_ = UserFileClient::ParseTokenInAbility(env, info);
895 }
896
897 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAccessHelperAsync",
898 GetMediaLibraryAsyncExecute, GetMediaLibraryAsyncComplete);
899 }
900
AddIntegerNamedProperty(napi_env env,napi_value object,const string & name,int32_t enumValue)901 static napi_status AddIntegerNamedProperty(napi_env env, napi_value object,
902 const string &name, int32_t enumValue)
903 {
904 napi_value enumNapiValue;
905 napi_status status = napi_create_int32(env, enumValue, &enumNapiValue);
906 if (status == napi_ok) {
907 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
908 }
909 return status;
910 }
911
CreateNumberEnumProperty(napi_env env,vector<string> properties,napi_ref & ref,int32_t offset=0)912 static napi_value CreateNumberEnumProperty(napi_env env, vector<string> properties, napi_ref &ref, int32_t offset = 0)
913 {
914 napi_value result = nullptr;
915 NAPI_CALL(env, napi_create_object(env, &result));
916 for (size_t i = 0; i < properties.size(); i++) {
917 NAPI_CALL(env, AddIntegerNamedProperty(env, result, properties[i], static_cast<int32_t>(i) + offset));
918 }
919 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
920 return result;
921 }
922
AddStringNamedProperty(napi_env env,napi_value object,const string & name,string enumValue)923 static napi_status AddStringNamedProperty(napi_env env, napi_value object,
924 const string &name, string enumValue)
925 {
926 napi_value enumNapiValue;
927 napi_status status = napi_create_string_utf8(env, enumValue.c_str(), NAPI_AUTO_LENGTH, &enumNapiValue);
928 if (status == napi_ok) {
929 status = napi_set_named_property(env, object, name.c_str(), enumNapiValue);
930 }
931 return status;
932 }
933
CreateStringEnumProperty(napi_env env,vector<pair<string,string>> properties,napi_ref & ref)934 static napi_value CreateStringEnumProperty(napi_env env, vector<pair<string, string>> properties, napi_ref &ref)
935 {
936 napi_value result = nullptr;
937 NAPI_CALL(env, napi_create_object(env, &result));
938 for (unsigned int i = 0; i < properties.size(); i++) {
939 NAPI_CALL(env, AddStringNamedProperty(env, result, properties[i].first, properties[i].second));
940 }
941 NAPI_CALL(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &ref));
942 return result;
943 }
944
DealWithCommonParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err,bool & present)945 static void DealWithCommonParam(napi_env env, napi_value arg,
946 const MediaLibraryAsyncContext &context, bool &err, bool &present)
947 {
948 MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
949 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
950
951 string propertyName = "selections";
952 string tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
953 if (!tmp.empty()) {
954 asyncContext->selection = tmp;
955 }
956
957 propertyName = "order";
958 tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
959 if (!tmp.empty()) {
960 asyncContext->order = tmp;
961 }
962
963 propertyName = "uri";
964 tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
965 if (!tmp.empty()) {
966 asyncContext->uri = tmp;
967 }
968
969 propertyName = "networkId";
970 tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
971 if (!tmp.empty()) {
972 asyncContext->networkId = tmp;
973 }
974
975 propertyName = "extendArgs";
976 tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
977 if (!tmp.empty()) {
978 asyncContext->extendArgs = tmp;
979 }
980 }
981
GetFetchOptionsParam(napi_env env,napi_value arg,const MediaLibraryAsyncContext & context,bool & err)982 static void GetFetchOptionsParam(napi_env env, napi_value arg, const MediaLibraryAsyncContext &context, bool &err)
983 {
984 MediaLibraryAsyncContext *asyncContext = const_cast<MediaLibraryAsyncContext *>(&context);
985 CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
986 napi_value property = nullptr;
987 napi_value stringItem = nullptr;
988 bool present = false;
989 DealWithCommonParam(env, arg, context, err, present);
990 napi_has_named_property(env, arg, "selectionArgs", &present);
991 if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok) {
992 uint32_t len = 0;
993 napi_get_array_length(env, property, &len);
994 char buffer[PATH_MAX];
995 for (size_t i = 0; i < len; i++) {
996 napi_get_element(env, property, i, &stringItem);
997 size_t res = 0;
998 napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
999 asyncContext->selectionArgs.push_back(string(buffer));
1000 CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
1001 }
1002 } else {
1003 NAPI_ERR_LOG("Could not get the string argument!");
1004 err = true;
1005 }
1006 }
1007
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)1008 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
1009 MediaLibraryAsyncContext &asyncContext)
1010 {
1011 bool err = false;
1012 const int32_t refCount = 1;
1013 auto context = &asyncContext;
1014
1015 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1016 for (size_t i = PARAM0; i < argc; i++) {
1017 napi_valuetype valueType = napi_undefined;
1018 napi_typeof(env, argv[i], &valueType);
1019
1020 if (i == PARAM0 && valueType == napi_object) {
1021 GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
1022 } else if (i == PARAM0 && valueType == napi_function) {
1023 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1024 break;
1025 } else if (i == PARAM1 && valueType == napi_function) {
1026 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1027 break;
1028 } else {
1029 NAPI_ASSERT(env, false, "type mismatch");
1030 }
1031 if (err) {
1032 NAPI_ERR_LOG("fetch options retrieval failed, err: %{public}d", err);
1033 NAPI_ASSERT(env, false, "type mismatch");
1034 }
1035 }
1036
1037 // Return true napi_value if params are successfully obtained
1038 napi_value result;
1039 napi_get_boolean(env, true, &result);
1040 return result;
1041 }
1042
GetPublicDirectoryExecute(napi_env env,void * data)1043 static void GetPublicDirectoryExecute(napi_env env, void *data)
1044 {
1045 MediaLibraryTracer tracer;
1046 tracer.Start("GetPublicDirectoryExecute");
1047
1048 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1049 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1050
1051 vector<string> selectionArgs;
1052 vector<string> columns;
1053 DataSharePredicates predicates;
1054 selectionArgs.push_back(to_string(context->dirType));
1055 predicates.SetWhereClause(DIRECTORY_DB_DIRECTORY_TYPE + " = ?");
1056 predicates.SetWhereArgs(selectionArgs);
1057 string queryUri = MEDIALIBRARY_DIRECTORY_URI;
1058 Uri uri(queryUri);
1059 int errCode = 0;
1060 shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode,
1061 context->userId);
1062 if (resultSet != nullptr) {
1063 auto count = 0;
1064 auto ret = resultSet->GetRowCount(count);
1065 if (ret != NativeRdb::E_OK) {
1066 NAPI_ERR_LOG("get rdbstore failed");
1067 context->error = JS_INNER_FAIL;
1068 return;
1069 }
1070 if (count == 0) {
1071 NAPI_ERR_LOG("Query for get publicDirectory form db failed");
1072 context->error = JS_INNER_FAIL;
1073 return;
1074 }
1075 NAPI_INFO_LOG("Query for get publicDirectory count = %{private}d", count);
1076 if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
1077 context->directoryRelativePath = get<string>(
1078 ResultSetUtils::GetValFromColumn(DIRECTORY_DB_DIRECTORY, resultSet, TYPE_STRING));
1079 }
1080 if (context->dirType == DirType::DIR_DOCUMENTS) {
1081 context->directoryRelativePath = DOC_DIR_VALUES;
1082 } else if (context->dirType == DirType::DIR_DOWNLOAD) {
1083 context->directoryRelativePath = DOWNLOAD_DIR_VALUES;
1084 }
1085 return;
1086 } else {
1087 context->SaveError(errCode);
1088 NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
1089 }
1090 }
1091
GetPublicDirectoryCallbackComplete(napi_env env,napi_status status,void * data)1092 static void GetPublicDirectoryCallbackComplete(napi_env env, napi_status status, void *data)
1093 {
1094 MediaLibraryTracer tracer;
1095 tracer.Start("GetPublicDirectoryCallbackComplete");
1096
1097 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1098 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1099 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1100 jsContext->status = false;
1101 if (context->error == ERR_DEFAULT) {
1102 napi_create_string_utf8(env, context->directoryRelativePath.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
1103 jsContext->status = true;
1104 napi_get_undefined(env, &jsContext->error);
1105 } else {
1106 context->HandleError(env, jsContext->error);
1107 napi_get_undefined(env, &jsContext->data);
1108 }
1109
1110 tracer.Finish();
1111 if (context->work != nullptr) {
1112 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1113 context->work, *jsContext);
1114 }
1115
1116 delete context;
1117 }
1118
JSGetPublicDirectory(napi_env env,napi_callback_info info)1119 napi_value MediaLibraryNapi::JSGetPublicDirectory(napi_env env, napi_callback_info info)
1120 {
1121 napi_status status;
1122 napi_value result = nullptr;
1123 size_t argc = ARGS_TWO;
1124 napi_value argv[ARGS_TWO] = {0};
1125 napi_value thisVar = nullptr;
1126 const int32_t refCount = 1;
1127
1128 MediaLibraryTracer tracer;
1129 tracer.Start("JSGetPublicDirectory");
1130
1131 GET_JS_ARGS(env, info, argc, argv, thisVar);
1132 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1133 napi_get_undefined(env, &result);
1134
1135 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1136 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1137 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1138 for (size_t i = PARAM0; i < argc; i++) {
1139 napi_valuetype valueType = napi_undefined;
1140 napi_typeof(env, argv[i], &valueType);
1141
1142 if (i == PARAM0 && valueType == napi_number) {
1143 napi_get_value_uint32(env, argv[i], &asyncContext->dirType);
1144 } else if (i == PARAM1 && valueType == napi_function) {
1145 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
1146 break;
1147 } else {
1148 NAPI_ASSERT(env, false, "type mismatch");
1149 }
1150 }
1151
1152 SetUserIdFromObjectInfo(asyncContext);
1153 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPublicDirectory",
1154 GetPublicDirectoryExecute, GetPublicDirectoryCallbackComplete);
1155 }
1156
1157 return result;
1158 }
1159
1160 #ifdef MEDIALIBRARY_COMPATIBILITY
GetVirtualIdFromApi10Uri(const string & uri)1161 static string GetVirtualIdFromApi10Uri(const string &uri)
1162 {
1163 string fileId = MediaFileUtils::GetIdFromUri(uri);
1164 if (!all_of(fileId.begin(), fileId.end(), ::isdigit)) {
1165 return fileId;
1166 }
1167 int32_t id;
1168 if (!StrToInt(fileId, id)) {
1169 NAPI_ERR_LOG("invalid fileuri %{private}s", uri.c_str());
1170 return fileId;
1171 }
1172 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
1173 return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_IMAGE));
1174 } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
1175 return to_string(MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_AUDIO));
1176 } else {
1177 return fileId;
1178 }
1179 }
1180 #endif
1181
GetFileAssetUpdateSelections(MediaLibraryAsyncContext * context)1182 static void GetFileAssetUpdateSelections(MediaLibraryAsyncContext *context)
1183 {
1184 if (!context->uri.empty()) {
1185 NAPI_ERR_LOG("context->uri is = %{private}s", context->uri.c_str());
1186 context->networkId = MediaFileUtils::GetNetworkIdFromUri(context->uri);
1187 #ifdef MEDIALIBRARY_COMPATIBILITY
1188 string fileId = GetVirtualIdFromApi10Uri(context->uri);
1189 #else
1190 string fileId = MediaFileUtils::::GetIdFromUri(context->uri);
1191 #endif
1192 if (!fileId.empty()) {
1193 string idPrefix = MEDIA_DATA_DB_ID + " = ? ";
1194 #ifdef MEDIALIBRARY_COMPATIBILITY
1195 context->selection = idPrefix;
1196 context->selectionArgs.clear();
1197 context->selectionArgs.emplace_back(fileId);
1198 #else
1199 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, idPrefix);
1200 context->selectionArgs.emplace_back(fileId);
1201 #endif
1202 }
1203 }
1204
1205 #ifdef MEDIALIBRARY_COMPATIBILITY
1206 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, MediaColumn::ASSETS_QUERY_FILTER);
1207 MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs, MEDIA_DATA_DB_RELATIVE_PATH,
1208 MEDIA_DATA_DB_RELATIVE_PATH, ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH);
1209 #else
1210 string trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? ";
1211 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
1212 context->selectionArgs.emplace_back("0");
1213 #endif
1214 string prefix = MEDIA_DATA_DB_MEDIA_TYPE + " <> ? ";
1215 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, prefix);
1216 context->selectionArgs.emplace_back(to_string(MEDIA_TYPE_ALBUM));
1217 }
1218
LogMedialibraryAPI(const string & saveUri)1219 static void LogMedialibraryAPI(const string& saveUri)
1220 {
1221 string logMedialibraryAPI = MEDIALIBRARY_DATA_URI + "/" + MISC_OPERATION + "/" + "log_medialibrary_api";
1222 Uri logUri(logMedialibraryAPI);
1223 DataShare::DataShareValuesBucket valuesBucket;
1224 string result;
1225 valuesBucket.Put("saveUri", saveUri);
1226 UserFileClient::InsertExt(logUri, valuesBucket, result);
1227 }
1228
GetFileAssetsExecute(napi_env env,void * data)1229 static void GetFileAssetsExecute(napi_env env, void *data)
1230 {
1231 MediaLibraryTracer tracer;
1232 tracer.Start("GetFileAssetsExecute");
1233
1234 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1235 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1236
1237 GetFileAssetUpdateSelections(context);
1238 context->fetchColumn = FILE_ASSET_COLUMNS;
1239 if (context->extendArgs.find(DATE_FUNCTION) != string::npos) {
1240 string group(" GROUP BY (");
1241 group += context->extendArgs + " )";
1242 context->selection += group;
1243 context->fetchColumn.insert(context->fetchColumn.begin(), "count(*)");
1244 }
1245 MediaLibraryNapiUtils::FixSpecialDateType(context->selection);
1246 context->predicates.SetWhereClause(context->selection);
1247 context->predicates.SetWhereArgs(context->selectionArgs);
1248 context->predicates.SetOrder(context->order);
1249
1250 LogMedialibraryAPI("");
1251
1252 string queryUri = MEDIALIBRARY_DATA_URI;
1253 if (!context->networkId.empty()) {
1254 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1255 }
1256 Uri uri(queryUri);
1257 int errCode = 0;
1258 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
1259 context->predicates, context->fetchColumn, errCode, context->userId);
1260 if (resultSet != nullptr) {
1261 // Create FetchResult object using the contents of resultSet
1262 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1263 context->fetchFileResult->SetNetworkId(context->networkId);
1264 return;
1265 } else {
1266 context->SaveError(errCode);
1267 NAPI_ERR_LOG("Query for get publicDirectory failed! errorCode is = %{public}d", errCode);
1268 }
1269 }
1270
GetNapiFileResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1271 static void GetNapiFileResult(napi_env env, MediaLibraryAsyncContext *context,
1272 unique_ptr<JSAsyncContextOutput> &jsContext)
1273 {
1274 // Create FetchResult object using the contents of resultSet
1275 if (context->fetchFileResult == nullptr) {
1276 NAPI_ERR_LOG("No fetch file result found!");
1277 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1278 "Failed to obtain Fetch File Result");
1279 return;
1280 }
1281 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchFileResult));
1282 if (fileResult == nullptr) {
1283 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1284 "Failed to create js object for Fetch File Result");
1285 } else {
1286 jsContext->data = fileResult;
1287 jsContext->status = true;
1288 napi_get_undefined(env, &jsContext->error);
1289 }
1290 }
1291
GetFileAssetsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1292 static void GetFileAssetsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1293 {
1294 MediaLibraryTracer tracer;
1295 tracer.Start("GetFileAssetsAsyncCallbackComplete");
1296
1297 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1298 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1299
1300 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1301 jsContext->status = false;
1302 napi_get_undefined(env, &jsContext->data);
1303
1304 if (context->error != ERR_DEFAULT) {
1305 context->HandleError(env, jsContext->error);
1306 } else {
1307 GetNapiFileResult(env, context, jsContext);
1308 }
1309
1310 tracer.Finish();
1311 if (context->work != nullptr) {
1312 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1313 context->work, *jsContext);
1314 }
1315 delete context;
1316 }
1317
JSGetFileAssets(napi_env env,napi_callback_info info)1318 napi_value MediaLibraryNapi::JSGetFileAssets(napi_env env, napi_callback_info info)
1319 {
1320 napi_status status;
1321 napi_value result = nullptr;
1322 size_t argc = ARGS_TWO;
1323 napi_value argv[ARGS_TWO] = {0};
1324 napi_value thisVar = nullptr;
1325
1326 MediaLibraryTracer tracer;
1327 tracer.Start("JSGetFileAssets");
1328
1329 GET_JS_ARGS(env, info, argc, argv, thisVar);
1330 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1331 napi_get_undefined(env, &result);
1332
1333 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1334 asyncContext->mediaTypes.clear();
1335 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1336 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1337 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1338 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1339 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1340
1341 SetUserIdFromObjectInfo(asyncContext);
1342 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetFileAssets", GetFileAssetsExecute,
1343 GetFileAssetsAsyncCallbackComplete);
1344 }
1345
1346 return result;
1347 }
1348
1349 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatSetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1350 static void CompatSetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1351 {
1352 MediaLibraryTracer tracer;
1353 tracer.Start("CompatSetAlbumCoverUri");
1354 DataSharePredicates predicates;
1355 int err;
1356 if (album->GetAlbumType() == PhotoAlbumType::USER) {
1357 err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates, false);
1358 } else {
1359 err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates, false);
1360 }
1361 if (err < 0) {
1362 NAPI_WARN_LOG("Failed to set cover uri for album subtype: %{public}d", album->GetAlbumSubType());
1363 return;
1364 }
1365 predicates.OrderByDesc(MediaColumn::MEDIA_DATE_ADDED);
1366 predicates.Limit(1, 0);
1367
1368 Uri uri(URI_QUERY_PHOTO_MAP);
1369 vector<string> columns;
1370 columns.assign(MediaColumn::DEFAULT_FETCH_COLUMNS.begin(), MediaColumn::DEFAULT_FETCH_COLUMNS.end());
1371 auto resultSet = UserFileClient::Query(uri, predicates, columns, err, context->userId);
1372 if (resultSet == nullptr) {
1373 NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", err);
1374 context->SaveError(err);
1375 return;
1376 }
1377 auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1378 if (fetchResult->GetCount() == 0) {
1379 return;
1380 }
1381 auto fileAsset = fetchResult->GetFirstObject();
1382 if (fileAsset == nullptr) {
1383 NAPI_WARN_LOG("Failed to get cover asset!");
1384 return;
1385 }
1386 album->SetCoverUri(fileAsset->GetUri());
1387 }
1388
SetCompatAlbumName(AlbumAsset * albumData)1389 static void SetCompatAlbumName(AlbumAsset *albumData)
1390 {
1391 string albumName;
1392 switch (albumData->GetAlbumSubType()) {
1393 case PhotoAlbumSubType::CAMERA:
1394 albumName = CAMERA_ALBUM_NAME;
1395 break;
1396 case PhotoAlbumSubType::SCREENSHOT:
1397 albumName = SCREEN_SHOT_ALBUM_NAME;
1398 break;
1399 default:
1400 NAPI_WARN_LOG("Ignore unsupported compat album type: %{public}d", albumData->GetAlbumSubType());
1401 }
1402 albumData->SetAlbumName(albumName);
1403 }
1404
CompatSetAlbumCount(unique_ptr<AlbumAsset> & album)1405 static void CompatSetAlbumCount(unique_ptr<AlbumAsset> &album)
1406 {
1407 MediaLibraryTracer tracer;
1408 tracer.Start("CompatSetAlbumCount");
1409 DataSharePredicates predicates;
1410 int err;
1411 if (album->GetAlbumType() == PhotoAlbumType::USER) {
1412 err = MediaLibraryNapiUtils::GetUserAlbumPredicates(album->GetAlbumId(), predicates, false);
1413 } else {
1414 err = MediaLibraryNapiUtils::GetSystemAlbumPredicates(album->GetAlbumSubType(), predicates, false);
1415 }
1416 if (err < 0) {
1417 NAPI_WARN_LOG("Failed to set count for album subtype: %{public}d", album->GetAlbumSubType());
1418 album->SetCount(0);
1419 return;
1420 }
1421
1422 Uri uri(URI_QUERY_PHOTO_MAP);
1423 vector<string> columns;
1424 auto resultSet = UserFileClient::Query(uri, predicates, columns, err);
1425 if (resultSet == nullptr) {
1426 NAPI_WARN_LOG("Query for assets failed! errorCode is = %{public}d", err);
1427 album->SetCount(0);
1428 return;
1429 }
1430 auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1431 int32_t count = fetchResult->GetCount();
1432 album->SetCount(count);
1433 }
1434 #else
SetAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<AlbumAsset> & album)1435 static void SetAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<AlbumAsset> &album)
1436 {
1437 MediaLibraryTracer tracer;
1438 tracer.Start("SetAlbumCoverUri");
1439 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1440 DataShare::DataSharePredicates predicates;
1441 predicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
1442 predicates.SetWhereArgs({ to_string(album->GetAlbumId()) });
1443 predicates.SetOrder(MEDIA_DATA_DB_DATE_ADDED + " DESC LIMIT 0,1 ");
1444 vector<string> columns;
1445 string queryUri = MEDIALIBRARY_DATA_URI;
1446 if (!context->networkId.empty()) {
1447 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER;
1448 NAPI_DEBUG_LOG("querycoverUri is = %{private}s", queryUri.c_str());
1449 }
1450 Uri uri(queryUri);
1451 int errCode = 0;
1452 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(
1453 uri, predicates, columns, errCode);
1454 if (resultSet == nullptr) {
1455 NAPI_ERR_LOG("Query for Album uri failed! errorCode is = %{public}d", errCode);
1456 return;
1457 }
1458 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1459 fetchFileResult->SetNetworkId(context->networkId);
1460 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
1461 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetAlbumCoverUr:FileAsset is nullptr");
1462 string coverUri = fileAsset->GetUri();
1463 album->SetCoverUri(coverUri);
1464 NAPI_DEBUG_LOG("coverUri is = %{private}s", album->GetCoverUri().c_str());
1465 }
1466 #endif
1467
SetAlbumData(AlbumAsset * albumData,shared_ptr<DataShare::DataShareResultSet> resultSet,const string & networkId)1468 void SetAlbumData(AlbumAsset* albumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
1469 const string &networkId)
1470 {
1471 #ifdef MEDIALIBRARY_COMPATIBILITY
1472 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
1473 TYPE_INT32)));
1474 albumData->SetAlbumType(static_cast<PhotoAlbumType>(
1475 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
1476 albumData->SetAlbumSubType(static_cast<PhotoAlbumSubType>(
1477 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
1478 SetCompatAlbumName(albumData);
1479 #else
1480 // Get album id index and value
1481 albumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_BUCKET_ID, resultSet,
1482 TYPE_INT32)));
1483
1484 // Get album title index and value
1485 albumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_TITLE, resultSet,
1486 TYPE_STRING)));
1487 #endif
1488
1489 // Get album asset count index and value
1490 albumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_COUNT, resultSet, TYPE_INT32)));
1491 MediaFileUri fileUri(MEDIA_TYPE_ALBUM, to_string(albumData->GetAlbumId()), networkId,
1492 MEDIA_API_VERSION_DEFAULT);
1493 albumData->SetAlbumUri(fileUri.ToString());
1494 // Get album relativePath index and value
1495 albumData->SetAlbumRelativePath(get<string>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_RELATIVE_PATH,
1496 resultSet, TYPE_STRING)));
1497 albumData->SetAlbumDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_DATE_MODIFIED,
1498 resultSet, TYPE_INT64)));
1499 }
1500
GetAlbumResult(MediaLibraryAsyncContext * context,shared_ptr<DataShareResultSet> resultSet)1501 static void GetAlbumResult(MediaLibraryAsyncContext *context, shared_ptr<DataShareResultSet> resultSet)
1502 {
1503 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1504 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1505 context->fetchAlbumResult = make_unique<FetchResult<AlbumAsset>>(move(resultSet));
1506 context->fetchAlbumResult->SetNetworkId(context->networkId);
1507 context->fetchAlbumResult->SetResultNapiType(context->resultNapiType);
1508 return;
1509 }
1510
1511 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1512 unique_ptr<AlbumAsset> albumData = make_unique<AlbumAsset>();
1513 if (albumData != nullptr) {
1514 SetAlbumData(albumData.get(), resultSet, context->networkId);
1515 #ifdef MEDIALIBRARY_COMPATIBILITY
1516 CompatSetAlbumCoverUri(context, albumData);
1517 CompatSetAlbumCount(albumData);
1518 #else
1519 SetAlbumCoverUri(context, albumData);
1520 #endif
1521 context->albumNativeArray.push_back(move(albumData));
1522 } else {
1523 context->SaveError(E_NO_MEMORY);
1524 }
1525 }
1526 }
1527
1528 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceAlbumName(const string & arg,string & argInstead)1529 static void ReplaceAlbumName(const string &arg, string &argInstead)
1530 {
1531 if (arg == CAMERA_ALBUM_NAME) {
1532 argInstead = to_string(PhotoAlbumSubType::CAMERA);
1533 } else if (arg == SCREEN_SHOT_ALBUM_NAME) {
1534 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1535 } else if (arg == SCREEN_RECORD_ALBUM_NAME) {
1536 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1537 } else {
1538 argInstead = arg;
1539 }
1540 }
1541
DoReplaceRelativePath(const string & arg,string & argInstead)1542 static bool DoReplaceRelativePath(const string &arg, string &argInstead)
1543 {
1544 if (arg == CAMERA_PATH) {
1545 argInstead = to_string(PhotoAlbumSubType::CAMERA);
1546 } else if (arg == SCREEN_SHOT_PATH) {
1547 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1548 } else if (arg == SCREEN_RECORD_PATH) {
1549 argInstead = to_string(PhotoAlbumSubType::SCREENSHOT);
1550 } else if (arg.empty()) {
1551 argInstead = arg;
1552 return false;
1553 } else {
1554 argInstead = arg;
1555 }
1556 return true;
1557 }
1558
ReplaceRelativePath(string & selection,size_t pos,const string & keyInstead,const string & arg,string & argInstead)1559 static inline void ReplaceRelativePath(string &selection, size_t pos, const string &keyInstead, const string &arg,
1560 string &argInstead)
1561 {
1562 bool shouldReplace = DoReplaceRelativePath(arg, argInstead);
1563 if (shouldReplace) {
1564 selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), keyInstead);
1565 }
1566 }
1567
ReplaceSelection(string & selection,vector<string> & selectionArgs,const string & key,const string & keyInstead,const int32_t mode)1568 void MediaLibraryNapi::ReplaceSelection(string &selection, vector<string> &selectionArgs,
1569 const string &key, const string &keyInstead, const int32_t mode)
1570 {
1571 for (size_t pos = 0; pos != string::npos;) {
1572 pos = selection.find(key, pos);
1573 if (pos == string::npos) {
1574 break;
1575 }
1576
1577 size_t argPos = selection.find('?', pos);
1578 if (argPos == string::npos) {
1579 break;
1580 }
1581 size_t argIndex = 0;
1582 for (size_t i = 0; i < argPos; i++) {
1583 if (selection[i] == '?') {
1584 argIndex++;
1585 }
1586 }
1587 if (argIndex > selectionArgs.size() - 1) {
1588 NAPI_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
1589 selection.c_str());
1590 break;
1591 }
1592 const string &arg = selectionArgs[argIndex];
1593 string argInstead = arg;
1594 if (key == MEDIA_DATA_DB_RELATIVE_PATH) {
1595 if (mode == ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH) {
1596 argInstead = MediaFileUtils::AddDocsToRelativePath(arg);
1597 } else {
1598 ReplaceRelativePath(selection, pos, keyInstead, arg, argInstead);
1599 }
1600 } else if (key == MEDIA_DATA_DB_BUCKET_NAME) {
1601 ReplaceAlbumName(arg, argInstead);
1602 selection.replace(pos, key.length(), keyInstead);
1603 } else if (key == MEDIA_DATA_DB_BUCKET_ID) {
1604 selection.replace(pos, key.length(), keyInstead);
1605 }
1606 selectionArgs[argIndex] = argInstead;
1607 argPos = selection.find('?', pos);
1608 if (argPos == string::npos) {
1609 break;
1610 }
1611 pos = argPos + 1;
1612 }
1613 }
1614
UpdateCompatSelection(MediaLibraryAsyncContext * context)1615 static void UpdateCompatSelection(MediaLibraryAsyncContext *context)
1616 {
1617 MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1618 MEDIA_DATA_DB_BUCKET_ID, PhotoAlbumColumns::ALBUM_ID);
1619 MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1620 MEDIA_DATA_DB_BUCKET_NAME, PhotoAlbumColumns::ALBUM_SUBTYPE);
1621 MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1622 MEDIA_DATA_DB_RELATIVE_PATH, PhotoAlbumColumns::ALBUM_SUBTYPE);
1623 static const string COMPAT_QUERY_FILTER = PhotoAlbumColumns::ALBUM_SUBTYPE + " IN (" +
1624 to_string(PhotoAlbumSubType::SCREENSHOT) + "," +
1625 to_string(PhotoAlbumSubType::CAMERA) + ")";
1626 if (!context->selection.empty()) {
1627 context->selection = COMPAT_QUERY_FILTER + " AND " + context->selection;
1628 } else {
1629 context->selection = COMPAT_QUERY_FILTER;
1630 }
1631 }
1632 #endif
1633
GetResultDataExecute(napi_env env,void * data)1634 static void GetResultDataExecute(napi_env env, void *data)
1635 {
1636 MediaLibraryTracer tracer;
1637 tracer.Start("GetResultDataExecute");
1638
1639 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1640
1641 #ifdef MEDIALIBRARY_COMPATIBILITY
1642 UpdateCompatSelection(context);
1643 #else
1644 MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
1645 #endif
1646 context->predicates.SetWhereClause(context->selection);
1647 context->predicates.SetWhereArgs(context->selectionArgs);
1648 if (!context->order.empty()) {
1649 context->predicates.SetOrder(context->order);
1650 }
1651
1652 #ifdef MEDIALIBRARY_COMPATIBILITY
1653 vector<string> columns;
1654 const set<string> &defaultFetchCols = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
1655 columns.assign(defaultFetchCols.begin(), defaultFetchCols.end());
1656 columns.push_back(PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
1657 #else
1658 vector<string> columns;
1659 #endif
1660 string queryUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1661 if (!context->networkId.empty()) {
1662 queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId +
1663 MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM;
1664 NAPI_DEBUG_LOG("queryAlbumUri is = %{private}s", queryUri.c_str());
1665 }
1666 Uri uri(queryUri);
1667 int errCode = 0;
1668 shared_ptr<DataShareResultSet> resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode,
1669 context->userId);
1670
1671 if (resultSet == nullptr) {
1672 NAPI_ERR_LOG("GetMediaResultData resultSet is nullptr, errCode is %{public}d", errCode);
1673 context->SaveError(errCode);
1674 return;
1675 }
1676
1677 GetAlbumResult(context, resultSet);
1678 }
1679
MediaLibAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1680 static void MediaLibAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1681 unique_ptr<JSAsyncContextOutput> &jsContext)
1682 {
1683 if (context->albumNativeArray.empty()) {
1684 napi_value albumNoArray = nullptr;
1685 napi_create_array(env, &albumNoArray);
1686 jsContext->status = true;
1687 napi_get_undefined(env, &jsContext->error);
1688 jsContext->data = albumNoArray;
1689 } else {
1690 napi_value albumArray = nullptr;
1691 napi_create_array_with_length(env, context->albumNativeArray.size(), &albumArray);
1692 for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
1693 napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
1694 napi_set_element(env, albumArray, i, albumNapiObj);
1695 }
1696 jsContext->status = true;
1697 napi_get_undefined(env, &jsContext->error);
1698 jsContext->data = albumArray;
1699 }
1700 }
1701
UserFileMgrAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1702 static void UserFileMgrAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1703 unique_ptr<JSAsyncContextOutput> &jsContext)
1704 {
1705 if (context->fetchAlbumResult->GetCount() < 0) {
1706 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1707 "find no data by options");
1708 } else {
1709 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumResult));
1710 if (fileResult == nullptr) {
1711 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1712 "Failed to create js object for Fetch Album Result");
1713 } else {
1714 jsContext->data = fileResult;
1715 jsContext->status = true;
1716 napi_get_undefined(env, &jsContext->error);
1717 }
1718 }
1719 }
1720
AlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1721 static void AlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
1722 unique_ptr<JSAsyncContextOutput> &jsContext)
1723 {
1724 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1725 MediaLibAlbumsAsyncResult(env, context, jsContext);
1726 } else {
1727 UserFileMgrAlbumsAsyncResult(env, context, jsContext);
1728 }
1729 }
1730
AlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)1731 static void AlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
1732 {
1733 MediaLibraryTracer tracer;
1734 tracer.Start("AlbumsAsyncCallbackComplete");
1735
1736 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
1737 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1738 jsContext->status = false;
1739 napi_get_undefined(env, &jsContext->error);
1740 if (context->error != ERR_DEFAULT) {
1741 napi_get_undefined(env, &jsContext->data);
1742 context->HandleError(env, jsContext->error);
1743 } else {
1744 AlbumsAsyncResult(env, context, jsContext);
1745 }
1746
1747 tracer.Finish();
1748 if (context->work != nullptr) {
1749 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1750 context->work, *jsContext);
1751 }
1752 delete context;
1753 }
1754
JSGetAlbums(napi_env env,napi_callback_info info)1755 napi_value MediaLibraryNapi::JSGetAlbums(napi_env env, napi_callback_info info)
1756 {
1757 napi_status status;
1758 napi_value result = nullptr;
1759 size_t argc = ARGS_TWO;
1760 napi_value argv[ARGS_TWO] = {0};
1761 napi_value thisVar = nullptr;
1762
1763 MediaLibraryTracer tracer;
1764 tracer.Start("JSGetAlbums");
1765
1766 GET_JS_ARGS(env, info, argc, argv, thisVar);
1767 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1768 napi_get_undefined(env, &result);
1769
1770 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
1771 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1772 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1773 result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1774 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1775
1776 SetUserIdFromObjectInfo(asyncContext);
1777 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAlbums", GetResultDataExecute,
1778 AlbumsAsyncCallbackComplete);
1779 }
1780
1781 return result;
1782 }
1783
1784 #ifndef MEDIALIBRARY_COMPATIBILITY
getFileAssetById(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1785 static void getFileAssetById(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1786 {
1787 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1788 vector<string> columns;
1789 DataShare::DataSharePredicates predicates;
1790
1791 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1792 predicates.SetWhereArgs({ to_string(id) });
1793
1794 string queryUri = MEDIALIBRARY_DATA_URI;
1795 Uri uri(queryUri);
1796 int errCode = 0;
1797 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
1798 CHECK_NULL_PTR_RETURN_VOID(resultSet, "Failed to get file asset by id, query resultSet is nullptr");
1799
1800 // Create FetchResult object using the contents of resultSet
1801 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1802 CHECK_NULL_PTR_RETURN_VOID(context->fetchFileResult, "Failed to get file asset by id, fetchFileResult is nullptr");
1803 context->fetchFileResult->SetNetworkId(networkId);
1804 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1805 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1806 context->fetchFileResult->SetResultNapiType(context->resultNapiType);
1807 }
1808 if (context->fetchFileResult->GetCount() < 1) {
1809 NAPI_ERR_LOG("Failed to query file by id: %{public}d, query count is 0", id);
1810 return;
1811 }
1812 unique_ptr<FileAsset> fileAsset = context->fetchFileResult->GetFirstObject();
1813 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "getFileAssetById: fileAsset is nullptr");
1814 context->fileAsset = move(fileAsset);
1815 }
1816 #endif
1817
1818 #ifdef MEDIALIBRARY_COMPATIBILITY
SetFileAssetByIdV9(int32_t id,const string & networkId,MediaLibraryAsyncContext * context)1819 static void SetFileAssetByIdV9(int32_t id, const string &networkId, MediaLibraryAsyncContext *context)
1820 {
1821 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1822 bool isValid = false;
1823 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1824 if (!isValid) {
1825 NAPI_ERR_LOG("get title is invalid");
1826 return;
1827 }
1828 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
1829 if (!isValid) {
1830 NAPI_ERR_LOG("get relativePath is invalid");
1831 return;
1832 }
1833 unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1834 fileAsset->SetId(id);
1835 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1836 string uri;
1837 if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
1838 MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1839 uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(MediaType::MEDIA_TYPE_FILE,
1840 to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1841 relativePath = MediaFileUtils::RemoveDocsFromRelativePath(relativePath);
1842 } else {
1843 uri = MediaFileUtils::GetVirtualUriFromRealUri(MediaFileUri(mediaType,
1844 to_string(id), networkId, MEDIA_API_VERSION_V9).ToString());
1845 }
1846 fileAsset->SetUri(uri);
1847 fileAsset->SetMediaType(mediaType);
1848 fileAsset->SetDisplayName(displayName);
1849 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1850 fileAsset->SetResultNapiType(ResultNapiType::TYPE_MEDIALIBRARY);
1851 fileAsset->SetRelativePath(relativePath);
1852 context->fileAsset = move(fileAsset);
1853 }
1854 #endif
1855
SetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1856 static void SetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1857 MediaLibraryAsyncContext *context)
1858 {
1859 bool isValid = false;
1860 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1861 if (!isValid) {
1862 NAPI_ERR_LOG("getting title is invalid");
1863 return;
1864 }
1865 unique_ptr<FileAsset> fileAsset = make_unique<FileAsset>();
1866 fileAsset->SetId(id);
1867 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1868 fileAsset->SetUri(uri);
1869 fileAsset->SetMediaType(mediaType);
1870 fileAsset->SetDisplayName(displayName);
1871 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1872 fileAsset->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1873 fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1874 fileAsset->SetUserId(context->userId);
1875 context->fileAsset = move(fileAsset);
1876 }
1877
PhotoAccessSetFileAssetByIdV10(int32_t id,const string & networkId,const string & uri,MediaLibraryAsyncContext * context)1878 static void PhotoAccessSetFileAssetByIdV10(int32_t id, const string &networkId, const string &uri,
1879 MediaLibraryAsyncContext *context)
1880 {
1881 bool isValid = false;
1882 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
1883 if (!isValid) {
1884 NAPI_ERR_LOG("getting title is invalid");
1885 return;
1886 }
1887 auto fileAsset = make_unique<FileAsset>();
1888 fileAsset->SetId(id);
1889 MediaType mediaType = MediaFileUtils::GetMediaType(displayName);
1890 fileAsset->SetUri(uri);
1891 fileAsset->SetMediaType(mediaType);
1892 fileAsset->SetDisplayName(displayName);
1893 fileAsset->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
1894 fileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1895 fileAsset->SetTimePending(UNCREATE_FILE_TIMEPENDING);
1896 fileAsset->SetUserId(context->userId);
1897 context->fileAsset = move(fileAsset);
1898 }
1899
JSCreateUriArrayInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1900 static void JSCreateUriArrayInCallback(napi_env env, MediaLibraryAsyncContext *context,
1901 unique_ptr<JSAsyncContextOutput> &jsContext)
1902 {
1903 napi_value jsObject = nullptr;
1904 if (context->uriArray.empty()) {
1905 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1906 "Obtain file asset uri array failed");
1907 napi_get_undefined(env, &jsContext->data);
1908 } else {
1909 napi_status status = napi_create_array(env, &jsObject);
1910 int count = 0;
1911 for (const auto &uri : context->uriArray) {
1912 napi_value uriObject = nullptr;
1913 status = napi_create_string_utf8(env, uri.c_str(), NAPI_AUTO_LENGTH, &uriObject);
1914 if (status != napi_ok || uriObject == nullptr) {
1915 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1916 napi_get_undefined(env, &jsContext->data);
1917 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1918 "System inner fail");
1919 return;
1920 }
1921
1922 status = napi_set_element(env, jsObject, count, uriObject);
1923 if (status != napi_ok) {
1924 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1925 napi_get_undefined(env, &jsContext->data);
1926 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1927 "System inner fail");
1928 return;
1929 }
1930 ++count;
1931 }
1932
1933 if (status != napi_ok || jsObject == nullptr) {
1934 NAPI_ERR_LOG("Failed to get file asset uri array napi object");
1935 napi_get_undefined(env, &jsContext->data);
1936 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1937 "System inner fail");
1938 } else {
1939 jsContext->data = jsObject;
1940 napi_get_undefined(env, &jsContext->error);
1941 jsContext->status = true;
1942 }
1943 }
1944 }
1945
JSCreateUriInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1946 static void JSCreateUriInCallback(napi_env env, MediaLibraryAsyncContext *context,
1947 unique_ptr<JSAsyncContextOutput> &jsContext)
1948 {
1949 napi_value jsObject = nullptr;
1950 if (context->uri.empty()) {
1951 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1952 "Obtain file asset uri failed");
1953 napi_get_undefined(env, &jsContext->data);
1954 } else {
1955 napi_status status = napi_create_string_utf8(env, context->uri.c_str(), NAPI_AUTO_LENGTH, &jsObject);
1956 if (status != napi_ok || jsObject == nullptr) {
1957 NAPI_ERR_LOG("Failed to get file asset uri napi object");
1958 napi_get_undefined(env, &jsContext->data);
1959 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1960 "System inner fail");
1961 } else {
1962 jsContext->data = jsObject;
1963 napi_get_undefined(env, &jsContext->error);
1964 jsContext->status = true;
1965 }
1966 }
1967 }
1968
JSCreateAssetInCallback(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1969 static void JSCreateAssetInCallback(napi_env env, MediaLibraryAsyncContext *context,
1970 unique_ptr<JSAsyncContextOutput> &jsContext)
1971 {
1972 napi_value jsFileAsset = nullptr;
1973 if (context->fileAsset == nullptr) {
1974 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1975 "Obtain file asset failed");
1976 napi_get_undefined(env, &jsContext->data);
1977 } else {
1978 context->fileAsset->SetUserId(context->userId);
1979 jsFileAsset = FileAssetNapi::CreateFileAsset(env, context->fileAsset);
1980 if (jsFileAsset == nullptr) {
1981 NAPI_ERR_LOG("Failed to get file asset napi object");
1982 napi_get_undefined(env, &jsContext->data);
1983 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
1984 "System inner fail");
1985 } else {
1986 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
1987 jsContext->data = jsFileAsset;
1988 napi_get_undefined(env, &jsContext->error);
1989 jsContext->status = true;
1990 }
1991 }
1992 }
1993
JSCreateAssetCompleteCallback(napi_env env,napi_status status,void * data)1994 static void JSCreateAssetCompleteCallback(napi_env env, napi_status status, void *data)
1995 {
1996 MediaLibraryTracer tracer;
1997 tracer.Start("JSCreateAssetCompleteCallback");
1998
1999 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2000 auto jsContext = make_unique<JSAsyncContextOutput>();
2001 jsContext->status = false;
2002
2003 if (context->error == ERR_DEFAULT) {
2004 if (context->isCreateByAgent) {
2005 JSCreateUriArrayInCallback(env, context, jsContext);
2006 } else if (context->isCreateByComponent) {
2007 JSCreateUriInCallback(env, context, jsContext);
2008 } else {
2009 JSCreateAssetInCallback(env, context, jsContext);
2010 }
2011 } else {
2012 context->HandleError(env, jsContext->error);
2013 napi_get_undefined(env, &jsContext->data);
2014 }
2015
2016 tracer.Finish();
2017 if (context->work != nullptr) {
2018 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2019 context->work, *jsContext);
2020 }
2021
2022 NAPI_INFO_LOG("End create asset.");
2023 delete context;
2024 }
2025
JSPhotoUriPermissionCallback(napi_env env,napi_status status,void * data)2026 static void JSPhotoUriPermissionCallback(napi_env env, napi_status status, void *data)
2027 {
2028 MediaLibraryTracer tracer;
2029 tracer.Start("JSPhotoUriPermissionCallback");
2030
2031 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2032 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2033
2034 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2035 jsContext->status = false;
2036
2037 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2038 if (context->error != ERR_DEFAULT) {
2039 context->HandleError(env, jsContext->error);
2040 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
2041 } else {
2042 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
2043 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2044 jsContext->status = true;
2045 }
2046
2047 tracer.Finish();
2048 if (context->work != nullptr) {
2049 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2050 context->work, *jsContext);
2051 }
2052 delete context;
2053 }
2054
CheckDisplayNameParams(MediaLibraryAsyncContext * context)2055 static bool CheckDisplayNameParams(MediaLibraryAsyncContext *context)
2056 {
2057 if (context == nullptr) {
2058 NAPI_ERR_LOG("Async context is null");
2059 return false;
2060 }
2061 if (!context->isCreateByComponent) {
2062 bool isValid = false;
2063 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
2064 if (!isValid) {
2065 NAPI_ERR_LOG("getting displayName is invalid");
2066 return false;
2067 }
2068 if (displayName.empty()) {
2069 return false;
2070 }
2071 }
2072
2073 return true;
2074 }
2075
GetFirstDirName(const string & relativePath)2076 static string GetFirstDirName(const string &relativePath)
2077 {
2078 string firstDirName = "";
2079 if (!relativePath.empty()) {
2080 string::size_type pos = relativePath.find_first_of('/');
2081 if (pos == relativePath.length()) {
2082 return relativePath;
2083 }
2084 firstDirName = relativePath.substr(0, pos + 1);
2085 NAPI_DEBUG_LOG("firstDirName substr = %{private}s", firstDirName.c_str());
2086 }
2087 return firstDirName;
2088 }
2089
IsDirectory(const string & dirName)2090 static bool IsDirectory(const string &dirName)
2091 {
2092 struct stat statInfo {};
2093 if (stat((ROOT_MEDIA_DIR + dirName).c_str(), &statInfo) == E_SUCCESS) {
2094 if (statInfo.st_mode & S_IFDIR) {
2095 return true;
2096 }
2097 }
2098
2099 return false;
2100 }
2101
CheckTypeOfType(const string & firstDirName,int32_t fileMediaType)2102 static bool CheckTypeOfType(const string &firstDirName, int32_t fileMediaType)
2103 {
2104 // "CDSA/"
2105 if (!strcmp(firstDirName.c_str(), directoryEnumValues[0].c_str())) {
2106 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
2107 return true;
2108 } else {
2109 return false;
2110 }
2111 }
2112 // "Movies/"
2113 if (!strcmp(firstDirName.c_str(), directoryEnumValues[1].c_str())) {
2114 if (fileMediaType == MEDIA_TYPE_VIDEO) {
2115 return true;
2116 } else {
2117 return false;
2118 }
2119 }
2120 if (!strcmp(firstDirName.c_str(), directoryEnumValues[SECOND_ENUM].c_str())) {
2121 if (fileMediaType == MEDIA_TYPE_IMAGE || fileMediaType == MEDIA_TYPE_VIDEO) {
2122 return true;
2123 } else {
2124 NAPI_INFO_LOG("CheckTypeOfType RETURN FALSE");
2125 return false;
2126 }
2127 }
2128 if (!strcmp(firstDirName.c_str(), directoryEnumValues[THIRD_ENUM].c_str())) {
2129 if (fileMediaType == MEDIA_TYPE_AUDIO) {
2130 return true;
2131 } else {
2132 return false;
2133 }
2134 }
2135 return true;
2136 }
CheckRelativePathParams(MediaLibraryAsyncContext * context)2137 static bool CheckRelativePathParams(MediaLibraryAsyncContext *context)
2138 {
2139 if (context == nullptr) {
2140 NAPI_ERR_LOG("Async context is null");
2141 return false;
2142 }
2143 bool isValid = false;
2144 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2145 if (!isValid) {
2146 NAPI_DEBUG_LOG("getting relativePath is invalid");
2147 return false;
2148 }
2149 isValid = false;
2150 int32_t fileMediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
2151 if (!isValid) {
2152 NAPI_DEBUG_LOG("getting fileMediaType is invalid");
2153 return false;
2154 }
2155 if (relativePath.empty()) {
2156 return false;
2157 }
2158
2159 if (IsDirectory(relativePath)) {
2160 return true;
2161 }
2162
2163 string firstDirName = GetFirstDirName(relativePath);
2164 if (!firstDirName.empty() && IsDirectory(firstDirName)) {
2165 return true;
2166 }
2167
2168 if (!firstDirName.empty()) {
2169 NAPI_DEBUG_LOG("firstDirName = %{private}s", firstDirName.c_str());
2170 for (unsigned int i = 0; i < directoryEnumValues.size(); i++) {
2171 NAPI_DEBUG_LOG("directoryEnumValues%{private}d = %{private}s", i, directoryEnumValues[i].c_str());
2172 if (!strcmp(firstDirName.c_str(), directoryEnumValues[i].c_str())) {
2173 return CheckTypeOfType(firstDirName, fileMediaType);
2174 }
2175 if (!strcmp(firstDirName.c_str(), DOCS_PATH.c_str())) {
2176 return true;
2177 }
2178 }
2179 NAPI_ERR_LOG("Failed to check relative path, firstDirName = %{private}s", firstDirName.c_str());
2180 }
2181 return false;
2182 }
2183
GetJSArgsForCreateAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2184 napi_value GetJSArgsForCreateAsset(napi_env env, size_t argc, const napi_value argv[],
2185 MediaLibraryAsyncContext &asyncContext)
2186 {
2187 const int32_t refCount = 1;
2188 napi_value result = nullptr;
2189 auto context = &asyncContext;
2190 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2191 int32_t fileMediaType = 0;
2192 size_t res = 0;
2193 char relativePathBuffer[PATH_MAX];
2194 char titleBuffer[PATH_MAX];
2195 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2196
2197 for (size_t i = PARAM0; i < argc; i++) {
2198 napi_valuetype valueType = napi_undefined;
2199 napi_typeof(env, argv[i], &valueType);
2200 if (i == PARAM0 && valueType == napi_number) {
2201 napi_get_value_int32(env, argv[i], &fileMediaType);
2202 } else if (i == PARAM1 && valueType == napi_string) {
2203 napi_get_value_string_utf8(env, argv[i], titleBuffer, PATH_MAX, &res);
2204 NAPI_DEBUG_LOG("displayName = %{private}s", string(titleBuffer).c_str());
2205 } else if (i == PARAM2 && valueType == napi_string) {
2206 napi_get_value_string_utf8(env, argv[i], relativePathBuffer, PATH_MAX, &res);
2207 NAPI_DEBUG_LOG("relativePath = %{private}s", string(relativePathBuffer).c_str());
2208 } else if (i == PARAM3 && valueType == napi_function) {
2209 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2210 } else {
2211 NAPI_DEBUG_LOG("type mismatch, valueType: %{public}d", valueType);
2212 return result;
2213 }
2214 }
2215
2216 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileMediaType);
2217 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, string(titleBuffer));
2218 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, string(relativePathBuffer));
2219
2220 context->assetType = TYPE_DEFAULT;
2221 if (fileMediaType == MediaType::MEDIA_TYPE_IMAGE || fileMediaType == MediaType::MEDIA_TYPE_VIDEO) {
2222 context->assetType = TYPE_PHOTO;
2223 } else if (fileMediaType == MediaType::MEDIA_TYPE_AUDIO) {
2224 context->assetType = TYPE_AUDIO;
2225 }
2226
2227 NAPI_DEBUG_LOG("GetJSArgsForCreateAsset END");
2228 // Return true napi_value if params are successfully obtained
2229 napi_get_boolean(env, true, &result);
2230 return result;
2231 }
2232
GetCreateUri(MediaLibraryAsyncContext * context,string & uri)2233 static void GetCreateUri(MediaLibraryAsyncContext *context, string &uri)
2234 {
2235 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
2236 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
2237 switch (context->assetType) {
2238 case TYPE_PHOTO:
2239 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2240 uri = (context->isCreateByComponent) ? UFM_CREATE_PHOTO_COMPONENT : UFM_CREATE_PHOTO;
2241 } else {
2242 uri = (context->isCreateByComponent) ? PAH_CREATE_PHOTO_COMPONENT :
2243 (context->needSystemApp ? PAH_SYS_CREATE_PHOTO : PAH_CREATE_PHOTO);
2244 }
2245 break;
2246 case TYPE_AUDIO:
2247 uri = (context->isCreateByComponent) ? UFM_CREATE_AUDIO_COMPONENT : UFM_CREATE_AUDIO;
2248 break;
2249 default:
2250 NAPI_ERR_LOG("Unsupported creation napitype %{public}d", static_cast<int32_t>(context->assetType));
2251 return;
2252 }
2253 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2254 } else {
2255 #ifdef MEDIALIBRARY_COMPATIBILITY
2256 bool isValid = false;
2257 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2258 if (MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOC_DIR_VALUES) ||
2259 MediaFileUtils::StartsWith(relativePath, DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
2260 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2261 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
2262 return;
2263 }
2264 switch (context->assetType) {
2265 case TYPE_PHOTO:
2266 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_PHOTOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2267 break;
2268 case TYPE_AUDIO:
2269 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2270 break;
2271 case TYPE_DEFAULT:
2272 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2273 break;
2274 default:
2275 NAPI_ERR_LOG("Unsupported creation napi type %{public}d", static_cast<int32_t>(context->assetType));
2276 return;
2277 }
2278 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V9));
2279 #else
2280 uri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CREATEASSET;
2281 #endif
2282 }
2283 }
2284
JSCreateAssetExecute(napi_env env,void * data)2285 static void JSCreateAssetExecute(napi_env env, void *data)
2286 {
2287 MediaLibraryTracer tracer;
2288 tracer.Start("JSCreateAssetExecute");
2289 NAPI_INFO_LOG("JSCreateAssetExecute start");
2290
2291 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2292 if (!CheckDisplayNameParams(context)) {
2293 context->error = JS_E_DISPLAYNAME;
2294 return;
2295 }
2296 if ((context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) && (!CheckRelativePathParams(context))) {
2297 context->error = JS_E_RELATIVEPATH;
2298 return;
2299 }
2300 bool isValid = false;
2301 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
2302 if (isValid) {
2303 if (MediaFileUtils::StartsWith(relativePath, DOC_DIR_VALUES) ||
2304 MediaFileUtils::StartsWith(relativePath, DOWNLOAD_DIR_VALUES)) {
2305 context->valuesBucket.valuesMap.erase(MEDIA_DATA_DB_RELATIVE_PATH);
2306 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, DOCS_PATH + relativePath);
2307 }
2308 }
2309
2310 string uri;
2311 GetCreateUri(context, uri);
2312 Uri createFileUri(uri);
2313 string outUri;
2314 int index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri,
2315 context->userId);
2316 if (index < 0) {
2317 context->SaveError(index);
2318 } else {
2319 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2320 if (context->isCreateByComponent) {
2321 context->uri = outUri;
2322 } else {
2323 SetFileAssetByIdV10(index, "", outUri, context);
2324 }
2325 } else {
2326 #ifdef MEDIALIBRARY_COMPATIBILITY
2327 SetFileAssetByIdV9(index, "", context);
2328 #else
2329 getFileAssetById(index, "", context);
2330 #endif
2331 LogMedialibraryAPI(context->fileAsset->GetUri());
2332 }
2333 }
2334 }
2335
JSCreateAsset(napi_env env,napi_callback_info info)2336 napi_value MediaLibraryNapi::JSCreateAsset(napi_env env, napi_callback_info info)
2337 {
2338 napi_status status;
2339 napi_value result = nullptr;
2340 size_t argc = ARGS_FOUR;
2341 napi_value argv[ARGS_FOUR] = {0};
2342 napi_value thisVar = nullptr;
2343
2344 MediaLibraryTracer tracer;
2345 tracer.Start("JSCreateAsset");
2346
2347 GET_JS_ARGS(env, info, argc, argv, thisVar);
2348 NAPI_ASSERT(env, (argc == ARGS_THREE || argc == ARGS_FOUR), "requires 4 parameters maximum");
2349 napi_get_undefined(env, &result);
2350
2351 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2352 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2353 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2354 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2355 result = GetJSArgsForCreateAsset(env, argc, argv, *asyncContext);
2356 ASSERT_NULLPTR_CHECK(env, result);
2357
2358 SetUserIdFromObjectInfo(asyncContext);
2359 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCreateAsset", JSCreateAssetExecute,
2360 JSCreateAssetCompleteCallback);
2361 }
2362
2363 return result;
2364 }
2365
2366 #ifdef MEDIALIBRARY_COMPATIBILITY
HandleCompatTrashAudio(MediaLibraryAsyncContext * context,const string & deleteId)2367 static void HandleCompatTrashAudio(MediaLibraryAsyncContext *context, const string &deleteId)
2368 {
2369 DataShareValuesBucket valuesBucket;
2370 valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
2371 DataSharePredicates predicates;
2372 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2373 predicates.SetWhereArgs({ deleteId });
2374 Uri uri(URI_DELETE_AUDIO);
2375 int32_t changedRows = UserFileClient::Delete(uri, predicates);
2376 if (changedRows < 0) {
2377 context->SaveError(changedRows);
2378 return;
2379 }
2380 context->retVal = changedRows;
2381 }
2382
HandleCompatDeletePhoto(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2383 static void HandleCompatDeletePhoto(MediaLibraryAsyncContext *context,
2384 const string &mediaType, const string &deleteId)
2385 {
2386 Uri uri(URI_COMPAT_DELETE_PHOTOS);
2387 DataSharePredicates predicates;
2388 predicates.In(MediaColumn::MEDIA_ID, vector<string>({ deleteId }));
2389 DataShareValuesBucket valuesBucket;
2390 valuesBucket.Put(MediaColumn::MEDIA_ID, deleteId);
2391 int changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2392 if (changedRows < 0) {
2393 context->SaveError(changedRows);
2394 return;
2395 }
2396 context->retVal = changedRows;
2397 }
2398
HandleCompatDelete(MediaLibraryAsyncContext * context,const string & mediaType,const string & deleteId)2399 static inline void HandleCompatDelete(MediaLibraryAsyncContext *context,
2400 const string &mediaType, const string &deleteId)
2401 {
2402 if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE) {
2403 return HandleCompatDeletePhoto(context, mediaType, deleteId);
2404 }
2405 if (mediaType == AUDIO_ASSET_TYPE) {
2406 return HandleCompatTrashAudio(context, deleteId);
2407 }
2408
2409 NAPI_WARN_LOG("Ignore unsupported media type deletion: %{private}s", mediaType.c_str());
2410 }
2411 #endif
2412
JSDeleteAssetExecute(napi_env env,void * data)2413 static void JSDeleteAssetExecute(napi_env env, void *data)
2414 {
2415 MediaLibraryTracer tracer;
2416 tracer.Start("JSDeleteAssetExecute");
2417
2418 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2419 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2420
2421 string mediaType;
2422 string deleteId;
2423 bool isValid = false;
2424 string notifyUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2425 if (!isValid) {
2426 context->error = ERR_INVALID_OUTPUT;
2427 return;
2428 }
2429 #ifdef MEDIALIBRARY_COMPATIBILITY
2430 notifyUri = MediaFileUtils::GetRealUriFromVirtualUri(notifyUri);
2431 #endif
2432 size_t index = notifyUri.rfind('/');
2433 if (index != string::npos) {
2434 deleteId = notifyUri.substr(index + 1);
2435 notifyUri = notifyUri.substr(0, index);
2436 size_t indexType = notifyUri.rfind('/');
2437 if (indexType != string::npos) {
2438 mediaType = notifyUri.substr(indexType + 1);
2439 }
2440 }
2441 if (MediaFileUtils::IsUriV10(mediaType)) {
2442 NAPI_ERR_LOG("Unsupported media type: %{private}s", mediaType.c_str());
2443 context->SaveError(E_INVALID_URI);
2444 return;
2445 }
2446 #ifdef MEDIALIBRARY_COMPATIBILITY
2447 if (mediaType == IMAGE_ASSET_TYPE || mediaType == VIDEO_ASSET_TYPE || mediaType == AUDIO_ASSET_TYPE) {
2448 return HandleCompatDelete(context, mediaType, deleteId);
2449 }
2450 #endif
2451 notifyUri = MEDIALIBRARY_DATA_URI + "/" + mediaType;
2452 string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET;
2453 Uri deleteAssetUri(deleteUri);
2454 DataSharePredicates predicates;
2455 predicates.EqualTo(MEDIA_DATA_DB_ID, deleteId);
2456 int retVal = UserFileClient::Delete(deleteAssetUri, predicates);
2457 if (retVal < 0) {
2458 context->SaveError(retVal);
2459 } else {
2460 context->retVal = retVal;
2461 Uri deleteNotify(notifyUri);
2462 UserFileClient::NotifyChange(deleteNotify);
2463 }
2464 }
2465
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)2466 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
2467 {
2468 MediaLibraryTracer tracer;
2469 tracer.Start("JSDeleteAssetCompleteCallback");
2470
2471 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2472 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2473 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2474 jsContext->status = false;
2475
2476 if (context->error == ERR_DEFAULT) {
2477 NAPI_DEBUG_LOG("Delete result = %{public}d", context->retVal);
2478 napi_create_int32(env, context->retVal, &jsContext->data);
2479 napi_get_undefined(env, &jsContext->error);
2480 jsContext->status = true;
2481 } else {
2482 context->HandleError(env, jsContext->error);
2483 napi_get_undefined(env, &jsContext->data);
2484 }
2485
2486 tracer.Finish();
2487 if (context->work != nullptr) {
2488 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2489 context->work, *jsContext);
2490 }
2491
2492 delete context;
2493 }
2494
JSTrashAssetExecute(napi_env env,void * data)2495 static void JSTrashAssetExecute(napi_env env, void *data)
2496 {
2497 MediaLibraryTracer tracer;
2498 tracer.Start("JSTrashAssetExecute");
2499
2500 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
2501 string uri = context->uri;
2502 if (uri.empty()) {
2503 context->error = ERR_INVALID_OUTPUT;
2504 return;
2505 }
2506 MediaFileUri::RemoveAllFragment(uri);
2507 string trashId = MediaFileUtils::GetIdFromUri(uri);
2508 string trashUri;
2509 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) != string::npos) {
2510 trashUri = UFM_UPDATE_PHOTO;
2511 } else if (uri.find(AudioColumn::AUDIO_URI_PREFIX) != string::npos) {
2512 trashUri = UFM_UPDATE_AUDIO;
2513 } else {
2514 context->error = E_VIOLATION_PARAMETERS;
2515 return;
2516 }
2517 MediaLibraryNapiUtils::UriAppendKeyValue(trashUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2518 Uri updateAssetUri(trashUri);
2519 DataSharePredicates predicates;
2520 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2521 predicates.SetWhereArgs({ trashId });
2522 DataShareValuesBucket valuesBucket;
2523 valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, MediaFileUtils::UTCTimeMilliSeconds());
2524 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2525 if (changedRows < 0) {
2526 context->SaveError(changedRows);
2527 NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
2528 }
2529 }
2530
JSTrashAssetCompleteCallback(napi_env env,napi_status status,void * data)2531 static void JSTrashAssetCompleteCallback(napi_env env, napi_status status, void *data)
2532 {
2533 MediaLibraryTracer tracer;
2534 tracer.Start("JSTrashAssetCompleteCallback");
2535
2536 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
2537 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2538 jsContext->status = false;
2539 napi_get_undefined(env, &jsContext->data);
2540 if (context->error == ERR_DEFAULT) {
2541 jsContext->status = true;
2542 } else {
2543 context->HandleError(env, jsContext->error);
2544 }
2545 if (context->work != nullptr) {
2546 tracer.Finish();
2547 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2548 context->work, *jsContext);
2549 }
2550
2551 delete context;
2552 }
2553
GetJSArgsForDeleteAsset(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)2554 napi_value GetJSArgsForDeleteAsset(napi_env env, size_t argc, const napi_value argv[],
2555 MediaLibraryAsyncContext &asyncContext)
2556 {
2557 const int32_t refCount = 1;
2558 napi_value result = nullptr;
2559 auto context = &asyncContext;
2560 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2561 size_t res = 0;
2562 char buffer[PATH_MAX];
2563
2564 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2565
2566 for (size_t i = PARAM0; i < argc; i++) {
2567 napi_valuetype valueType = napi_undefined;
2568 napi_typeof(env, argv[i], &valueType);
2569
2570 if (i == PARAM0 && valueType == napi_string) {
2571 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
2572 } else if (i == PARAM1 && valueType == napi_function) {
2573 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2574 break;
2575 } else {
2576 NAPI_ASSERT(env, false, "type mismatch");
2577 }
2578 }
2579
2580 context->valuesBucket.Put(MEDIA_DATA_DB_URI, string(buffer));
2581
2582 // Return true napi_value if params are successfully obtained
2583 napi_get_boolean(env, true, &result);
2584 return result;
2585 }
2586
JSDeleteAsset(napi_env env,napi_callback_info info)2587 napi_value MediaLibraryNapi::JSDeleteAsset(napi_env env, napi_callback_info info)
2588 {
2589 napi_status status;
2590 napi_value result = nullptr;
2591 size_t argc = ARGS_TWO;
2592 napi_value argv[ARGS_TWO] = {0};
2593 napi_value thisVar = nullptr;
2594
2595 MediaLibraryTracer tracer;
2596 tracer.Start("JSDeleteAsset");
2597
2598 GET_JS_ARGS(env, info, argc, argv, thisVar);
2599 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2600 napi_get_undefined(env, &result);
2601
2602 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
2603 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2604 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2605 result = GetJSArgsForDeleteAsset(env, argc, argv, *asyncContext);
2606 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
2607
2608 SetUserIdFromObjectInfo(asyncContext);
2609 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeleteAsset", JSDeleteAssetExecute,
2610 JSDeleteAssetCompleteCallback);
2611 }
2612
2613 return result;
2614 }
2615
SetValueInt32(const napi_env & env,const char * fieldStr,const int intValue,napi_value & result)2616 static napi_status SetValueInt32(const napi_env& env, const char* fieldStr, const int intValue, napi_value& result)
2617 {
2618 napi_value value;
2619 napi_status status = napi_create_int32(env, intValue, &value);
2620 if (status != napi_ok) {
2621 NAPI_ERR_LOG("Set value create int32 error! field: %{public}s", fieldStr);
2622 return status;
2623 }
2624 status = napi_set_named_property(env, result, fieldStr, value);
2625 if (status != napi_ok) {
2626 NAPI_ERR_LOG("Set int32 named property error! field: %{public}s, status: %{public}d", fieldStr, status);
2627 }
2628 return status;
2629 }
2630
SetValueArray(const napi_env & env,const char * fieldStr,const std::list<Uri> listValue,napi_value & result)2631 static napi_status SetValueArray(const napi_env& env,
2632 const char* fieldStr, const std::list<Uri> listValue, napi_value& result)
2633 {
2634 napi_value value = nullptr;
2635 napi_status status = napi_create_array_with_length(env, listValue.size(), &value);
2636 if (status != napi_ok) {
2637 NAPI_ERR_LOG("Create array error! field: %{public}s", fieldStr);
2638 return status;
2639 }
2640 int elementIndex = 0;
2641 for (auto uri : listValue) {
2642 napi_value uriRet = nullptr;
2643 napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &uriRet);
2644 status = napi_set_element(env, value, elementIndex++, uriRet);
2645 if (status != napi_ok) {
2646 NAPI_ERR_LOG("Set lite item failed, error: %d", status);
2647 }
2648 }
2649 status = napi_set_named_property(env, result, fieldStr, value);
2650 if (status != napi_ok) {
2651 NAPI_ERR_LOG("Set array named property error! field: %{public}s", fieldStr);
2652 }
2653
2654 return status;
2655 }
2656
SetSharedAssetArray(const napi_env & env,const char * fieldStr,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,napi_value & result,bool isPhoto)2657 napi_status ChangeListenerNapi::SetSharedAssetArray(const napi_env& env, const char* fieldStr,
2658 ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper, napi_value& result, bool isPhoto)
2659 {
2660 MediaLibraryTracer tracer;
2661 tracer.Start("SolveOnChange BuildSharedPhotoAssetsObj");
2662 std::vector<std::string> assetIds;
2663 napi_status status = napi_ok;
2664 napi_value assetResults = ChangeListenerNapi::BuildSharedPhotoAssetsObj(env, wrapper, isPhoto);
2665 if (assetResults == nullptr) {
2666 NAPI_ERR_LOG("Failed to get assets Result from rdb");
2667 status = napi_invalid_arg;
2668 return status;
2669 }
2670 status = napi_set_named_property(env, result, fieldStr, assetResults);
2671 if (status != napi_ok) {
2672 NAPI_ERR_LOG("set array named property error: %{public}s", fieldStr);
2673 }
2674 return status;
2675 }
2676
SetSubUris(const napi_env & env,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,napi_value & result)2677 static napi_status SetSubUris(const napi_env& env, ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper,
2678 napi_value& result)
2679 {
2680 MediaLibraryTracer tracer;
2681 tracer.Start("SolveOnChange SetSubUris");
2682 uint32_t len = wrapper->extraUris_.size();
2683 napi_status status = napi_invalid_arg;
2684 napi_value subUriArray = nullptr;
2685 napi_create_array_with_length(env, len, &subUriArray);
2686 int subElementIndex = 0;
2687 for (auto iter = wrapper->extraUris_.begin(); iter != wrapper->extraUris_.end(); iter++) {
2688 string subUri = *iter;
2689 if (subUri.empty()) {
2690 NAPI_ERR_LOG("Failed to read sub uri");
2691 return status;
2692 }
2693 napi_value subUriRet = nullptr;
2694 napi_create_string_utf8(env, subUri.c_str(), NAPI_AUTO_LENGTH, &subUriRet);
2695 napi_set_element(env, subUriArray, subElementIndex++, subUriRet);
2696 }
2697 status = napi_set_named_property(env, result, "extraUris", subUriArray);
2698 if (status != napi_ok) {
2699 NAPI_ERR_LOG("Set subUri named property error!");
2700 }
2701 napi_value photoAssetArray = MediaLibraryNapiUtils::GetSharedPhotoAssets(env, wrapper->extraSharedAssets_, len);
2702 if (photoAssetArray == nullptr) {
2703 NAPI_ERR_LOG("Failed to get sharedPhotoAsset");
2704 }
2705 status = napi_set_named_property(env, result, "sharedExtraPhotoAssets", photoAssetArray);
2706 if (status != napi_ok) {
2707 NAPI_ERR_LOG("Set extraAssets named property error!");
2708 }
2709 return status;
2710 }
2711
GetTrashAlbumUri()2712 string ChangeListenerNapi::GetTrashAlbumUri()
2713 {
2714 MediaLibraryTracer tracer;
2715 tracer.Start("ChangeListenerNapi::GetTrashAlbumUri");
2716 if (!trashAlbumUri_.empty()) {
2717 return trashAlbumUri_;
2718 }
2719 string queryUri = UFM_QUERY_PHOTO_ALBUM;
2720 Uri uri(queryUri);
2721 int errCode = 0;
2722 DataSharePredicates predicates;
2723 predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::TRASH));
2724 vector<string> columns;
2725 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2726 unique_ptr<FetchResult<PhotoAlbum>> albumSet = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
2727 if (albumSet == nullptr) {
2728 return trashAlbumUri_;
2729 }
2730 if (albumSet->GetCount() != 1) {
2731 return trashAlbumUri_;
2732 }
2733 unique_ptr<PhotoAlbum> albumAssetPtr = albumSet->GetFirstObject();
2734 if (albumAssetPtr == nullptr) {
2735 return trashAlbumUri_;
2736 }
2737 return albumSet->GetFirstObject()->GetAlbumUri();
2738 }
2739
SolveOnChange(napi_env env,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper)2740 napi_value ChangeListenerNapi::SolveOnChange(napi_env env, ChangeListenerNapi::JsOnChangeCallbackWrapper* wrapper)
2741 {
2742 MediaLibraryTracer tracer;
2743 tracer.Start("ChangeListenerNapi::SolveOnChange");
2744 UvChangeMsg* msg = wrapper->msg_;
2745 static napi_value result;
2746 if (msg->changeInfo_.uris_.empty()) {
2747 napi_get_undefined(env, &result);
2748 NAPI_ERR_LOG("changeInfo_.uris_ is empty");
2749 return result;
2750 }
2751 napi_create_object(env, &result);
2752 SetValueArray(env, "uris", msg->changeInfo_.uris_, result);
2753 if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2754 ChangeListenerNapi::SetSharedAssetArray(env, "sharedAlbumAssets", wrapper, result, false);
2755 } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2756 ChangeListenerNapi::SetSharedAssetArray(env, "sharedPhotoAssets", wrapper, result, true);
2757 } else {
2758 NAPI_DEBUG_LOG("other albums notify");
2759 }
2760
2761 if (msg->changeInfo_.uris_.size() == DEFAULT_ALBUM_COUNT) {
2762 if (msg->changeInfo_.uris_.front().ToString().compare(GetTrashAlbumUri()) == 0) {
2763 if (!MediaLibraryNapiUtils::IsSystemApp()) {
2764 napi_get_undefined(env, &result);
2765 NAPI_ERR_LOG("tha app is not system");
2766 return nullptr;
2767 }
2768 }
2769 }
2770 if (msg->data_ != nullptr && msg->changeInfo_.size_ > 0) {
2771 if ((int)msg->changeInfo_.changeType_ == ChangeType::INSERT) {
2772 SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_ADD_ASSET, result);
2773 } else {
2774 SetValueInt32(env, "type", (int)NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, result);
2775 }
2776 napi_status status = SetSubUris(env, wrapper, result);
2777 if (status != napi_ok) {
2778 NAPI_ERR_LOG("Set subArray named property error! field: subUris");
2779 }
2780 } else {
2781 SetValueInt32(env, "type", (int)msg->changeInfo_.changeType_, result);
2782 }
2783 return result;
2784 }
2785
GetSharedResultSetFromIds(std::vector<string> & Ids,bool isPhoto)2786 std::shared_ptr<NativeRdb::ResultSet> ChangeListenerNapi::GetSharedResultSetFromIds(std::vector<string>& Ids,
2787 bool isPhoto)
2788 {
2789 string queryString = isPhoto ? PAH_QUERY_PHOTO : PAH_QUERY_PHOTO_ALBUM;
2790 MediaLibraryNapiUtils::UriAppendKeyValue(queryString, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2791 Uri queryUri(queryString);
2792 DataShare::DataSharePredicates predicates;
2793 if (isPhoto) {
2794 predicates.In(MediaColumn::MEDIA_ID, Ids);
2795 } else {
2796 predicates.In(PhotoAlbumColumns::ALBUM_ID, Ids);
2797 }
2798 std::vector<std::string> columns = isPhoto ? PHOTO_COLUMN : ALBUM_COLUMN;
2799 return UserFileClient::QueryRdb(queryUri, predicates, columns);
2800 }
2801
GetIdsFromUris(std::list<Uri> & listValue,std::vector<std::string> & ids,bool isPhoto)2802 void ChangeListenerNapi::GetIdsFromUris(std::list<Uri>& listValue, std::vector<std::string>& ids, bool isPhoto)
2803 {
2804 for (auto& uri : listValue) {
2805 string assetId = isPhoto ? MediaLibraryNapiUtils::GetFileIdFromUriString(uri.ToString()) :
2806 MediaLibraryNapiUtils::GetAlbumIdFromUriString(uri.ToString());
2807 if (assetId == "") {
2808 NAPI_WARN_LOG("Failed to read assetId");
2809 continue;
2810 }
2811 ids.push_back(assetId);
2812 }
2813 }
2814
GetResultSetFromMsg(UvChangeMsg * msg,JsOnChangeCallbackWrapper * wrapper)2815 void ChangeListenerNapi::GetResultSetFromMsg(UvChangeMsg *msg, JsOnChangeCallbackWrapper* wrapper)
2816 {
2817 std::vector<string> ids = {};
2818 std::shared_ptr<NativeRdb::ResultSet> sharedAssets = nullptr;
2819 if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2820 GetIdsFromUris(msg->changeInfo_.uris_, ids, false);
2821 sharedAssets = GetSharedResultSetFromIds(ids, false);
2822 } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2823 GetIdsFromUris(msg->changeInfo_.uris_, ids, true);
2824 sharedAssets = GetSharedResultSetFromIds(ids, true);
2825 } else {
2826 NAPI_DEBUG_LOG("other albums notify");
2827 }
2828 wrapper->uriSize_ = ids.size();
2829 wrapper->sharedAssets_ = sharedAssets;
2830 shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
2831 std::vector<string> extraIds = {};
2832 if (parcel->ParseFrom(reinterpret_cast<uintptr_t>(msg->data_), msg->changeInfo_.size_)) {
2833 uint32_t len = 0;
2834 if (!parcel->ReadUint32(len)) {
2835 NAPI_ERR_LOG("Failed to read sub uri list length");
2836 return;
2837 }
2838 if (len > MAX_LEN_LIMIT) {
2839 NAPI_ERR_LOG("len exceed the limit.");
2840 return;
2841 }
2842 for (uint32_t i = 0; i < len; i++) {
2843 string subUri = parcel->ReadString();
2844 if (subUri.empty()) {
2845 NAPI_ERR_LOG("Failed to read sub uri");
2846 continue;
2847 }
2848 wrapper->extraUris_.push_back(subUri);
2849 string fileId = MediaLibraryNapiUtils::GetFileIdFromUriString(subUri);
2850 if (!fileId.empty()) {
2851 extraIds.push_back(fileId);
2852 }
2853 }
2854 if (len > MAX_QUERY_LIMIT) {
2855 NAPI_INFO_LOG("subUri length exceed the limit.");
2856 wrapper->extraSharedAssets_ = nullptr;
2857 return;
2858 }
2859 if (extraIds.size() != 0) {
2860 wrapper->extraSharedAssets_ = GetSharedResultSetFromIds(extraIds, true);
2861 }
2862 }
2863 }
2864
OnChange(MediaChangeListener & listener,const napi_ref cbRef)2865 void ChangeListenerNapi::OnChange(MediaChangeListener &listener, const napi_ref cbRef)
2866 {
2867 UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(env_, cbRef, listener.changeInfo, listener.strUri);
2868 if (msg == nullptr) {
2869 return;
2870 }
2871 if (!listener.changeInfo.uris_.empty()) {
2872 if (listener.changeInfo.changeType_ == DataShare::DataShareObserver::ChangeType::OTHER) {
2873 NAPI_ERR_LOG("changeInfo.changeType_ is other");
2874 delete msg;
2875 return;
2876 }
2877 if (msg->changeInfo_.size_ > 0) {
2878 msg->data_ = (uint8_t *)malloc(msg->changeInfo_.size_);
2879 if (msg->data_ == nullptr) {
2880 NAPI_ERR_LOG("new msg->data failed");
2881 delete msg;
2882 return;
2883 }
2884 int copyRet = memcpy_s(msg->data_, msg->changeInfo_.size_, msg->changeInfo_.data_, msg->changeInfo_.size_);
2885 if (copyRet != 0) {
2886 NAPI_ERR_LOG("Parcel data copy failed, err = %{public}d", copyRet);
2887 }
2888 }
2889 }
2890 QueryRdbAndNotifyChange(msg);
2891 }
2892
QueryRdbAndNotifyChange(UvChangeMsg * msg)2893 void ChangeListenerNapi::QueryRdbAndNotifyChange(UvChangeMsg *msg)
2894 {
2895 JsOnChangeCallbackWrapper* wrapper = new (std::nothrow) JsOnChangeCallbackWrapper();
2896 if (wrapper == nullptr) {
2897 NAPI_ERR_LOG("JsOnChangeCallbackWrapper allocation failed");
2898 delete msg;
2899 return;
2900 }
2901 wrapper->msg_ = msg;
2902 MediaLibraryTracer tracer;
2903 tracer.Start("GetResultSetFromMsg");
2904 GetResultSetFromMsg(msg, wrapper);
2905 tracer.Finish();
2906 int ret = 0;
2907 if (msg->strUri_.find(PhotoAlbumColumns::DEFAULT_PHOTO_ALBUM_URI) != std::string::npos) {
2908 ret = ChangeListenerNapi::ParseSharedPhotoAssets(wrapper, false);
2909 } else if (msg->strUri_.find(PhotoColumn::DEFAULT_PHOTO_URI) != std::string::npos) {
2910 ret = ChangeListenerNapi::ParseSharedPhotoAssets(wrapper, true);
2911 } else {
2912 NAPI_INFO_LOG("other albums notify");
2913 }
2914 if (ret != 0) {
2915 wrapper->sharedAssetsRowObjVector_.clear();
2916 NAPI_WARN_LOG("Failed to ParseSharedPhotoAssets, ret: %{public}d", ret);
2917 }
2918 std::function<void()> task = [wrapper, this]() {
2919 UvQueueWork(wrapper);
2920 };
2921 ret = napi_send_event(env_, task, napi_eprio_immediate);
2922 if (ret != 0) {
2923 NAPI_ERR_LOG("Failed to execute napi_send_event, ret: %{public}d", ret);
2924 free(msg->data_);
2925 delete msg;
2926 delete wrapper;
2927 }
2928 }
2929
UvQueueWork(JsOnChangeCallbackWrapper * wrapper)2930 void ChangeListenerNapi::UvQueueWork(JsOnChangeCallbackWrapper* wrapper)
2931 {
2932 if (wrapper == nullptr) {
2933 return;
2934 }
2935 UvChangeMsg* msg = reinterpret_cast<UvChangeMsg *>(wrapper->msg_);
2936 do {
2937 if (msg == nullptr) {
2938 NAPI_ERR_LOG("UvChangeMsg is null");
2939 break;
2940 }
2941 napi_env env = msg->env_;
2942 NapiScopeHandler scopeHandler(env);
2943 if (!scopeHandler.IsValid()) {
2944 NAPI_ERR_LOG("scopeHandler is invalid");
2945 break;
2946 }
2947
2948 napi_value jsCallback = nullptr;
2949 napi_status status = napi_get_reference_value(env, msg->ref_, &jsCallback);
2950 if (status != napi_ok) {
2951 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
2952 break;
2953 }
2954 napi_value retVal = nullptr;
2955 napi_value result[ARGS_ONE];
2956 result[PARAM0] = ChangeListenerNapi::SolveOnChange(env, wrapper);
2957 if (result[PARAM0] == nullptr) {
2958 NAPI_ERR_LOG("result is nullptr");
2959 break;
2960 }
2961 MediaLibraryTracer tracer;
2962 tracer.Start("ChangeListenerNapi::napi_call_function");
2963 napi_call_function(env, nullptr, jsCallback, ARGS_ONE, result, &retVal);
2964 if (status != napi_ok) {
2965 NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
2966 break;
2967 }
2968 } while (0);
2969 delete msg;
2970 delete wrapper;
2971 }
2972
ParseSharedPhotoAssets(ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,bool isPhoto)2973 int ChangeListenerNapi::ParseSharedPhotoAssets(ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper, bool isPhoto)
2974 {
2975 MediaLibraryTracer tracer;
2976 std::string traceName = std::string("ParseSharedPhotoAssets to wrapper for ") + (isPhoto ? "photo" : "album");
2977 tracer.Start(traceName.c_str());
2978 int ret = -1;
2979 if (wrapper->uriSize_ > MAX_QUERY_LIMIT) {
2980 return ret;
2981 }
2982
2983 std::shared_ptr<NativeRdb::ResultSet> result = wrapper->sharedAssets_;
2984 if (result == nullptr) {
2985 NAPI_WARN_LOG("ParseSharedPhotoAssets result is nullptr");
2986 return ret;
2987 }
2988 wrapper->sharedAssetsRowObjVector_.clear();
2989 while (result->GoToNextRow() == NativeRdb::E_OK) {
2990 std::shared_ptr<RowObject> rowObj = std::make_shared<RowObject>();
2991 if (isPhoto) {
2992 ret = MediaLibraryNapiUtils::ParseNextRowObject(rowObj, result, true);
2993 } else {
2994 ret = MediaLibraryNapiUtils::ParseNextRowAlbumObject(rowObj, result);
2995 }
2996 if (ret != NativeRdb::E_OK) {
2997 result->Close();
2998 return ret;
2999 }
3000 wrapper->sharedAssetsRowObjVector_.emplace_back(std::move(rowObj));
3001 }
3002 result->Close();
3003 return ret;
3004 }
3005
BuildSharedPhotoAssetsObj(const napi_env & env,ChangeListenerNapi::JsOnChangeCallbackWrapper * wrapper,bool isPhoto)3006 napi_value ChangeListenerNapi::BuildSharedPhotoAssetsObj(const napi_env& env,
3007 ChangeListenerNapi::JsOnChangeCallbackWrapper *wrapper, bool isPhoto)
3008 {
3009 napi_value value = nullptr;
3010 napi_status status = napi_create_array_with_length(env, wrapper->sharedAssetsRowObjVector_.size(), &value);
3011 CHECK_COND_RET(status == napi_ok, nullptr, "Create array error!");
3012 napi_value tmpValue = nullptr;
3013 status = napi_create_array_with_length(env, 0, &tmpValue);
3014 CHECK_COND_RET(status == napi_ok, nullptr, "Create array error!");
3015 if (wrapper->uriSize_ > MAX_QUERY_LIMIT) {
3016 NAPI_WARN_LOG("BuildSharedPhotoAssetsObj uriSize is over limit");
3017 return tmpValue;
3018 }
3019 if (wrapper->sharedAssets_ == nullptr) {
3020 NAPI_WARN_LOG("wrapper sharedAssets is nullptr");
3021 return tmpValue;
3022 }
3023 size_t elementIndex = 0;
3024 while (elementIndex < wrapper->sharedAssetsRowObjVector_.size()) {
3025 napi_value assetValue;
3026 if (isPhoto) {
3027 assetValue = MediaLibraryNapiUtils::BuildNextRowObject(
3028 env, wrapper->sharedAssetsRowObjVector_[elementIndex], true);
3029 } else {
3030 assetValue = MediaLibraryNapiUtils::BuildNextRowAlbumObject(
3031 env, wrapper->sharedAssetsRowObjVector_[elementIndex]);
3032 }
3033 if (assetValue == nullptr) {
3034 wrapper->sharedAssets_->Close();
3035 return tmpValue;
3036 }
3037 status = napi_set_element(env, value, elementIndex++, assetValue);
3038 if (status != napi_ok) {
3039 NAPI_ERR_LOG("Set photo asset value failed");
3040 wrapper->sharedAssets_->Close();
3041 return tmpValue;
3042 }
3043 }
3044 wrapper->sharedAssets_->Close();
3045 return value;
3046 }
3047
GetListenerType(const string & str) const3048 int32_t MediaLibraryNapi::GetListenerType(const string &str) const
3049 {
3050 auto iter = ListenerTypeMaps.find(str);
3051 if (iter == ListenerTypeMaps.end()) {
3052 NAPI_ERR_LOG("Invalid Listener Type %{public}s", str.c_str());
3053 return INVALID_LISTENER;
3054 }
3055
3056 return iter->second;
3057 }
3058
RegisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)3059 void MediaLibraryNapi::RegisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
3060 {
3061 NAPI_DEBUG_LOG("Register change type = %{public}s", type.c_str());
3062
3063 int32_t typeEnum = GetListenerType(type);
3064 switch (typeEnum) {
3065 case AUDIO_LISTENER:
3066 listObj.audioDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_AUDIO);
3067 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
3068 break;
3069 case VIDEO_LISTENER:
3070 listObj.videoDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_VIDEO);
3071 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
3072 break;
3073 case IMAGE_LISTENER:
3074 listObj.imageDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_IMAGE);
3075 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
3076 break;
3077 case FILE_LISTENER:
3078 listObj.fileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_FILE);
3079 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
3080 break;
3081 case SMARTALBUM_LISTENER:
3082 listObj.smartAlbumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_SMARTALBUM);
3083 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
3084 listObj.smartAlbumDataObserver_);
3085 break;
3086 case DEVICE_LISTENER:
3087 listObj.deviceDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_DEVICE);
3088 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
3089 break;
3090 case REMOTEFILE_LISTENER:
3091 listObj.remoteFileDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_REMOTEFILE);
3092 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
3093 break;
3094 case ALBUM_LISTENER:
3095 listObj.albumDataObserver_ = new(nothrow) MediaObserver(listObj, MEDIA_TYPE_ALBUM);
3096 UserFileClient::RegisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
3097 break;
3098 default:
3099 NAPI_ERR_LOG("Invalid Media Type!");
3100 }
3101 }
3102
RegisterNotifyChange(napi_env env,const std::string & uri,bool isDerived,napi_ref ref,ChangeListenerNapi & listObj)3103 void MediaLibraryNapi::RegisterNotifyChange(napi_env env,
3104 const std::string &uri, bool isDerived, napi_ref ref, ChangeListenerNapi &listObj)
3105 {
3106 Uri notifyUri(uri);
3107 shared_ptr<MediaOnNotifyObserver> observer= make_shared<MediaOnNotifyObserver>(listObj, uri, ref);
3108 UserFileClient::RegisterObserverExt(notifyUri,
3109 static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), isDerived);
3110 lock_guard<mutex> lock(sOnOffMutex_);
3111 listObj.observers_.push_back(observer);
3112 }
3113
JSOnCallback(napi_env env,napi_callback_info info)3114 napi_value MediaLibraryNapi::JSOnCallback(napi_env env, napi_callback_info info)
3115 {
3116 MediaLibraryTracer tracer;
3117 tracer.Start("JSOnCallback");
3118 napi_value undefinedResult = nullptr;
3119 napi_get_undefined(env, &undefinedResult);
3120 size_t argc = ARGS_TWO;
3121 napi_value argv[ARGS_TWO] = {nullptr};
3122 napi_value thisVar = nullptr;
3123 GET_JS_ARGS(env, info, argc, argv, thisVar);
3124 NAPI_ASSERT(env, argc == ARGS_TWO, "requires 2 parameters");
3125 MediaLibraryNapi *obj = nullptr;
3126 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3127 if (status == napi_ok && obj != nullptr) {
3128 napi_valuetype valueType = napi_undefined;
3129 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
3130 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3131 return undefinedResult;
3132 }
3133 char buffer[ARG_BUF_SIZE];
3134 size_t res = 0;
3135 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3136 NAPI_ERR_LOG("Failed to get value string utf8 for type");
3137 return undefinedResult;
3138 }
3139 string type = string(buffer);
3140 const int32_t refCount = 1;
3141 napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOnRef_);
3142 tracer.Start("RegisterChange");
3143 obj->RegisterChange(env, type, *g_listObj);
3144 tracer.Finish();
3145 }
3146 return undefinedResult;
3147 }
3148
CheckRef(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,bool isOff,const string & uri)3149 bool MediaLibraryNapi::CheckRef(napi_env env,
3150 napi_ref ref, ChangeListenerNapi &listObj, bool isOff, const string &uri)
3151 {
3152 napi_value offCallback = nullptr;
3153 napi_status status = napi_get_reference_value(env, ref, &offCallback);
3154 if (status != napi_ok) {
3155 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
3156 return false;
3157 }
3158 bool isSame = false;
3159 shared_ptr<DataShare::DataShareObserver> obs;
3160 string obsUri;
3161 {
3162 lock_guard<mutex> lock(sOnOffMutex_);
3163 for (auto it = listObj.observers_.begin(); it < listObj.observers_.end(); it++) {
3164 napi_value onCallback = nullptr;
3165 status = napi_get_reference_value(env, (*it)->ref_, &onCallback);
3166 if (status != napi_ok) {
3167 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
3168 return false;
3169 }
3170 napi_strict_equals(env, offCallback, onCallback, &isSame);
3171 if (isSame) {
3172 obsUri = (*it)->uri_;
3173 if ((isOff) && (uri.compare(obsUri) == 0)) {
3174 obs = static_cast<shared_ptr<DataShare::DataShareObserver>>(*it);
3175 listObj.observers_.erase(it);
3176 break;
3177 }
3178 if (uri.compare(obsUri) != 0) {
3179 return true;
3180 }
3181 return false;
3182 }
3183 }
3184 }
3185 if (isSame && isOff) {
3186 if (obs != nullptr) {
3187 UserFileClient::UnregisterObserverExt(Uri(obsUri), obs);
3188 }
3189 }
3190 return true;
3191 }
3192
UserFileMgrOnCallback(napi_env env,napi_callback_info info)3193 napi_value MediaLibraryNapi::UserFileMgrOnCallback(napi_env env, napi_callback_info info)
3194 {
3195 MediaLibraryTracer tracer;
3196 tracer.Start("UserFileMgrOnCallback");
3197 napi_value undefinedResult = nullptr;
3198 napi_get_undefined(env, &undefinedResult);
3199 size_t argc = ARGS_THREE;
3200 napi_value argv[ARGS_THREE] = {nullptr};
3201 napi_value thisVar = nullptr;
3202 GET_JS_ARGS(env, info, argc, argv, thisVar);
3203 if (argc == ARGS_TWO) {
3204 return JSOnCallback(env, info);
3205 }
3206 NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
3207 MediaLibraryNapi *obj = nullptr;
3208 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3209 if (status == napi_ok && obj != nullptr) {
3210 napi_valuetype valueType = napi_undefined;
3211 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
3212 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
3213 napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
3214 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3215 return undefinedResult;
3216 }
3217 char buffer[ARG_BUF_SIZE];
3218 size_t res = 0;
3219 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3220 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3221 return undefinedResult;
3222 }
3223 string uri = string(buffer);
3224 bool isDerived = false;
3225 if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
3226 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3227 return undefinedResult;
3228 }
3229 const int32_t refCount = 1;
3230 napi_ref cbOnRef = nullptr;
3231 napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
3232 tracer.Start("RegisterNotifyChange");
3233 if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
3234 obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
3235 } else {
3236 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3237 napi_delete_reference(env, cbOnRef);
3238 cbOnRef = nullptr;
3239 return undefinedResult;
3240 }
3241 tracer.Finish();
3242 }
3243 return undefinedResult;
3244 }
3245
UnregisterChange(napi_env env,const string & type,ChangeListenerNapi & listObj)3246 void MediaLibraryNapi::UnregisterChange(napi_env env, const string &type, ChangeListenerNapi &listObj)
3247 {
3248 NAPI_DEBUG_LOG("Unregister change type = %{public}s", type.c_str());
3249
3250 MediaType mediaType;
3251 int32_t typeEnum = GetListenerType(type);
3252
3253 switch (typeEnum) {
3254 case AUDIO_LISTENER:
3255 CHECK_NULL_PTR_RETURN_VOID(listObj.audioDataObserver_, "Failed to obtain audio data observer");
3256 mediaType = MEDIA_TYPE_AUDIO;
3257 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_AUDIO_URI), listObj.audioDataObserver_);
3258 listObj.audioDataObserver_ = nullptr;
3259 break;
3260 case VIDEO_LISTENER:
3261 CHECK_NULL_PTR_RETURN_VOID(listObj.videoDataObserver_, "Failed to obtain video data observer");
3262 mediaType = MEDIA_TYPE_VIDEO;
3263 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_VIDEO_URI), listObj.videoDataObserver_);
3264 listObj.videoDataObserver_ = nullptr;
3265 break;
3266 case IMAGE_LISTENER:
3267 CHECK_NULL_PTR_RETURN_VOID(listObj.imageDataObserver_, "Failed to obtain image data observer");
3268 mediaType = MEDIA_TYPE_IMAGE;
3269 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_IMAGE_URI), listObj.imageDataObserver_);
3270 listObj.imageDataObserver_ = nullptr;
3271 break;
3272 case FILE_LISTENER:
3273 CHECK_NULL_PTR_RETURN_VOID(listObj.fileDataObserver_, "Failed to obtain file data observer");
3274 mediaType = MEDIA_TYPE_FILE;
3275 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_FILE_URI), listObj.fileDataObserver_);
3276 listObj.fileDataObserver_ = nullptr;
3277 break;
3278 case SMARTALBUM_LISTENER:
3279 CHECK_NULL_PTR_RETURN_VOID(listObj.smartAlbumDataObserver_, "Failed to obtain smart album data observer");
3280 mediaType = MEDIA_TYPE_SMARTALBUM;
3281 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_SMARTALBUM_CHANGE_URI),
3282 listObj.smartAlbumDataObserver_);
3283 listObj.smartAlbumDataObserver_ = nullptr;
3284 break;
3285 case DEVICE_LISTENER:
3286 CHECK_NULL_PTR_RETURN_VOID(listObj.deviceDataObserver_, "Failed to obtain device data observer");
3287 mediaType = MEDIA_TYPE_DEVICE;
3288 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_DEVICE_URI), listObj.deviceDataObserver_);
3289 listObj.deviceDataObserver_ = nullptr;
3290 break;
3291 case REMOTEFILE_LISTENER:
3292 CHECK_NULL_PTR_RETURN_VOID(listObj.remoteFileDataObserver_, "Failed to obtain remote file data observer");
3293 mediaType = MEDIA_TYPE_REMOTEFILE;
3294 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_REMOTEFILE_URI), listObj.remoteFileDataObserver_);
3295 listObj.remoteFileDataObserver_ = nullptr;
3296 break;
3297 case ALBUM_LISTENER:
3298 CHECK_NULL_PTR_RETURN_VOID(listObj.albumDataObserver_, "Failed to obtain album data observer");
3299 mediaType = MEDIA_TYPE_ALBUM;
3300 UserFileClient::UnregisterObserver(Uri(MEDIALIBRARY_ALBUM_URI), listObj.albumDataObserver_);
3301 listObj.albumDataObserver_ = nullptr;
3302 break;
3303 default:
3304 NAPI_ERR_LOG("Invalid Media Type");
3305 return;
3306 }
3307
3308 if (listObj.cbOffRef_ != nullptr) {
3309 MediaChangeListener listener;
3310 listener.mediaType = mediaType;
3311 listObj.OnChange(listener, listObj.cbOffRef_);
3312 }
3313 }
3314
UnRegisterNotifyChange(napi_env env,const std::string & uri,napi_ref ref,ChangeListenerNapi & listObj)3315 void MediaLibraryNapi::UnRegisterNotifyChange(napi_env env,
3316 const std::string &uri, napi_ref ref, ChangeListenerNapi &listObj)
3317 {
3318 if (ref != nullptr) {
3319 CheckRef(env, ref, listObj, true, uri);
3320 return;
3321 }
3322 if (listObj.observers_.size() == 0) {
3323 return;
3324 }
3325 std::vector<std::shared_ptr<MediaOnNotifyObserver>> offObservers;
3326 {
3327 lock_guard<mutex> lock(sOnOffMutex_);
3328 for (auto iter = listObj.observers_.begin(); iter != listObj.observers_.end();) {
3329 if (uri.compare((*iter)->uri_) == 0) {
3330 offObservers.push_back(*iter);
3331 vector<shared_ptr<MediaOnNotifyObserver>>::iterator tmp = iter;
3332 iter = listObj.observers_.erase(tmp);
3333 } else {
3334 iter++;
3335 }
3336 }
3337 }
3338 for (auto obs : offObservers) {
3339 UserFileClient::UnregisterObserverExt(Uri(uri),
3340 static_cast<shared_ptr<DataShare::DataShareObserver>>(obs));
3341 }
3342 }
3343
JSOffCallback(napi_env env,napi_callback_info info)3344 napi_value MediaLibraryNapi::JSOffCallback(napi_env env, napi_callback_info info)
3345 {
3346 MediaLibraryTracer tracer;
3347 tracer.Start("JSOffCallback");
3348 napi_value undefinedResult = nullptr;
3349 napi_get_undefined(env, &undefinedResult);
3350 size_t argc = ARGS_TWO;
3351 napi_value argv[ARGS_TWO] = {nullptr};
3352 napi_value thisVar = nullptr;
3353 GET_JS_ARGS(env, info, argc, argv, thisVar);
3354 NAPI_ASSERT(env, ARGS_ONE <= argc && argc <= ARGS_TWO, "requires one or two parameters");
3355 if (thisVar == nullptr || argv[PARAM0] == nullptr) {
3356 NAPI_ERR_LOG("Failed to retrieve details about the callback");
3357 return undefinedResult;
3358 }
3359 MediaLibraryNapi *obj = nullptr;
3360 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3361 if (status == napi_ok && obj != nullptr) {
3362 napi_valuetype valueType = napi_undefined;
3363 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
3364 return undefinedResult;
3365 }
3366 if (argc == ARGS_TWO) {
3367 auto status = napi_typeof(env, argv[PARAM1], &valueType);
3368 if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
3369 argc -= 1;
3370 }
3371 }
3372 size_t res = 0;
3373 char buffer[ARG_BUF_SIZE];
3374 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3375 NAPI_ERR_LOG("Failed to get value string utf8 for type");
3376 return undefinedResult;
3377 }
3378 string type = string(buffer);
3379 if (argc == ARGS_TWO) {
3380 if (napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function ||
3381 g_listObj == nullptr) {
3382 return undefinedResult;
3383 }
3384 const int32_t refCount = 1;
3385 napi_create_reference(env, argv[PARAM1], refCount, &g_listObj->cbOffRef_);
3386 }
3387
3388 tracer.Start("UnregisterChange");
3389 obj->UnregisterChange(env, type, *g_listObj);
3390 tracer.Finish();
3391 }
3392
3393 return undefinedResult;
3394 }
3395
UserFileMgrOffCheckArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3396 static napi_value UserFileMgrOffCheckArgs(napi_env env, napi_callback_info info,
3397 unique_ptr<MediaLibraryAsyncContext> &context)
3398 {
3399 napi_value thisVar = nullptr;
3400 context->argc = ARGS_TWO;
3401 GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
3402 NAPI_ASSERT(env, ARGS_ONE <= context->argc && context->argc<= ARGS_TWO, "requires one or two parameters");
3403 if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
3404 return nullptr;
3405 }
3406
3407 napi_valuetype valueType = napi_undefined;
3408 if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
3409 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3410 return nullptr;
3411 }
3412
3413 if (context->argc == ARGS_TWO) {
3414 auto status = napi_typeof(env, context->argv[PARAM1], &valueType);
3415 if (status == napi_ok && (valueType == napi_undefined || valueType == napi_null)) {
3416 context->argc -= 1;
3417 }
3418 }
3419
3420 return thisVar;
3421 }
3422
UserFileMgrOffCallback(napi_env env,napi_callback_info info)3423 napi_value MediaLibraryNapi::UserFileMgrOffCallback(napi_env env, napi_callback_info info)
3424 {
3425 MediaLibraryTracer tracer;
3426 tracer.Start("UserFileMgrOffCallback");
3427 napi_value undefinedResult = nullptr;
3428 napi_get_undefined(env, &undefinedResult);
3429
3430 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3431 napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
3432 MediaLibraryNapi *obj = nullptr;
3433 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
3434 if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
3435 return undefinedResult;
3436 }
3437 size_t res = 0;
3438 char buffer[ARG_BUF_SIZE];
3439 if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
3440 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3441 return undefinedResult;
3442 }
3443
3444 string uri = string(buffer);
3445 napi_valuetype valueType = napi_undefined;
3446 if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
3447 if (asyncContext->argc == ARGS_TWO) {
3448 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3449 return undefinedResult;
3450 }
3451 const int32_t refCount = 1;
3452 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
3453 }
3454 obj->UnregisterChange(env, uri, *g_listObj);
3455 return undefinedResult;
3456 }
3457 napi_ref cbOffRef = nullptr;
3458 if (asyncContext->argc == ARGS_TWO) {
3459 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
3460 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3461 return undefinedResult;
3462 }
3463 const int32_t refCount = 1;
3464 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
3465 }
3466 tracer.Start("UnRegisterNotifyChange");
3467 obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
3468 return undefinedResult;
3469 }
3470
JSReleaseCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)3471 static void JSReleaseCompleteCallback(napi_env env, napi_status status,
3472 MediaLibraryAsyncContext *context)
3473 {
3474 MediaLibraryTracer tracer;
3475 tracer.Start("JSReleaseCompleteCallback");
3476
3477 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3478
3479 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3480 jsContext->status = false;
3481 napi_create_int32(env, E_SUCCESS, &jsContext->data);
3482 jsContext->status = true;
3483 napi_get_undefined(env, &jsContext->error);
3484
3485 tracer.Finish();
3486 MediaLibraryNapiUtils::InvokeJSAsyncMethodWithoutWork(env, context->deferred, context->callbackRef,
3487 *jsContext);
3488
3489 delete context;
3490 }
3491
JSRelease(napi_env env,napi_callback_info info)3492 napi_value MediaLibraryNapi::JSRelease(napi_env env, napi_callback_info info)
3493 {
3494 napi_status status;
3495 napi_value result = nullptr;
3496 size_t argc = ARGS_ONE;
3497 napi_value argv[ARGS_ONE] = {0};
3498 napi_value thisVar = nullptr;
3499 int32_t refCount = 1;
3500
3501 MediaLibraryTracer tracer;
3502 tracer.Start("JSRelease");
3503
3504 GET_JS_ARGS(env, info, argc, argv, thisVar);
3505 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_ZERO), "requires 1 parameters maximum");
3506 napi_get_undefined(env, &result);
3507
3508 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3509 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3510 NAPI_ASSERT(env, status == napi_ok && asyncContext->objectInfo != nullptr, "Failed to get object info");
3511
3512 if (argc == PARAM1) {
3513 napi_valuetype valueType = napi_undefined;
3514 napi_typeof(env, argv[PARAM0], &valueType);
3515 if (valueType == napi_function) {
3516 napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
3517 }
3518 }
3519 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3520 NAPI_CALL(env, napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
3521 asyncContext->objectInfo = nullptr;
3522 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3523 MediaLibraryAsyncContext *context = asyncContext.get();
3524 std::function<void()> task = [env, status, context]() {
3525 JSReleaseCompleteCallback(env, status, context);
3526 };
3527
3528 status = napi_send_event(env, task, napi_eprio_immediate);
3529 if (status != napi_ok) {
3530 napi_get_undefined(env, &result);
3531 } else {
3532 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
3533 asyncContext.release();
3534 }
3535
3536 return result;
3537 }
3538
SetSmartAlbumCoverUri(MediaLibraryAsyncContext * context,unique_ptr<SmartAlbumAsset> & smartAlbum)3539 static void SetSmartAlbumCoverUri(MediaLibraryAsyncContext *context, unique_ptr<SmartAlbumAsset> &smartAlbum)
3540 {
3541 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3542 if (smartAlbum == nullptr) {
3543 NAPI_ERR_LOG("SmartAlbumAsset is nullptr");
3544 return;
3545 }
3546 if (smartAlbum->GetAlbumCapacity() == 0) {
3547 return;
3548 }
3549 string trashPrefix;
3550 if (smartAlbum->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
3551 trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
3552 } else {
3553 trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
3554 }
3555 MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
3556 context->selectionArgs.emplace_back("0");
3557 context->selectionArgs.emplace_back(to_string(smartAlbum->GetAlbumId()));
3558 DataShare::DataSharePredicates predicates;
3559 predicates.SetOrder(SMARTALBUMMAP_DB_ID + " DESC LIMIT 0,1 ");
3560 predicates.SetWhereClause(context->selection);
3561 predicates.SetWhereArgs(context->selectionArgs);
3562 vector<string> columns;
3563 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + ASSETMAP_VIEW_NAME);
3564 int errCode = 0;
3565 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode,
3566 context->userId);
3567 if (resultSet == nullptr) {
3568 NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
3569 return;
3570 }
3571 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
3572 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
3573 CHECK_NULL_PTR_RETURN_VOID(fileAsset, "SetSmartAlbumCoverUri fileAsset is nullptr");
3574 string coverUri = fileAsset->GetUri();
3575 smartAlbum->SetCoverUri(coverUri);
3576 NAPI_DEBUG_LOG("coverUri is = %{private}s", smartAlbum->GetCoverUri().c_str());
3577 }
3578
SetSmartAlbumData(SmartAlbumAsset * smartAlbumData,shared_ptr<DataShare::DataShareResultSet> resultSet,MediaLibraryAsyncContext * context)3579 static void SetSmartAlbumData(SmartAlbumAsset* smartAlbumData, shared_ptr<DataShare::DataShareResultSet> resultSet,
3580 MediaLibraryAsyncContext *context)
3581 {
3582 CHECK_NULL_PTR_RETURN_VOID(smartAlbumData, "albumData is null");
3583 smartAlbumData->SetAlbumId(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_ID, resultSet, TYPE_INT32)));
3584 smartAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_NAME, resultSet,
3585 TYPE_STRING)));
3586 smartAlbumData->SetAlbumCapacity(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUMASSETS_ALBUMCAPACITY,
3587 resultSet, TYPE_INT32)));
3588 MediaFileUri fileUri(MEDIA_TYPE_SMARTALBUM, to_string(smartAlbumData->GetAlbumId()), context->networkId,
3589 MEDIA_API_VERSION_DEFAULT);
3590 smartAlbumData->SetAlbumUri(fileUri.ToString());
3591 smartAlbumData->SetDescription(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_DESCRIPTION, resultSet,
3592 TYPE_STRING)));
3593 smartAlbumData->SetExpiredTime(get<int32_t>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_EXPIRED_TIME, resultSet,
3594 TYPE_INT32)));
3595 smartAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(SMARTALBUM_DB_COVER_URI, resultSet,
3596 TYPE_STRING)));
3597 smartAlbumData->SetResultNapiType(context->resultNapiType);
3598 }
3599
3600 #ifndef MEDIALIBRARY_COMPATIBILITY
GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3601 static void GetAllSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3602 {
3603 MediaLibraryTracer tracer;
3604 tracer.Start("GetAllSmartAlbumResultDataExecute");
3605
3606 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3607 NAPI_INFO_LOG("context->privateAlbumType = %{public}d", context->privateAlbumType);
3608
3609 if (context->privateAlbumType == TYPE_TRASH) {
3610 context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(TRASH_ALBUM_ID_VALUES));
3611 NAPI_INFO_LOG("context->privateAlbumType == TYPE_TRASH");
3612 }
3613 if (context->privateAlbumType == TYPE_FAVORITE) {
3614 context->predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + to_string(FAVOURITE_ALBUM_ID_VALUES));
3615 NAPI_INFO_LOG("context->privateAlbumType == TYPE_FAVORITE");
3616 }
3617
3618 vector<string> columns;
3619 string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3620 if (!context->networkId.empty()) {
3621 uriStr = MEDIALIBRARY_DATA_ABILITY_PREFIX + context->networkId + MEDIALIBRARY_DATA_URI_IDENTIFIER +
3622 "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + SMARTALBUM_TABLE;
3623 }
3624 Uri uri(uriStr);
3625 int errCode = 0;
3626 auto resultSet = UserFileClient::Query(uri, context->predicates, columns, errCode,
3627 context->userId);
3628 if (resultSet == nullptr) {
3629 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
3630 context->error = E_PERMISSION_DENIED;
3631 return;
3632 }
3633
3634 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
3635 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
3636 context->fetchSmartAlbumResult = make_unique<FetchResult<SmartAlbumAsset>>(move(resultSet));
3637 context->fetchSmartAlbumResult->SetNetworkId(context->networkId);
3638 context->fetchSmartAlbumResult->SetResultNapiType(context->resultNapiType);
3639 return;
3640 }
3641 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3642 unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3643 SetSmartAlbumData(albumData.get(), resultSet, context);
3644 if (albumData->GetCoverUri().empty()) {
3645 SetSmartAlbumCoverUri(context, albumData);
3646 }
3647 context->privateSmartAlbumNativeArray.push_back(move(albumData));
3648 }
3649 }
3650
MediaLibSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3651 static void MediaLibSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3652 unique_ptr<JSAsyncContextOutput> &jsContext)
3653 {
3654 if (context->smartAlbumData != nullptr) {
3655 NAPI_ERR_LOG("context->smartAlbumData != nullptr");
3656 jsContext->status = true;
3657 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
3658 napi_get_undefined(env, &jsContext->error);
3659 jsContext->data = albumNapiObj;
3660 } else if (!context->privateSmartAlbumNativeArray.empty()) {
3661 jsContext->status = true;
3662 napi_value albumArray = nullptr;
3663 napi_create_array(env, &albumArray);
3664 for (size_t i = 0; i < context->privateSmartAlbumNativeArray.size(); i++) {
3665 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3666 context->privateSmartAlbumNativeArray[i]);
3667 napi_set_element(env, albumArray, i, albumNapiObj);
3668 }
3669 napi_get_undefined(env, &jsContext->error);
3670 jsContext->data = albumArray;
3671 } else {
3672 NAPI_ERR_LOG("No fetch file result found!");
3673 napi_get_undefined(env, &jsContext->data);
3674 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3675 "Failed to obtain Fetch File Result");
3676 }
3677 }
3678
UserFileMgrSmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3679 static void UserFileMgrSmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3680 unique_ptr<JSAsyncContextOutput> &jsContext)
3681 {
3682 if (context->fetchSmartAlbumResult->GetCount() < 0) {
3683 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
3684 "find no data by options");
3685 } else {
3686 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchSmartAlbumResult));
3687 if (fileResult == nullptr) {
3688 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3689 "Failed to create js object for Fetch SmartAlbum Result");
3690 } else {
3691 jsContext->data = fileResult;
3692 jsContext->status = true;
3693 napi_get_undefined(env, &jsContext->error);
3694 }
3695 }
3696 }
3697
SmartAlbumsAsyncResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3698 static void SmartAlbumsAsyncResult(napi_env env, MediaLibraryAsyncContext *context,
3699 unique_ptr<JSAsyncContextOutput> &jsContext)
3700 {
3701 if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
3702 MediaLibSmartAlbumsAsyncResult(env, context, jsContext);
3703 } else {
3704 UserFileMgrSmartAlbumsAsyncResult(env, context, jsContext);
3705 }
3706 }
3707
GetPrivateAlbumCallbackComplete(napi_env env,napi_status status,void * data)3708 static void GetPrivateAlbumCallbackComplete(napi_env env, napi_status status, void *data)
3709 {
3710 MediaLibraryTracer tracer;
3711 tracer.Start("GetPrivateAlbumCallbackComplete");
3712
3713 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3714 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3715 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3716 jsContext->status = false;
3717 napi_get_undefined(env, &jsContext->error);
3718 if (context->error != ERR_DEFAULT) {
3719 napi_get_undefined(env, &jsContext->data);
3720 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3721 "Query for get fileAssets failed");
3722 } else {
3723 SmartAlbumsAsyncResult(env, context, jsContext);
3724 }
3725
3726 tracer.Finish();
3727 if (context->work != nullptr) {
3728 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3729 context->work, *jsContext);
3730 }
3731 delete context;
3732 }
3733 #endif
3734
GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext * context)3735 static void GetSmartAlbumResultDataExecute(MediaLibraryAsyncContext *context)
3736 {
3737 DataShare::DataSharePredicates predicates;
3738 predicates.SetWhereClause(context->selection);
3739 predicates.SetWhereArgs(context->selectionArgs);
3740 vector<string> columns;
3741 Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3742 int errCode = 0;
3743 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
3744 if (resultSet == nullptr) {
3745 NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3746 context->error = ERR_INVALID_OUTPUT;
3747 return;
3748 }
3749 if (resultSet->GoToFirstRow() == NativeRdb::E_OK) {
3750 context->smartAlbumData = make_unique<SmartAlbumAsset>();
3751 SetSmartAlbumData(context->smartAlbumData.get(), resultSet, context);
3752 SetSmartAlbumCoverUri(context, context->smartAlbumData);
3753 } else {
3754 NAPI_ERR_LOG("Failed to goToFirstRow");
3755 context->error = ERR_INVALID_OUTPUT;
3756 return;
3757 }
3758 }
3759
SmartAlbumsAsyncCallbackComplete(napi_env env,napi_status status,void * data)3760 static void SmartAlbumsAsyncCallbackComplete(napi_env env, napi_status status, void *data)
3761 {
3762 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3763 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3764 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3765 jsContext->status = false;
3766 napi_get_undefined(env, &jsContext->error);
3767 if (context->error != ERR_DEFAULT) {
3768 napi_get_undefined(env, &jsContext->data);
3769 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3770 "Query for get smartAlbums failed");
3771 } else {
3772 if (!context->smartAlbumNativeArray.empty()) {
3773 jsContext->status = true;
3774 napi_value albumArray = nullptr;
3775 napi_create_array(env, &albumArray);
3776 for (size_t i = 0; i < context->smartAlbumNativeArray.size(); i++) {
3777 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env,
3778 context->smartAlbumNativeArray[i]);
3779 napi_set_element(env, albumArray, i, albumNapiObj);
3780 }
3781 napi_get_undefined(env, &jsContext->error);
3782 jsContext->data = albumArray;
3783 } else {
3784 NAPI_ERR_LOG("No SmartAlbums result found!");
3785 napi_get_undefined(env, &jsContext->data);
3786 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3787 "Failed to obtain SmartAlbums Result");
3788 }
3789 }
3790 if (context->work != nullptr) {
3791 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3792 context->work, *jsContext);
3793 }
3794 delete context;
3795 }
3796
GetJSArgsForGetSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)3797 napi_value GetJSArgsForGetSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
3798 MediaLibraryAsyncContext &asyncContext)
3799 {
3800 napi_value result = nullptr;
3801 auto context = &asyncContext;
3802 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
3803 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
3804 for (size_t i = 0; i < argc; i++) {
3805 napi_valuetype valueType = napi_undefined;
3806 napi_typeof(env, argv[i], &valueType);
3807 if (i == 0 && valueType == napi_number) {
3808 napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
3809 } else if ((i == PARAM1) && valueType == napi_function) {
3810 napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
3811 break;
3812 } else {
3813 NAPI_ASSERT(env, false, "type mismatch");
3814 }
3815 }
3816 if (context->parentSmartAlbumId < 0) {
3817 NAPI_ASSERT(env, false, "type mismatch");
3818 }
3819 napi_get_boolean(env, true, &result);
3820 return result;
3821 }
3822
GetSmartAlbumsResultDataExecute(napi_env env,void * data)3823 static void GetSmartAlbumsResultDataExecute(napi_env env, void *data)
3824 {
3825 auto context = static_cast<MediaLibraryAsyncContext *>(data);
3826 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3827 if (context->parentSmartAlbumId < 0) {
3828 context->error = ERR_INVALID_OUTPUT;
3829 NAPI_ERR_LOG("ParentSmartAlbumId is invalid");
3830 return;
3831 }
3832 DataShare::DataSharePredicates predicates;
3833 if (context->parentSmartAlbumId == 0) {
3834 predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " ISNULL");
3835 } else {
3836 predicates.SetWhereClause(SMARTABLUMASSETS_PARENTID + " = ? ");
3837 predicates.SetWhereArgs({ to_string(context->parentSmartAlbumId) });
3838 }
3839 vector<string> columns;
3840 Uri uri(MEDIALIBRARY_DATA_URI + "/" + SMARTALBUMASSETS_VIEW_NAME);
3841 int errCode = 0;
3842 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
3843 if (resultSet == nullptr) {
3844 NAPI_ERR_LOG("ResultSet is nullptr, errCode is %{public}d", errCode);
3845 context->error = ERR_INVALID_OUTPUT;
3846 return;
3847 }
3848 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
3849 unique_ptr<SmartAlbumAsset> albumData = make_unique<SmartAlbumAsset>();
3850 SetSmartAlbumData(albumData.get(), resultSet, context);
3851 if (albumData->GetCoverUri().empty()) {
3852 SetSmartAlbumCoverUri(context, albumData);
3853 }
3854 context->smartAlbumNativeArray.push_back(move(albumData));
3855 }
3856 }
3857
JSGetSmartAlbums(napi_env env,napi_callback_info info)3858 napi_value MediaLibraryNapi::JSGetSmartAlbums(napi_env env, napi_callback_info info)
3859 {
3860 napi_status status;
3861 napi_value result = nullptr;
3862 size_t argc = ARGS_TWO;
3863 napi_value argv[ARGS_TWO] = {0};
3864 napi_value thisVar = nullptr;
3865
3866 GET_JS_ARGS(env, info, argc, argv, thisVar);
3867 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
3868 napi_get_undefined(env, &result);
3869 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
3870 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
3871 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Async context is null");
3872 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
3873 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
3874 result = GetJSArgsForGetSmartAlbum(env, argc, argv, *asyncContext);
3875 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
3876 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
3877 SetUserIdFromObjectInfo(asyncContext);
3878 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbums",
3879 GetSmartAlbumsResultDataExecute, SmartAlbumsAsyncCallbackComplete);
3880 }
3881
3882 return result;
3883 }
3884
CheckAlbumFetchColumns(const vector<string> & fetchColumn)3885 static bool CheckAlbumFetchColumns(const vector<string> &fetchColumn)
3886 {
3887 for (const auto &column : fetchColumn) {
3888 if (!PhotoAlbumColumns::IsPhotoAlbumColumn(column) && column.compare(MEDIA_DATA_DB_URI) != 0) {
3889 return false;
3890 }
3891 }
3892 return true;
3893 }
3894
AddDefaultPhotoAlbumColumns(vector<string> & fetchColumn)3895 static void AddDefaultPhotoAlbumColumns(vector<string> &fetchColumn)
3896 {
3897 auto columns = PhotoAlbumColumns::DEFAULT_FETCH_COLUMNS;
3898 for (const auto &column : fetchColumn) {
3899 if (column.compare(MEDIA_DATA_DB_URI) == 0) {
3900 continue;
3901 }
3902 if (columns.count(column) == 0) {
3903 columns.insert(column);
3904 }
3905 }
3906 fetchColumn.assign(columns.begin(), columns.end());
3907 }
3908
AddDefaultColumnsForNonAnalysisAlbums(MediaLibraryAsyncContext & context)3909 static void AddDefaultColumnsForNonAnalysisAlbums(MediaLibraryAsyncContext& context)
3910 {
3911 if (!context.isAnalysisAlbum) {
3912 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
3913 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
3914 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_LPATH);
3915 context.fetchColumn.push_back(PhotoAlbumColumns::ALBUM_DATE_ADDED);
3916 }
3917 }
3918
3919 #ifdef MEDIALIBRARY_COMPATIBILITY
CompatGetPrivateAlbumExecute(napi_env env,void * data)3920 static void CompatGetPrivateAlbumExecute(napi_env env, void *data)
3921 {
3922 MediaLibraryTracer tracer;
3923 tracer.Start("CompatGetPrivateAlbumExecute");
3924
3925 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3926 string queryUri = URI_QUERY_PHOTO_ALBUM;
3927 Uri uri(queryUri);
3928 int err = 0;
3929 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, err,
3930 context->userId);
3931 if (resultSet == nullptr) {
3932 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", err);
3933 context->SaveError(err);
3934 return;
3935 }
3936 err = resultSet->GoToFirstRow();
3937 if (err != NativeRdb::E_OK) {
3938 context->SaveError(E_HAS_DB_ERROR);
3939 return;
3940 }
3941
3942 auto albumData = make_unique<AlbumAsset>();
3943 SetAlbumData(albumData.get(), resultSet, "");
3944 CompatSetAlbumCoverUri(context, albumData);
3945 context->albumNativeArray.push_back(move(albumData));
3946 }
3947
CompatGetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)3948 static void CompatGetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
3949 unique_ptr<JSAsyncContextOutput> &jsContext)
3950 {
3951 jsContext->status = true;
3952 napi_value albumArray = nullptr;
3953 CHECK_ARGS_RET_VOID(env, napi_create_array(env, &albumArray), JS_INNER_FAIL);
3954 for (size_t i = 0; i < context->albumNativeArray.size(); i++) {
3955 napi_value albumNapiObj = AlbumNapi::CreateAlbumNapi(env, context->albumNativeArray[i]);
3956 CHECK_ARGS_RET_VOID(env, napi_set_element(env, albumArray, i, albumNapiObj), JS_INNER_FAIL);
3957 }
3958 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3959 jsContext->data = albumArray;
3960 }
3961
CompatGetPrivateAlbumComplete(napi_env env,napi_status status,void * data)3962 static void CompatGetPrivateAlbumComplete(napi_env env, napi_status status, void *data)
3963 {
3964 MediaLibraryTracer tracer;
3965 tracer.Start("JSGetPhotoAlbumsCompleteCallback");
3966
3967 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
3968 auto jsContext = make_unique<JSAsyncContextOutput>();
3969 jsContext->status = false;
3970
3971 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3972 if (context->error != ERR_DEFAULT || context->albumNativeArray.empty()) {
3973 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3974 context->HandleError(env, jsContext->error);
3975 } else {
3976 CompatGetPhotoAlbumQueryResult(env, context, jsContext);
3977 }
3978
3979 tracer.Finish();
3980 if (context->work != nullptr) {
3981 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3982 context->work, *jsContext);
3983 }
3984 delete context;
3985 }
3986
ParseArgsGetPrivateAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)3987 napi_value ParseArgsGetPrivateAlbum(napi_env env, napi_callback_info info,
3988 unique_ptr<MediaLibraryAsyncContext> &context)
3989 {
3990 int32_t privateAlbumType = -1;
3991 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, context, privateAlbumType),
3992 JS_ERR_PARAMETER_INVALID);
3993 if (privateAlbumType != PrivateAlbumType::TYPE_FAVORITE && privateAlbumType != PrivateAlbumType::TYPE_TRASH) {
3994 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
3995 return nullptr;
3996 }
3997
3998 PhotoAlbumSubType subType = ANY;
3999 switch (privateAlbumType) {
4000 case PrivateAlbumType::TYPE_FAVORITE: {
4001 subType = PhotoAlbumSubType::FAVORITE;
4002 break;
4003 }
4004 case PrivateAlbumType::TYPE_TRASH: {
4005 subType = PhotoAlbumSubType::TRASH;
4006 break;
4007 }
4008 default: {
4009 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid private album type");
4010 return nullptr;
4011 }
4012 }
4013 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
4014 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subType));
4015 CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
4016 AddDefaultPhotoAlbumColumns(context->fetchColumn);
4017
4018 napi_value result = nullptr;
4019 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
4020 return result;
4021 }
4022
CompatGetPrivateAlbum(napi_env env,napi_callback_info info)4023 napi_value CompatGetPrivateAlbum(napi_env env, napi_callback_info info)
4024 {
4025 auto asyncContext = make_unique<MediaLibraryAsyncContext>();
4026 CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
4027
4028 SetUserIdFromObjectInfo(asyncContext);
4029 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CompatGetPrivateAlbum",
4030 CompatGetPrivateAlbumExecute, CompatGetPrivateAlbumComplete);
4031 }
4032 #endif // MEDIALIBRARY_COMPATIBILITY
4033
JSGetPrivateAlbum(napi_env env,napi_callback_info info)4034 napi_value MediaLibraryNapi::JSGetPrivateAlbum(napi_env env, napi_callback_info info)
4035 {
4036 #ifdef MEDIALIBRARY_COMPATIBILITY
4037 return CompatGetPrivateAlbum(env, info);
4038 #else
4039 napi_status status;
4040 napi_value result = nullptr;
4041 size_t argc = ARGS_TWO;
4042 napi_value argv[ARGS_TWO] = {0};
4043 napi_value thisVar = nullptr;
4044 const int32_t refCount = 1;
4045
4046 GET_JS_ARGS(env, info, argc, argv, thisVar);
4047 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
4048 napi_get_undefined(env, &result);
4049 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4050 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
4051 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4052 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4053 for (size_t i = PARAM0; i < argc; i++) {
4054 napi_valuetype valueType = napi_undefined;
4055 napi_typeof(env, argv[i], &valueType);
4056 if (i == PARAM0 && valueType == napi_number) {
4057 napi_get_value_int32(env, argv[i], &asyncContext->privateAlbumType);
4058 } else if (i == PARAM1 && valueType == napi_function) {
4059 napi_create_reference(env, argv[i], refCount, &asyncContext->callbackRef);
4060 break;
4061 } else {
4062 NAPI_ASSERT(env, false, "type mismatch");
4063 }
4064 }
4065
4066 SetUserIdFromObjectInfo(asyncContext);
4067 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPrivateAlbum",
4068 [](napi_env env, void *data) {
4069 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4070 GetAllSmartAlbumResultDataExecute(context);
4071 }, GetPrivateAlbumCallbackComplete);
4072 }
4073 return result;
4074 #endif
4075 }
4076
GetJSArgsForCreateSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)4077 napi_value GetJSArgsForCreateSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
4078 MediaLibraryAsyncContext &asyncContext)
4079 {
4080 const int32_t refCount = 1;
4081 napi_value result = nullptr;
4082 auto context = &asyncContext;
4083 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
4084 size_t res = 0;
4085 char buffer[PATH_MAX];
4086 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
4087 for (size_t i = 0; i < argc; i++) {
4088 napi_valuetype valueType = napi_undefined;
4089 napi_typeof(env, argv[i], &valueType);
4090 if (i == 0 && valueType == napi_number) {
4091 napi_get_value_int32(env, argv[i], &context->parentSmartAlbumId);
4092 } else if (i == PARAM1 && valueType == napi_string) {
4093 napi_get_value_string_utf8(env, argv[i], buffer, PATH_MAX, &res);
4094 } else if (i == PARAM2 && valueType == napi_function) {
4095 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
4096 break;
4097 } else {
4098 NAPI_ASSERT(env, false, "type mismatch");
4099 }
4100 }
4101 if (context->parentSmartAlbumId < 0) {
4102 NAPI_ASSERT(env, false, "type mismatch");
4103 }
4104 string smartName = string(buffer);
4105 if (smartName.empty()) {
4106 NAPI_ASSERT(env, false, "type mismatch");
4107 }
4108 context->valuesBucket.Put(SMARTALBUM_DB_NAME, smartName);
4109 napi_get_boolean(env, true, &result);
4110 return result;
4111 }
4112
JSCreateSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4113 static void JSCreateSmartAlbumCompleteCallback(napi_env env, napi_status status,
4114 MediaLibraryAsyncContext *context)
4115 {
4116 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4117 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4118 jsContext->status = false;
4119 if (context->error == ERR_DEFAULT) {
4120 if (context->smartAlbumData == nullptr) {
4121 NAPI_ERR_LOG("No albums found");
4122 napi_get_undefined(env, &jsContext->data);
4123 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4124 "No albums found");
4125 } else {
4126 jsContext->status = true;
4127 napi_value albumNapiObj = SmartAlbumNapi::CreateSmartAlbumNapi(env, context->smartAlbumData);
4128 jsContext->data = albumNapiObj;
4129 napi_get_undefined(env, &jsContext->error);
4130 }
4131 } else {
4132 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4133 "File asset creation failed");
4134 napi_get_undefined(env, &jsContext->data);
4135 }
4136 if (context->work != nullptr) {
4137 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4138 context->work, *jsContext);
4139 }
4140 delete context;
4141 }
4142
CreateSmartAlbumExecute(MediaLibraryAsyncContext * context)4143 static void CreateSmartAlbumExecute(MediaLibraryAsyncContext *context)
4144 {
4145 context->valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
4146 Uri CreateSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMOPRN + "/" +
4147 MEDIA_SMARTALBUMOPRN_CREATEALBUM);
4148 int retVal = UserFileClient::Insert(CreateSmartAlbumUri, context->valuesBucket);
4149 if (retVal < 0) {
4150 context->SaveError(retVal);
4151 NAPI_ERR_LOG("CreateSmartAlbum failed, retVal = %{private}d", retVal);
4152 return;
4153 }
4154 context->selection = SMARTALBUM_DB_ID + " = ?";
4155 context->selectionArgs = { to_string(retVal) };
4156 GetSmartAlbumResultDataExecute(context);
4157 // If parentSmartAlbumId == 0 do not need to add to smart map
4158 if (context->parentSmartAlbumId != 0) {
4159 DataShare::DataShareValuesBucket valuesBucket;
4160 valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->parentSmartAlbumId);
4161 valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ALBUM_ID, retVal);
4162 NAPI_DEBUG_LOG("CreateSmartAlbumExecute retVal = %{public}d, parentSmartAlbumId = %{public}d",
4163 retVal, context->parentSmartAlbumId);
4164 Uri addAsseturi(MEDIALIBRARY_DATA_URI +
4165 "/" + MEDIA_SMARTALBUMMAPOPRN + "/" + MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM);
4166 int32_t changedRows = UserFileClient::Insert(addAsseturi, valuesBucket);
4167 context->SaveError(changedRows);
4168 }
4169 }
4170
JSCreateSmartAlbum(napi_env env,napi_callback_info info)4171 napi_value MediaLibraryNapi::JSCreateSmartAlbum(napi_env env, napi_callback_info info)
4172 {
4173 napi_status status;
4174 napi_value result = nullptr;
4175 size_t argc = ARGS_THREE;
4176 napi_value argv[ARGS_THREE] = {0};
4177 napi_value thisVar = nullptr;
4178 napi_value resource = nullptr;
4179
4180 GET_JS_ARGS(env, info, argc, argv, thisVar);
4181 NAPI_ASSERT(env, (argc == ARGS_TWO || argc == ARGS_THREE), "requires 3 parameters maximum");
4182 napi_get_undefined(env, &result);
4183 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4184 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
4185 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4186 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4187 result = GetJSArgsForCreateSmartAlbum(env, argc, argv, *asyncContext);
4188 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
4189 SetUserIdFromObjectInfo(asyncContext);
4190 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4191 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCreateSmartAlbum", asyncContext);
4192 status = napi_create_async_work(
4193 env, nullptr, resource, [](napi_env env, void *data) {
4194 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4195 CreateSmartAlbumExecute(context);
4196 },
4197 reinterpret_cast<CompleteCallback>(JSCreateSmartAlbumCompleteCallback),
4198 static_cast<void *>(asyncContext.get()), &asyncContext->work);
4199 if (status != napi_ok) {
4200 napi_get_undefined(env, &result);
4201 } else {
4202 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4203 asyncContext.release();
4204 }
4205 }
4206 return result;
4207 }
4208
JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext * context)4209 static void JSDeleteSmartAlbumExecute(MediaLibraryAsyncContext *context)
4210 {
4211 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4212 if (context->smartAlbumId == TYPE_TRASH) {
4213 NAPI_ERR_LOG("Trash smartalbum can not be deleted");
4214 context->error = E_TRASHALBUM_CAN_NOT_DELETE;
4215 return;
4216 }
4217 if (context->smartAlbumId == TYPE_FAVORITE) {
4218 NAPI_ERR_LOG("Facorite smartalbum can not be deleted");
4219 context->error = E_FAVORITEALBUM_CAN_NOT_DELETE;
4220 return;
4221 }
4222 DataShare::DataShareValuesBucket valuesBucket;
4223 valuesBucket.Put(SMARTALBUM_DB_ID, context->smartAlbumId);
4224 Uri DeleteSmartAlbumUri(MEDIALIBRARY_DATA_URI + "/" +
4225 MEDIA_SMARTALBUMOPRN + "/" + MEDIA_SMARTALBUMOPRN_DELETEALBUM);
4226 int retVal = UserFileClient::Insert(DeleteSmartAlbumUri, valuesBucket);
4227 NAPI_DEBUG_LOG("JSDeleteSmartAlbumExecute retVal = %{private}d, smartAlbumId = %{private}d",
4228 retVal, context->smartAlbumId);
4229 if (retVal < 0) {
4230 context->SaveError(retVal);
4231 } else {
4232 context->retVal = retVal;
4233 }
4234 }
4235
GetJSArgsForDeleteSmartAlbum(napi_env env,size_t argc,const napi_value argv[],MediaLibraryAsyncContext & asyncContext)4236 napi_value GetJSArgsForDeleteSmartAlbum(napi_env env, size_t argc, const napi_value argv[],
4237 MediaLibraryAsyncContext &asyncContext)
4238 {
4239 napi_value result = nullptr;
4240 auto context = &asyncContext;
4241 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
4242 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
4243 for (size_t i = 0; i < argc; i++) {
4244 napi_valuetype valueType = napi_undefined;
4245 napi_typeof(env, argv[i], &valueType);
4246 if (i == 0 && valueType == napi_number) {
4247 napi_get_value_int32(env, argv[i], &context->smartAlbumId);
4248 } else if (i == PARAM1 && valueType == napi_function) {
4249 napi_create_reference(env, argv[i], DEFAULT_REFCOUNT, &context->callbackRef);
4250 break;
4251 } else {
4252 NAPI_ASSERT(env, false, "type mismatch");
4253 }
4254 }
4255 if (context->smartAlbumId < 0) {
4256 NAPI_ASSERT(env, false, "type mismatch");
4257 }
4258 napi_get_boolean(env, true, &result);
4259 return result;
4260 }
4261
JSDeleteSmartAlbumCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4262 static void JSDeleteSmartAlbumCompleteCallback(napi_env env, napi_status status,
4263 MediaLibraryAsyncContext *context)
4264 {
4265 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4266 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4267 jsContext->status = false;
4268 if (context->error == ERR_DEFAULT) {
4269 napi_create_int32(env, context->retVal, &jsContext->data);
4270 napi_get_undefined(env, &jsContext->error);
4271 jsContext->status = true;
4272 } else {
4273 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4274 "UserFileClient is invalid");
4275 napi_get_undefined(env, &jsContext->data);
4276 }
4277 if (context->work != nullptr) {
4278 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4279 context->work, *jsContext);
4280 }
4281 delete context;
4282 }
4283
JSDeleteSmartAlbum(napi_env env,napi_callback_info info)4284 napi_value MediaLibraryNapi::JSDeleteSmartAlbum(napi_env env, napi_callback_info info)
4285 {
4286 napi_status status;
4287 napi_value result = nullptr;
4288 size_t argc = ARGS_TWO;
4289 napi_value argv[ARGS_TWO] = {0};
4290 napi_value thisVar = nullptr;
4291 napi_value resource = nullptr;
4292
4293 GET_JS_ARGS(env, info, argc, argv, thisVar);
4294 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
4295 napi_get_undefined(env, &result);
4296 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4297 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4298 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4299 result = GetJSArgsForDeleteSmartAlbum(env, argc, argv, *asyncContext);
4300 CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
4301 SetUserIdFromObjectInfo(asyncContext);
4302 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4303 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSDeleteSmartAlbum", asyncContext);
4304 status = napi_create_async_work(
4305 env, nullptr, resource, [](napi_env env, void *data) {
4306 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4307 JSDeleteSmartAlbumExecute(context);
4308 },
4309 reinterpret_cast<CompleteCallback>(JSDeleteSmartAlbumCompleteCallback),
4310 static_cast<void *>(asyncContext.get()), &asyncContext->work);
4311 if (status != napi_ok) {
4312 napi_get_undefined(env, &result);
4313 } else {
4314 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4315 asyncContext.release();
4316 }
4317 }
4318 return result;
4319 }
4320
SetValueUtf8String(const napi_env & env,const char * fieldStr,const char * str,napi_value & result)4321 static napi_status SetValueUtf8String(const napi_env& env, const char* fieldStr, const char* str, napi_value& result)
4322 {
4323 napi_value value;
4324 napi_status status = napi_create_string_utf8(env, str, NAPI_AUTO_LENGTH, &value);
4325 if (status != napi_ok) {
4326 NAPI_ERR_LOG("Set value create utf8 string error! field: %{public}s", fieldStr);
4327 return status;
4328 }
4329 status = napi_set_named_property(env, result, fieldStr, value);
4330 if (status != napi_ok) {
4331 NAPI_ERR_LOG("Set utf8 string named property error! field: %{public}s", fieldStr);
4332 }
4333 return status;
4334 }
4335
SetValueBool(const napi_env & env,const char * fieldStr,const bool boolvalue,napi_value & result)4336 static napi_status SetValueBool(const napi_env& env, const char* fieldStr, const bool boolvalue, napi_value& result)
4337 {
4338 napi_value value = nullptr;
4339 napi_status status = napi_get_boolean(env, boolvalue, &value);
4340 if (status != napi_ok) {
4341 NAPI_ERR_LOG("Set value create boolean error! field: %{public}s", fieldStr);
4342 return status;
4343 }
4344 status = napi_set_named_property(env, result, fieldStr, value);
4345 if (status != napi_ok) {
4346 NAPI_ERR_LOG("Set boolean named property error! field: %{public}s", fieldStr);
4347 }
4348 return status;
4349 }
4350
PeerInfoToJsArray(const napi_env & env,const vector<unique_ptr<PeerInfo>> & vecPeerInfo,const int32_t idx,napi_value & arrayResult)4351 static void PeerInfoToJsArray(const napi_env &env, const vector<unique_ptr<PeerInfo>> &vecPeerInfo,
4352 const int32_t idx, napi_value &arrayResult)
4353 {
4354 if (idx >= (int32_t) vecPeerInfo.size()) {
4355 return;
4356 }
4357 auto info = vecPeerInfo[idx].get();
4358 if (info == nullptr) {
4359 return;
4360 }
4361 napi_value result = nullptr;
4362 napi_create_object(env, &result);
4363 SetValueUtf8String(env, "deviceName", info->deviceName.c_str(), result);
4364 SetValueUtf8String(env, "networkId", info->networkId.c_str(), result);
4365 SetValueInt32(env, "deviceTypeId", (int) info->deviceTypeId, result);
4366 SetValueBool(env, "isOnline", info->isOnline, result);
4367
4368 napi_status status = napi_set_element(env, arrayResult, idx, result);
4369 if (status != napi_ok) {
4370 NAPI_ERR_LOG("PeerInfo To JsArray set element error: %d", status);
4371 }
4372 }
4373
QueryActivePeer(int & errCode,MediaLibraryAsyncContext * context,string & uriType)4374 shared_ptr<DataShare::DataShareResultSet> QueryActivePeer(int &errCode,
4375 MediaLibraryAsyncContext *context, string &uriType)
4376 {
4377 vector<string> columns;
4378 DataShare::DataSharePredicates predicates;
4379 Uri uri(uriType);
4380 if (uriType == MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE) {
4381 string strQueryCondition = DEVICE_DB_DATE_MODIFIED + " = 0";
4382 predicates.SetWhereClause(strQueryCondition);
4383 } else if (uriType == MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE) {
4384 predicates.SetWhereClause(context->selection);
4385 }
4386 predicates.SetWhereArgs(context->selectionArgs);
4387 return UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
4388 }
4389
JSGetActivePeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4390 void JSGetActivePeersCompleteCallback(napi_env env, napi_status status,
4391 MediaLibraryAsyncContext *context)
4392 {
4393 napi_value jsPeerInfoArray = nullptr;
4394 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4395 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4396 jsContext->status = false;
4397 napi_get_undefined(env, &jsContext->data);
4398 string uriType = MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYACTIVEDEVICE;
4399 int errCode = 0;
4400 shared_ptr<DataShare::DataShareResultSet> resultSet = QueryActivePeer(errCode, context, uriType);
4401 if (resultSet == nullptr) {
4402 NAPI_ERR_LOG("JSGetActivePeers resultSet is null, errCode is %{public}d", errCode);
4403 delete context;
4404 return;
4405 }
4406
4407 vector<unique_ptr<PeerInfo>> peerInfoArray;
4408 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
4409 unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
4410 if (peerInfo != nullptr) {
4411 peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
4412 TYPE_STRING));
4413 peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
4414 TYPE_STRING));
4415 peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
4416 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
4417 peerInfo->isOnline = true;
4418 peerInfoArray.push_back(move(peerInfo));
4419 }
4420 }
4421
4422 if (napi_create_array(env, &jsPeerInfoArray) == napi_ok) {
4423 for (size_t i = 0; i < peerInfoArray.size(); ++i) {
4424 PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
4425 }
4426
4427 jsContext->data = jsPeerInfoArray;
4428 napi_get_undefined(env, &jsContext->error);
4429 jsContext->status = true;
4430 }
4431
4432 if (context->work != nullptr) {
4433 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4434 context->work, *jsContext);
4435 }
4436
4437 delete context;
4438 }
4439
JSGetAllPeersCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4440 void JSGetAllPeersCompleteCallback(napi_env env, napi_status status,
4441 MediaLibraryAsyncContext *context)
4442 {
4443 napi_value jsPeerInfoArray = nullptr;
4444 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4445 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4446 jsContext->status = false;
4447 napi_get_undefined(env, &jsContext->data);
4448 string uriType = MEDIALIBRARY_DATA_URI + "/" + MEDIA_DEVICE_QUERYALLDEVICE;
4449 int errCode = 0;
4450 shared_ptr<DataShare::DataShareResultSet> resultSet = QueryActivePeer(errCode, context, uriType);
4451 if (resultSet == nullptr) {
4452 NAPI_ERR_LOG("JSGetAllPeers resultSet is null, errCode is %{public}d", errCode);
4453 delete context;
4454 return;
4455 }
4456
4457 vector<unique_ptr<PeerInfo>> peerInfoArray;
4458 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
4459 unique_ptr<PeerInfo> peerInfo = make_unique<PeerInfo>();
4460 if (peerInfo != nullptr) {
4461 peerInfo->deviceName = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NAME, resultSet,
4462 TYPE_STRING));
4463 peerInfo->networkId = get<string>(ResultSetUtils::GetValFromColumn(DEVICE_DB_NETWORK_ID, resultSet,
4464 TYPE_STRING));
4465 peerInfo->deviceTypeId = (DistributedHardware::DmDeviceType)
4466 (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_TYPE, resultSet, TYPE_INT32)));
4467 peerInfo->isOnline = (get<int32_t>(ResultSetUtils::GetValFromColumn(DEVICE_DB_DATE_MODIFIED, resultSet,
4468 TYPE_INT32)) == 0);
4469 peerInfoArray.push_back(move(peerInfo));
4470 }
4471 }
4472
4473 if (napi_create_array(env, &jsPeerInfoArray) == napi_ok) {
4474 for (size_t i = 0; i < peerInfoArray.size(); ++i) {
4475 PeerInfoToJsArray(env, peerInfoArray, i, jsPeerInfoArray);
4476 }
4477
4478 jsContext->data = jsPeerInfoArray;
4479 napi_get_undefined(env, &jsContext->error);
4480 jsContext->status = true;
4481 }
4482
4483 if (context->work != nullptr) {
4484 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4485 context->work, *jsContext);
4486 }
4487 delete context;
4488 }
4489
JSGetActivePeers(napi_env env,napi_callback_info info)4490 napi_value MediaLibraryNapi::JSGetActivePeers(napi_env env, napi_callback_info info)
4491 {
4492 napi_status status;
4493 napi_value result = nullptr;
4494 const int32_t refCount = 1;
4495 size_t argc = ARGS_ONE;
4496 napi_value argv[ARGS_ONE] = {0};
4497 napi_value thisVar = nullptr;
4498
4499 MediaLibraryTracer tracer;
4500 tracer.Start("JSGetActivePeers");
4501
4502 GET_JS_ARGS(env, info, argc, argv, thisVar);
4503 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
4504 napi_get_undefined(env, &result);
4505
4506 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4507 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4508 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4509 if (argc == ARGS_ONE) {
4510 GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
4511 }
4512 SetUserIdFromObjectInfo(asyncContext);
4513
4514 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4515
4516 NAPI_CALL(env, napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo)));
4517 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4518 MediaLibraryAsyncContext *context = asyncContext.get();
4519 std::function<void()> task = [env, status, context]() {
4520 JSGetActivePeersCompleteCallback(env, status, context);
4521 };
4522
4523 status = napi_send_event(env, task, napi_eprio_immediate);
4524 if (status != napi_ok) {
4525 napi_get_undefined(env, &result);
4526 } else {
4527 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4528 asyncContext.release();
4529 }
4530 }
4531
4532 return result;
4533 }
4534
JSGetAllPeers(napi_env env,napi_callback_info info)4535 napi_value MediaLibraryNapi::JSGetAllPeers(napi_env env, napi_callback_info info)
4536 {
4537 napi_status status;
4538 napi_value result = nullptr;
4539 const int32_t refCount = 1;
4540 size_t argc = ARGS_ONE;
4541 napi_value argv[ARGS_ONE] = {0};
4542 napi_value thisVar = nullptr;
4543
4544 MediaLibraryTracer tracer;
4545 tracer.Start("JSGetAllPeers");
4546
4547 GET_JS_ARGS(env, info, argc, argv, thisVar);
4548 NAPI_ASSERT(env, argc <= ARGS_ONE, "requires 1 parameter maximum");
4549 napi_get_undefined(env, &result);
4550
4551 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4552 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4553 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4554 if (argc == ARGS_ONE) {
4555 GET_JS_ASYNC_CB_REF(env, argv[PARAM0], refCount, asyncContext->callbackRef);
4556 }
4557 SetUserIdFromObjectInfo(asyncContext);
4558
4559 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4560 MediaLibraryAsyncContext *context = asyncContext.get();
4561 std::function<void()> task = [env, status, context]() {
4562 JSGetAllPeersCompleteCallback(env, status, context);
4563 };
4564 status = napi_send_event(env, task, napi_eprio_immediate);
4565 if (status != napi_ok) {
4566 napi_get_undefined(env, &result);
4567 } else {
4568 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4569 asyncContext.release();
4570 }
4571 }
4572
4573 return result;
4574 }
4575
CloseAsset(MediaLibraryAsyncContext * context,string uri)4576 static int32_t CloseAsset(MediaLibraryAsyncContext *context, string uri)
4577 {
4578 string abilityUri = MEDIALIBRARY_DATA_URI;
4579 Uri closeAssetUri(URI_CLOSE_FILE);
4580 context->valuesBucket.Clear();
4581 context->valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
4582 int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
4583 NAPI_DEBUG_LOG("File close asset %{public}d", ret);
4584 if (ret != E_SUCCESS) {
4585 context->error = ret;
4586 NAPI_ERR_LOG("File close asset fail, %{public}d", ret);
4587 }
4588 return ret;
4589 }
4590
GetStoreMediaAssetUri(MediaLibraryAsyncContext * context,string & uri)4591 static void GetStoreMediaAssetUri(MediaLibraryAsyncContext *context, string &uri)
4592 {
4593 bool isValid = false;
4594 string relativePath = context->valuesBucket.Get(MEDIA_DATA_DB_RELATIVE_PATH, isValid);
4595 if (relativePath.find(CAMERA_DIR_VALUES) == 0 ||
4596 relativePath.find(VIDEO_DIR_VALUES) == 0 ||
4597 relativePath.find(PIC_DIR_VALUES) == 0) {
4598 uri = URI_CREATE_PHOTO;
4599 } else if (relativePath.find(AUDIO_DIR_VALUES) == 0) {
4600 uri = URI_CREATE_AUDIO;
4601 } else {
4602 uri = URI_CREATE_FILE;
4603 }
4604 }
4605
JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext * context)4606 static void JSGetStoreMediaAssetExecute(MediaLibraryAsyncContext *context)
4607 {
4608 string realPath;
4609 if (!PathToRealPath(context->storeMediaSrc, realPath)) {
4610 NAPI_ERR_LOG("src path is not exist, %{public}d", errno);
4611 context->error = JS_ERR_NO_SUCH_FILE;
4612 return;
4613 }
4614 context->error = JS_E_RELATIVEPATH;
4615 int32_t srcFd = open(realPath.c_str(), O_RDWR);
4616 CHECK_IF_EQUAL(srcFd != -1, "src path open fail, %{public}d", errno);
4617 struct stat statSrc;
4618 if (fstat(srcFd, &statSrc) == -1) {
4619 close(srcFd);
4620 NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
4621 return;
4622 }
4623 string uriString;
4624 GetStoreMediaAssetUri(context, uriString);
4625 Uri createFileUri(uriString);
4626 int index = UserFileClient::Insert(createFileUri, context->valuesBucket);
4627 if (index < 0) {
4628 close(srcFd);
4629 NAPI_ERR_LOG("storeMedia fail, file already exist %{public}d", index);
4630 return;
4631 }
4632 SetFileAssetByIdV9(index, "", context);
4633 if (context->fileAsset == nullptr) {
4634 close(srcFd);
4635 NAPI_ERR_LOG("JSGetStoreMediaAssetExecute: context->fileAsset is nullptr");
4636 return;
4637 }
4638 LogMedialibraryAPI(context->fileAsset->GetUri());
4639 Uri openFileUri(context->fileAsset->GetUri());
4640 int32_t destFd = UserFileClient::OpenFile(openFileUri, MEDIA_FILEMODE_READWRITE, context->userId);
4641 if (destFd < 0) {
4642 context->error = destFd;
4643 NAPI_DEBUG_LOG("File open asset failed");
4644 close(srcFd);
4645 return;
4646 }
4647 if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
4648 close(srcFd);
4649 close(destFd);
4650 CloseAsset(context, context->fileAsset->GetUri());
4651 NAPI_ERR_LOG("copy file fail %{public}d ", errno);
4652 return;
4653 }
4654 close(srcFd);
4655 close(destFd);
4656 CloseAsset(context, context->fileAsset->GetUri());
4657 context->error = ERR_DEFAULT;
4658 }
4659
JSGetStoreMediaAssetCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4660 static void JSGetStoreMediaAssetCompleteCallback(napi_env env, napi_status status,
4661 MediaLibraryAsyncContext *context)
4662 {
4663 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4664 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4665 CHECK_NULL_PTR_RETURN_VOID(jsContext, "Async context is null");
4666 jsContext->status = false;
4667 napi_get_undefined(env, &jsContext->data);
4668 if (context->error != ERR_DEFAULT) {
4669 NAPI_ERR_LOG("JSGetStoreMediaAssetCompleteCallback failed %{public}d ", context->error);
4670 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4671 "storeMediaAsset fail");
4672 } else {
4673 napi_create_string_utf8(env, context->fileAsset->GetUri().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4674 jsContext->status = true;
4675 napi_get_undefined(env, &jsContext->error);
4676 }
4677
4678 if (context->work != nullptr) {
4679 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4680 context->work, *jsContext);
4681 }
4682 delete context;
4683 }
4684
ConvertMediaType(const string & mimeType)4685 static int ConvertMediaType(const string &mimeType)
4686 {
4687 string res;
4688 // mimeType 'image/gif', 'video/mp4', 'audio/mp3', 'file/pdf'
4689 size_t slash = mimeType.find('/');
4690 if (slash != string::npos) {
4691 res = mimeType.substr(0, slash);
4692 if (res.empty()) {
4693 return MediaType::MEDIA_TYPE_FILE;
4694 }
4695 }
4696 if (res == "image") {
4697 return MediaType::MEDIA_TYPE_IMAGE;
4698 } else if (res == "video") {
4699 return MediaType::MEDIA_TYPE_VIDEO;
4700 } else if (res == "audio") {
4701 return MediaType::MEDIA_TYPE_AUDIO;
4702 }
4703 return MediaType::MEDIA_TYPE_FILE;
4704 }
4705
GetStoreMediaAssetProper(napi_env env,napi_value param,const string & proper,string & res)4706 static bool GetStoreMediaAssetProper(napi_env env, napi_value param, const string &proper, string &res)
4707 {
4708 napi_value value = MediaLibraryNapiUtils::GetPropertyValueByName(env, param, proper.c_str());
4709 if (value == nullptr) {
4710 NAPI_ERR_LOG("GetPropertyValueByName %{public}s fail", proper.c_str());
4711 return false;
4712 }
4713 unique_ptr<char[]> tmp;
4714 bool succ;
4715 tie(succ, tmp, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, value);
4716 if (!succ) {
4717 NAPI_ERR_LOG("param %{public}s fail", proper.c_str());
4718 return false;
4719 }
4720 res = string(tmp.get());
4721 return true;
4722 }
4723
GetDefaultDirectory(int mediaType)4724 static string GetDefaultDirectory(int mediaType)
4725 {
4726 string relativePath;
4727 if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
4728 relativePath = "Pictures/";
4729 } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
4730 relativePath = "Videos/";
4731 } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
4732 relativePath = "Audios/";
4733 } else {
4734 relativePath = DOCS_PATH + DOC_DIR_VALUES;
4735 }
4736 return relativePath;
4737 }
4738
GetStoreMediaAssetArgs(napi_env env,napi_value param,MediaLibraryAsyncContext & asyncContext)4739 static napi_value GetStoreMediaAssetArgs(napi_env env, napi_value param,
4740 MediaLibraryAsyncContext &asyncContext)
4741 {
4742 auto context = &asyncContext;
4743 if (!GetStoreMediaAssetProper(env, param, "src", context->storeMediaSrc)) {
4744 NAPI_ERR_LOG("param get fail");
4745 return nullptr;
4746 }
4747 string fileName = MediaFileUtils::GetFileName(context->storeMediaSrc);
4748 if (fileName.empty() || (fileName.at(0) == '.')) {
4749 NAPI_ERR_LOG("src file name is not proper");
4750 context->error = JS_E_RELATIVEPATH;
4751 return nullptr;
4752 };
4753 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, fileName);
4754 string mimeType;
4755 if (!GetStoreMediaAssetProper(env, param, "mimeType", mimeType)) {
4756 NAPI_ERR_LOG("param get fail");
4757 return nullptr;
4758 }
4759 auto mediaType = ConvertMediaType(mimeType);
4760 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
4761 string relativePath;
4762 if (!GetStoreMediaAssetProper(env, param, "relativePath", relativePath)) {
4763 NAPI_DEBUG_LOG("optional relativePath param empty");
4764 relativePath = GetDefaultDirectory(mediaType);
4765 }
4766 relativePath = MediaFileUtils::AddDocsToRelativePath(relativePath);
4767 context->valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, relativePath);
4768 NAPI_DEBUG_LOG("src:%{private}s mime:%{private}s relp:%{private}s filename:%{private}s",
4769 context->storeMediaSrc.c_str(), mimeType.c_str(), relativePath.c_str(), fileName.c_str());
4770 napi_value result = nullptr;
4771 napi_get_undefined(env, &result);
4772 return result;
4773 }
4774
JSStoreMediaAsset(napi_env env,napi_callback_info info)4775 napi_value MediaLibraryNapi::JSStoreMediaAsset(napi_env env, napi_callback_info info)
4776 {
4777 size_t argc = ARGS_TWO;
4778 napi_value argv[ARGS_TWO] = {0};
4779 napi_value thisVar = nullptr;
4780 GET_JS_ARGS(env, info, argc, argv, thisVar);
4781 napi_value result = nullptr;
4782 napi_get_undefined(env, &result);
4783 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4784 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4785 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4786 if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
4787 napi_value res = GetStoreMediaAssetArgs(env, argv[PARAM0], *asyncContext);
4788 CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, res, "Failed to obtain arguments");
4789 if (argc == ARGS_TWO) {
4790 const int32_t refCount = 1;
4791 GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4792 }
4793 SetUserIdFromObjectInfo(asyncContext);
4794 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4795 napi_value resource = nullptr;
4796 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStoreMediaAsset", asyncContext);
4797 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4798 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4799 JSGetStoreMediaAssetExecute(context);
4800 },
4801 reinterpret_cast<CompleteCallback>(JSGetStoreMediaAssetCompleteCallback),
4802 static_cast<void *>(asyncContext.get()), &asyncContext->work);
4803 if (status != napi_ok) {
4804 napi_get_undefined(env, &result);
4805 } else {
4806 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4807 asyncContext.release();
4808 }
4809 }
4810 return result;
4811 }
4812
CreateAsyncCallbackInfo(napi_env env)4813 static Ability *CreateAsyncCallbackInfo(napi_env env)
4814 {
4815 if (env == nullptr) {
4816 NAPI_ERR_LOG("env == nullptr.");
4817 return nullptr;
4818 }
4819 napi_status ret;
4820 napi_value global = 0;
4821 const napi_extended_error_info *errorInfo = nullptr;
4822 ret = napi_get_global(env, &global);
4823 if (ret != napi_ok) {
4824 napi_get_last_error_info(env, &errorInfo);
4825 NAPI_ERR_LOG("get_global=%{public}d err:%{public}s", ret, errorInfo->error_message);
4826 }
4827 napi_value abilityObj = 0;
4828 ret = napi_get_named_property(env, global, "ability", &abilityObj);
4829 if (ret != napi_ok) {
4830 napi_get_last_error_info(env, &errorInfo);
4831 NAPI_ERR_LOG("get_named_property=%{public}d e:%{public}s", ret, errorInfo->error_message);
4832 }
4833 Ability *ability = nullptr;
4834 ret = napi_get_value_external(env, abilityObj, (void **)&ability);
4835 if (ret != napi_ok) {
4836 napi_get_last_error_info(env, &errorInfo);
4837 NAPI_ERR_LOG("get_value_external=%{public}d e:%{public}s", ret, errorInfo->error_message);
4838 }
4839 return ability;
4840 }
4841
GetImagePreviewArgsUri(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4842 static napi_value GetImagePreviewArgsUri(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4843 {
4844 uint32_t arraySize = 0;
4845 if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
4846 NAPI_ERR_LOG("GetImagePreviewArgs get args fail, not array");
4847 return nullptr;
4848 }
4849 string uri = "";
4850 for (uint32_t i = 0; i < arraySize; i++) {
4851 napi_value jsValue = nullptr;
4852 if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
4853 NAPI_ERR_LOG("GetImagePreviewArgs get args fail");
4854 return nullptr;
4855 }
4856 unique_ptr<char[]> inputStr;
4857 bool succ;
4858 tie(succ, inputStr, ignore) = MediaLibraryNapiUtils::ToUTF8String(env, jsValue);
4859 if (!succ) {
4860 NAPI_ERR_LOG("GetImagePreviewArgs get string fail");
4861 return nullptr;
4862 }
4863 uri += MediaLibraryNapiUtils::TransferUri(string(inputStr.get()));
4864 uri += "?";
4865 }
4866 context.uri = uri.substr(0, uri.length() - 1);
4867 NAPI_DEBUG_LOG("GetImagePreviewArgs res %{private}s", context.uri.c_str());
4868 napi_value res;
4869 napi_get_undefined(env, &res);
4870 return res;
4871 }
4872
GetImagePreviewArgsNum(napi_env env,napi_value param,MediaLibraryAsyncContext & context)4873 static napi_value GetImagePreviewArgsNum(napi_env env, napi_value param, MediaLibraryAsyncContext &context)
4874 {
4875 context.imagePreviewIndex = 0;
4876 napi_valuetype valueType = napi_undefined;
4877 napi_typeof(env, param, &valueType);
4878 if (valueType != napi_number) {
4879 NAPI_ERR_LOG("not napi value");
4880 return nullptr;
4881 }
4882 if (napi_get_value_int32(env, param, &context.imagePreviewIndex) != napi_ok) {
4883 NAPI_ERR_LOG("get property value fail");
4884 }
4885 NAPI_ERR_LOG("GetImagePreviewArgs num %{public}d", context.imagePreviewIndex);
4886 napi_value res;
4887 napi_get_undefined(env, &res);
4888 return res;
4889 }
4890
JSStartImagePreviewExecute(MediaLibraryAsyncContext * context)4891 static void JSStartImagePreviewExecute(MediaLibraryAsyncContext *context)
4892 {
4893 if (context->ability_ == nullptr) {
4894 NAPI_ERR_LOG("ability_ is not exist");
4895 context->error = ERR_INVALID_OUTPUT;
4896 return;
4897 }
4898 Want want;
4899 want.SetType("image/jpeg");
4900 want.SetAction("ohos.want.action.viewData");
4901 want.SetUri(context->uri);
4902 want.SetParam("viewIndex", context->imagePreviewIndex + 1);
4903 context->error = context->ability_->StartAbility(want);
4904 }
4905
JSGetJSStartImagePreviewCompleteCallback(napi_env env,napi_status status,MediaLibraryAsyncContext * context)4906 static void JSGetJSStartImagePreviewCompleteCallback(napi_env env, napi_status status,
4907 MediaLibraryAsyncContext *context)
4908 {
4909 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4910 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4911 CHECK_NULL_PTR_RETURN_VOID(jsContext, "get jsContext failed");
4912 jsContext->status = true;
4913 napi_get_undefined(env, &jsContext->data);
4914 if (context->error != 0) {
4915 jsContext->status = false;
4916 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4917 "startImagePreview currently fail");
4918 }
4919 if (context->work != nullptr) {
4920 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4921 context->work, *jsContext);
4922 }
4923 delete context;
4924 }
4925
JSStartImagePreview(napi_env env,napi_callback_info info)4926 napi_value MediaLibraryNapi::JSStartImagePreview(napi_env env, napi_callback_info info)
4927 {
4928 size_t argc = ARGS_THREE;
4929 napi_value argv[ARGS_THREE] = {0};
4930 napi_value thisVar = nullptr;
4931 GET_JS_ARGS(env, info, argc, argv, thisVar);
4932 napi_value result = nullptr;
4933 napi_get_undefined(env, &result);
4934 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
4935 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "Failed to get asyncContext");
4936 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
4937 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
4938 napi_value res = GetImagePreviewArgsUri(env, argv[PARAM0], *asyncContext);
4939 CHECK_NULL_PTR_RETURN_UNDEFINED(env, res, result, "Failed to obtain arguments uri");
4940 GetImagePreviewArgsNum(env, argv[PARAM1], *asyncContext);
4941 asyncContext->ability_ = CreateAsyncCallbackInfo(env);
4942 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->ability_, result, "Failed to obtain ability");
4943 const int32_t refCount = 1;
4944 if (argc == ARGS_THREE) {
4945 GET_JS_ASYNC_CB_REF(env, argv[PARAM2], refCount, asyncContext->callbackRef);
4946 } else if (argc == ARGS_TWO && MediaLibraryNapiUtils::CheckJSArgsTypeAsFunc(env, argv[PARAM1])) {
4947 GET_JS_ASYNC_CB_REF(env, argv[PARAM1], refCount, asyncContext->callbackRef);
4948 }
4949 SetUserIdFromObjectInfo(asyncContext);
4950 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
4951 napi_value resource = nullptr;
4952 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSStartImagePreview", asyncContext);
4953 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
4954 auto context = static_cast<MediaLibraryAsyncContext *>(data);
4955 JSStartImagePreviewExecute(context);
4956 },
4957 reinterpret_cast<CompleteCallback>(JSGetJSStartImagePreviewCompleteCallback),
4958 static_cast<void *>(asyncContext.get()), &asyncContext->work);
4959 if (status != napi_ok) {
4960 napi_get_undefined(env, &result);
4961 } else {
4962 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
4963 asyncContext.release();
4964 }
4965 }
4966 return result;
4967 }
4968
CheckCreateOption(MediaLibraryAsyncContext & context)4969 static napi_status CheckCreateOption(MediaLibraryAsyncContext &context)
4970 {
4971 bool isValid = false;
4972 int32_t subtype = context.valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
4973 string cameraShotKey = context.valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
4974 if (isValid) {
4975 if (cameraShotKey.size() < CAMERA_SHOT_KEY_SIZE) {
4976 NAPI_ERR_LOG("cameraShotKey is not null with but is less than CAMERA_SHOT_KEY_SIZE");
4977 return napi_invalid_arg;
4978 }
4979 if (subtype == static_cast<int32_t>(PhotoSubType::SCREENSHOT)) {
4980 NAPI_ERR_LOG("cameraShotKey is not null with subtype is SCREENSHOT");
4981 return napi_invalid_arg;
4982 } else {
4983 context.valuesBucket.Put(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::CAMERA));
4984 }
4985 }
4986
4987 return napi_ok;
4988 }
4989
ParsePhotoAssetCreateOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)4990 static napi_status ParsePhotoAssetCreateOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
4991 {
4992 for (const auto &iter : PHOTO_CREATE_OPTIONS_PARAM) {
4993 string param = iter.first;
4994 bool present = false;
4995 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
4996 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
4997 if (!present) {
4998 continue;
4999 }
5000 napi_value value;
5001 result = napi_get_named_property(env, arg, param.c_str(), &value);
5002 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5003 napi_valuetype valueType = napi_undefined;
5004 result = napi_typeof(env, value, &valueType);
5005 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5006 if (valueType == napi_number) {
5007 int32_t number = 0;
5008 result = napi_get_value_int32(env, value, &number);
5009 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5010 context.valuesBucket.Put(iter.second, number);
5011 } else if (valueType == napi_boolean) {
5012 bool isTrue = false;
5013 result = napi_get_value_bool(env, value, &isTrue);
5014 CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
5015 context.valuesBucket.Put(iter.second, isTrue);
5016 } else if (valueType == napi_string) {
5017 char buffer[ARG_BUF_SIZE];
5018 size_t res = 0;
5019 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5020 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5021 context.valuesBucket.Put(iter.second, string(buffer));
5022 } else if (valueType == napi_undefined || valueType == napi_null) {
5023 continue;
5024 } else {
5025 NAPI_ERR_LOG("valueType %{public}d is unaccepted", static_cast<int>(valueType));
5026 return napi_invalid_arg;
5027 }
5028 }
5029
5030 return CheckCreateOption(context);
5031 }
5032
ParseCreateOptions(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)5033 static napi_status ParseCreateOptions(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
5034 {
5035 for (const auto &iter : CREATE_OPTIONS_PARAM) {
5036 string param = iter.first;
5037 bool present = false;
5038 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
5039 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
5040 if (!present) {
5041 continue;
5042 }
5043 napi_value value;
5044 result = napi_get_named_property(env, arg, param.c_str(), &value);
5045 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5046 napi_valuetype valueType = napi_undefined;
5047 result = napi_typeof(env, value, &valueType);
5048 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5049 if (valueType == napi_number) {
5050 int32_t number = 0;
5051 result = napi_get_value_int32(env, value, &number);
5052 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5053 context.valuesBucket.Put(iter.second, number);
5054 } else if (valueType == napi_boolean) {
5055 bool isTrue = false;
5056 result = napi_get_value_bool(env, value, &isTrue);
5057 CHECK_COND_RET(result == napi_ok, result, "failed to get bool");
5058 context.valuesBucket.Put(iter.second, isTrue);
5059 } else if (valueType == napi_string) {
5060 char buffer[ARG_BUF_SIZE];
5061 size_t res = 0;
5062 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5063 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5064 context.valuesBucket.Put(iter.second, string(buffer));
5065 } else if (valueType == napi_undefined || valueType == napi_null) {
5066 continue;
5067 } else {
5068 NAPI_ERR_LOG("ParseCreateOptions failed, valueType %{public}d is unaccepted",
5069 static_cast<int>(valueType));
5070 return napi_invalid_arg;
5071 }
5072 }
5073
5074 return napi_ok;
5075 }
5076
ParseArgsCreatePhotoAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5077 static napi_value ParseArgsCreatePhotoAssetSystem(napi_env env, napi_callback_info info,
5078 unique_ptr<MediaLibraryAsyncContext> &context)
5079 {
5080 /* Parse the first argument into displayName */
5081 napi_valuetype valueType;
5082 MediaType mediaType;
5083 string displayName;
5084 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
5085 napi_ok, "Failed to get displayName");
5086 mediaType = MediaFileUtils::GetMediaType(displayName);
5087 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
5088 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
5089
5090 /* Parse the second argument into albumUri if exists */
5091 string albumUri;
5092 if ((context->argc >= ARGS_TWO)) {
5093 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ONE], &valueType) == napi_ok, "Failed to get napi type");
5094 if (valueType == napi_string) {
5095 if (MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri) == napi_ok) {
5096 context->valuesBucket.Put(MEDIA_DATA_DB_ALARM_URI, albumUri);
5097 }
5098 } else if (valueType == napi_object) {
5099 NAPI_ASSERT(env, ParsePhotoAssetCreateOption(env, context->argv[ARGS_ONE], *context) == napi_ok,
5100 "Parse asset create option failed");
5101 }
5102 }
5103
5104 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5105 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
5106
5107 napi_value result = nullptr;
5108 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5109 return result;
5110 }
5111
ParseArgsCreatePhotoAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5112 static napi_value ParseArgsCreatePhotoAssetComponent(napi_env env, napi_callback_info info,
5113 unique_ptr<MediaLibraryAsyncContext> &context)
5114 {
5115 /* Parse the first argument into displayName */
5116 napi_valuetype valueType;
5117 MediaType mediaType;
5118 int32_t type = 0;
5119 NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
5120 "Failed to get type value");
5121 mediaType = static_cast<MediaType>(type);
5122 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO), "invalid file type");
5123
5124 /* Parse the second argument into albumUri if exists */
5125 string extension;
5126 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extension) ==
5127 napi_ok, "Failed to get extension");
5128 CHECK_COND_WITH_MESSAGE(env, mediaType == MediaFileUtils::GetMediaType("." + extension),
5129 "Failed to check extension");
5130 context->valuesBucket.Put(ASSET_EXTENTION, extension);
5131
5132 /* Parse the third argument into albumUri if exists */
5133 if (context->argc >= ARGS_THREE) {
5134 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
5135 if (valueType == napi_object) {
5136 NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
5137 "Parse asset create option failed");
5138 } else if (valueType != napi_function) {
5139 NAPI_ERR_LOG("Napi type is wrong in create options");
5140 return nullptr;
5141 }
5142 }
5143
5144 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5145
5146 napi_value result = nullptr;
5147 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5148 return result;
5149 }
5150
ParseArgsCreatePhotoAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5151 static napi_value ParseArgsCreatePhotoAsset(napi_env env, napi_callback_info info,
5152 unique_ptr<MediaLibraryAsyncContext> &context)
5153 {
5154 constexpr size_t minArgs = ARGS_ONE;
5155 constexpr size_t maxArgs = ARGS_FOUR;
5156 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5157 napi_ok, "Failed to get object info");
5158
5159 napi_valuetype valueType;
5160 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
5161 if (valueType == napi_string) {
5162 context->isCreateByComponent = false;
5163 context->needSystemApp = true;
5164 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5165 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5166 return nullptr;
5167 }
5168 return ParseArgsCreatePhotoAssetSystem(env, info, context);
5169 } else if (valueType == napi_number) {
5170 context->isCreateByComponent = true;
5171 return ParseArgsCreatePhotoAssetComponent(env, info, context);
5172 } else {
5173 NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5174 return nullptr;
5175 }
5176 }
5177
ParseTokenId(napi_env env,napi_value arg,uint32_t & tokenId)5178 static napi_status ParseTokenId(napi_env env, napi_value arg,
5179 uint32_t &tokenId)
5180 {
5181 napi_valuetype valueType = napi_undefined;
5182 CHECK_STATUS_RET(napi_typeof(env, arg, &valueType), "Failed to get type");
5183 if (valueType == napi_number) {
5184 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetUInt32(env, arg, tokenId), "Failed to get tokenId");
5185 CHECK_COND_RET(tokenId > 0, napi_invalid_arg, "Invalid tokenId");
5186 } else {
5187 NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5188 return napi_invalid_arg;
5189 }
5190 return napi_ok;
5191 }
5192
ParsePermissionType(napi_env env,napi_value arg,int32_t & permissionType)5193 static napi_status ParsePermissionType(napi_env env, napi_value arg, int32_t &permissionType)
5194 {
5195 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetInt32(env, arg, permissionType), "Failed to get permissionType");
5196 if (AppUriPermissionColumn::PERMISSION_TYPES_PICKER.find((int)permissionType) ==
5197 AppUriPermissionColumn::PERMISSION_TYPES_PICKER.end()) {
5198 NAPI_ERR_LOG("invalid picker permissionType, permissionType=%{public}d", permissionType);
5199 return napi_invalid_arg;
5200 }
5201 return napi_ok;
5202 }
5203
ParseHidenSensitiveType(napi_env env,napi_value arg,int32_t & hideSensitiveType)5204 static napi_status ParseHidenSensitiveType(napi_env env, napi_value arg, int32_t &hideSensitiveType)
5205 {
5206 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetInt32(env, arg, hideSensitiveType), "Failed to get hideSensitiveType");
5207 if (AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.find((int)hideSensitiveType) ==
5208 AppUriSensitiveColumn::SENSITIVE_TYPES_ALL.end()) {
5209 NAPI_ERR_LOG("invalid picker hideSensitiveType, hideSensitiveType=%{public}d", hideSensitiveType);
5210 return napi_invalid_arg;
5211 }
5212 return napi_ok;
5213 }
5214
ParseGrantMediaUris(napi_env env,napi_value arg,vector<string> & uris)5215 static napi_status ParseGrantMediaUris(napi_env env, napi_value arg, vector<string> &uris)
5216 {
5217 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetStringArray(env, arg, uris), "Failed to get uris");
5218 size_t urisMaxSize = 1000;
5219 if (uris.empty() || uris.size() > urisMaxSize) {
5220 NAPI_ERR_LOG("the size of uriList is invalid");
5221 return napi_invalid_arg;
5222 }
5223 return napi_ok;
5224 }
5225
ParseArgsGrantPhotoUriPermissionInner(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5226 static napi_value ParseArgsGrantPhotoUriPermissionInner(napi_env env, napi_callback_info info,
5227 unique_ptr<MediaLibraryAsyncContext> &context)
5228 {
5229 // parse appid or tokenId
5230 uint32_t tokenId;
5231 NAPI_ASSERT(env, ParseTokenId(env, context->argv[ARGS_ZERO], tokenId) ==
5232 napi_ok, "Invalid args[0]");
5233 context->valuesBucket.Put(AppUriPermissionColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5234 uint32_t srcTokenId = IPCSkeleton::GetCallingTokenID();
5235 context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(srcTokenId));
5236
5237 // parse fileId
5238 string uri;
5239 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], uri) ==
5240 napi_ok, "Failed to get uri");
5241 int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5242 NAPI_ASSERT(env, fileId >= 0, "Invalid uri");
5243 context->valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5244
5245 // parse permissionType
5246 int32_t permissionType;
5247 NAPI_ASSERT(env, ParsePermissionType(env, context->argv[ARGS_TWO], permissionType) ==
5248 napi_ok, "Invalid PermissionType");
5249 context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5250
5251 // parse hideSensitiveType
5252 int32_t hideSensitiveType;
5253 NAPI_ASSERT(env, ParseHidenSensitiveType(env, context->argv[ARGS_THREE],
5254 hideSensitiveType) == napi_ok, "Invalid SensitiveType");
5255 context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
5256
5257 // parsing fileId ensured uri is photo.
5258 context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5259
5260 napi_value result = nullptr;
5261 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5262 return result;
5263 }
5264
ParseArgsGrantPhotoUriPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5265 static napi_value ParseArgsGrantPhotoUriPermission(napi_env env, napi_callback_info info,
5266 unique_ptr<MediaLibraryAsyncContext> &context)
5267 {
5268 constexpr size_t minArgs = ARGS_ONE;
5269 constexpr size_t maxArgs = ARGS_FOUR;
5270 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5271 napi_ok, "Failed to get object info");
5272
5273 context->isCreateByComponent = false;
5274 context->needSystemApp = true;
5275 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5276 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5277 return nullptr;
5278 }
5279
5280 return ParseArgsGrantPhotoUriPermissionInner(env, info, context);
5281 }
5282
ParseUriTypes(std::vector<std::string> & uris,unique_ptr<MediaLibraryAsyncContext> & context)5283 static napi_status ParseUriTypes(std::vector<std::string> &uris, unique_ptr<MediaLibraryAsyncContext> &context)
5284 {
5285 // used for deduplication
5286 std::set<int32_t> fileIdSet;
5287 for (const auto &uri : uris) {
5288 OHOS::DataShare::DataShareValuesBucket valuesBucket;
5289 int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5290 if (fileId < 0) {
5291 NAPI_ERR_LOG("invalid uri can not find fileid");
5292 return napi_invalid_arg;
5293 }
5294 if (fileIdSet.find(fileId) != fileIdSet.end()) {
5295 continue;
5296 }
5297 fileIdSet.insert(fileId);
5298 valuesBucket = context->valuesBucket;
5299 valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5300 valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5301 context->valuesBucketArray.push_back(move(valuesBucket));
5302 }
5303 return napi_ok;
5304 }
5305
ParseArgsGrantPhotoUrisForForceSensitive(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5306 static napi_value ParseArgsGrantPhotoUrisForForceSensitive(napi_env env, napi_callback_info info,
5307 unique_ptr<MediaLibraryAsyncContext> &context)
5308 {
5309 constexpr size_t minArgs = ARGS_ONE;
5310 constexpr size_t maxArgs = ARGS_TWO;
5311 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5312 napi_ok, "Failed to get object info");
5313
5314 context->isCreateByComponent = false;
5315 context->needSystemApp = true;
5316 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5317 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5318 return nullptr;
5319 }
5320
5321 // tokenId
5322 uint32_t tokenId = IPCSkeleton::GetCallingTokenID();
5323 context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(tokenId));
5324 context->valuesBucket.Put(AppUriSensitiveColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5325
5326 // parse uris
5327 vector<string> uris;
5328 NAPI_ASSERT(env, ParseGrantMediaUris(env, context->argv[ARGS_ZERO], uris) ==
5329 napi_ok, "Invalid uri");
5330
5331 // parse hideSensitiveType
5332 int32_t hideSensitiveType;
5333 NAPI_ASSERT(env, ParseHidenSensitiveType(env, context->argv[ARGS_ONE],
5334 hideSensitiveType) == napi_ok, "Invalid SensitiveType");
5335 context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
5336 NAPI_ASSERT(env, ParseUriTypes(uris, context) == napi_ok, "ParseUriTypes failed");
5337
5338 napi_value result = nullptr;
5339 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5340 return result;
5341 }
5342
ParseArgsGrantPhotoUrisPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5343 static napi_value ParseArgsGrantPhotoUrisPermission(napi_env env, napi_callback_info info,
5344 unique_ptr<MediaLibraryAsyncContext> &context)
5345 {
5346 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, ARGS_ONE, ARGS_FOUR) ==
5347 napi_ok, "Failed to get object info");
5348
5349 context->isCreateByComponent = false;
5350 context->needSystemApp = true;
5351 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5352 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5353 return nullptr;
5354 }
5355 // parse appid or tokenId
5356 uint32_t tokenId;
5357 NAPI_ASSERT(env, ParseTokenId(env, context->argv[ARGS_ZERO], tokenId) ==
5358 napi_ok, "Invalid tokenId");
5359 context->valuesBucket.Put(AppUriPermissionColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5360 uint32_t srcTokenId = IPCSkeleton::GetCallingTokenID();
5361 context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(srcTokenId));
5362
5363 // parse permissionType
5364 int32_t permissionType;
5365 NAPI_ASSERT(env, ParsePermissionType(env, context->argv[ARGS_TWO], permissionType) ==
5366 napi_ok, "Invalid PermissionType");
5367 context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5368
5369 // parse hideSensitiveType
5370 int32_t hideSensitiveType;
5371 NAPI_ASSERT(env, ParseHidenSensitiveType(env, context->argv[ARGS_THREE], hideSensitiveType) ==
5372 napi_ok, "Invalid SensitiveType");
5373 context->valuesBucket.Put(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, hideSensitiveType);
5374
5375 // parsing fileId ensured uri is photo.
5376 context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5377
5378 // parse uris
5379 vector<string> uris;
5380 NAPI_ASSERT(env, ParseGrantMediaUris(env, context->argv[ARGS_ONE], uris) ==
5381 napi_ok, "Invalid uris");
5382 NAPI_ASSERT(env, ParseUriTypes(uris, context) == napi_ok, "ParseUriTypes failed");
5383
5384 napi_value result = nullptr;
5385 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5386 return result;
5387 }
5388
ParseArgsCancelPhotoUriPermission(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5389 static napi_value ParseArgsCancelPhotoUriPermission(napi_env env, napi_callback_info info,
5390 unique_ptr<MediaLibraryAsyncContext> &context)
5391 {
5392 constexpr size_t minArgs = ARGS_ONE;
5393 constexpr size_t maxArgs = ARGS_THREE;
5394 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5395 napi_ok, "Failed to get object info");
5396
5397 context->isCreateByComponent = false;
5398 context->needSystemApp = true;
5399 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5400 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5401 return nullptr;
5402 }
5403 // parse tokenId
5404 uint32_t tokenId;
5405 NAPI_ASSERT(env, ParseTokenId(env, context->argv[ARGS_ZERO], tokenId) ==
5406 napi_ok, "Invalid args[0]");
5407 context->valuesBucket.Put(AppUriPermissionColumn::TARGET_TOKENID, static_cast<int64_t>(tokenId));
5408
5409 //get caller tokenid
5410 uint32_t callerTokenId = IPCSkeleton::GetCallingTokenID();
5411 context->valuesBucket.Put(AppUriSensitiveColumn::SOURCE_TOKENID, static_cast<int64_t>(callerTokenId));
5412
5413 // parse fileId
5414 string uri;
5415 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], uri) ==
5416 napi_ok, "Failed to get uri");
5417 int32_t fileId = MediaLibraryNapiUtils::GetFileIdFromPhotoUri(uri);
5418 if (fileId < 0) {
5419 return nullptr;
5420 }
5421 context->valuesBucket.Put(AppUriPermissionColumn::FILE_ID, fileId);
5422
5423 // parse permissionType
5424 int32_t permissionType;
5425 NAPI_ASSERT(env, ParsePermissionType(env, context->argv[ARGS_TWO], permissionType) ==
5426 napi_ok, "Invalid args[2]");
5427 context->valuesBucket.Put(AppUriPermissionColumn::PERMISSION_TYPE, permissionType);
5428
5429 // parsing fileId ensured uri is photo.
5430 context->valuesBucket.Put(AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::URI_PHOTO);
5431
5432 napi_value result = nullptr;
5433 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5434 return result;
5435 }
5436
HandleBundleInfo(OHOS::DataShare::DataShareValuesBucket & valuesBucket,bool isAuthorization,BundleInfo bundleInfo)5437 static void HandleBundleInfo(OHOS::DataShare::DataShareValuesBucket &valuesBucket, bool isAuthorization,
5438 BundleInfo bundleInfo)
5439 {
5440 if (isAuthorization) {
5441 valuesBucket.Put(MEDIA_DATA_DB_OWNER_PACKAGE, bundleInfo.bundleName);
5442 valuesBucket.Put(MEDIA_DATA_DB_OWNER_APPID, bundleInfo.appId);
5443 valuesBucket.Put(MEDIA_DATA_DB_PACKAGE_NAME, bundleInfo.packageName);
5444 }
5445 if (!bundleInfo.ownerAlbumId.empty()) {
5446 valuesBucket.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, bundleInfo.ownerAlbumId);
5447 NAPI_INFO_LOG("client put ownerAlbumId: %{public}s", bundleInfo.ownerAlbumId.c_str());
5448 }
5449 }
5450
ParseCreateConfig(napi_env env,napi_value arg,BundleInfo bundleInfo,MediaLibraryAsyncContext & context,bool isAuthorization=true)5451 static napi_status ParseCreateConfig(napi_env env, napi_value arg,
5452 BundleInfo bundleInfo, MediaLibraryAsyncContext &context, bool isAuthorization = true)
5453 {
5454 const std::map<std::string, std::string> PHOTO_CREATE_CONFIG_PARAM = {
5455 { PHOTO_TYPE, MEDIA_DATA_DB_MEDIA_TYPE },
5456 { PHOTO_SUB_TYPE, PhotoColumn::PHOTO_SUBTYPE },
5457 { TITLE, MediaColumn::MEDIA_TITLE },
5458 { EXTENSION, ASSET_EXTENTION }
5459 };
5460
5461 OHOS::DataShare::DataShareValuesBucket valuesBucket;
5462 for (const auto &iter : PHOTO_CREATE_CONFIG_PARAM) {
5463 string param = iter.first;
5464 bool present = false;
5465 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
5466 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
5467 if (!present) {
5468 continue;
5469 }
5470 napi_value value;
5471 result = napi_get_named_property(env, arg, param.c_str(), &value);
5472 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
5473 napi_valuetype valueType = napi_undefined;
5474 result = napi_typeof(env, value, &valueType);
5475 CHECK_COND_RET(result == napi_ok, result, "failed to get value type");
5476 if (valueType == napi_number) {
5477 int32_t number = 0;
5478 result = napi_get_value_int32(env, value, &number);
5479 CHECK_COND_RET(result == napi_ok, result, "failed to get int32_t");
5480 valuesBucket.Put(iter.second, number);
5481 } else if (valueType == napi_string) {
5482 char buffer[ARG_BUF_SIZE];
5483 size_t res = 0;
5484 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
5485 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
5486 string bufferString(buffer);
5487 if (!bufferString.empty()) {
5488 valuesBucket.Put(iter.second, bufferString);
5489 }
5490 } else if (valueType == napi_undefined || valueType == napi_null) {
5491 continue;
5492 } else {
5493 NAPI_ERR_LOG("ParseCreateConfig failed, valueType %{public}d is unaccepted", static_cast<int>(valueType));
5494 return napi_invalid_arg;
5495 }
5496 }
5497 HandleBundleInfo(valuesBucket, isAuthorization, bundleInfo);
5498 if (isAuthorization) {
5499 context.tokenId = bundleInfo.tokenId;
5500 }
5501 context.valuesBucketArray.push_back(move(valuesBucket));
5502 return napi_ok;
5503 }
5504
ParseCreateSource(napi_env env,napi_value arg,BundleInfo & bundleInfo)5505 static napi_value ParseCreateSource(napi_env env, napi_value arg, BundleInfo &bundleInfo)
5506 {
5507 napi_value valueBundleName = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5508 CONFIRM_BOX_BUNDLE_NAME.c_str());
5509 CHECK_NULLPTR_RET(valueBundleName);
5510 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, valueBundleName,
5511 bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
5512 napi_value valueAppName = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5513 CONFIRM_BOX_APP_NAME.c_str());
5514 CHECK_NULLPTR_RET(valueAppName);
5515 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, valueAppName,
5516 bundleInfo.packageName) == napi_ok, "Failed to get appName");
5517 napi_value valueAppId = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5518 CONFIRM_BOX_APP_ID.c_str());
5519 CHECK_NULLPTR_RET(valueAppId);
5520 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, valueAppId,
5521 bundleInfo.appId) == napi_ok, "Failed to get appId");
5522 napi_value valueTokenId = MediaLibraryNapiUtils::GetPropertyValueByName(env, arg,
5523 TOKEN_ID.c_str());
5524 CHECK_NULLPTR_RET(valueTokenId);
5525 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetUInt32(env, valueTokenId,
5526 bundleInfo.tokenId) == napi_ok, "Failed to get appId");
5527 napi_value result = nullptr;
5528 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5529 return result;
5530 }
5531
ParseArgsCreatePhotoAssetForAppWithAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5532 static napi_value ParseArgsCreatePhotoAssetForAppWithAlbum(napi_env env, napi_callback_info info,
5533 unique_ptr<MediaLibraryAsyncContext> &context)
5534 {
5535 constexpr size_t minArgs = ARGS_FOUR;
5536 constexpr size_t maxArgs = ARGS_FOUR;
5537 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5538 napi_ok, "Failed to get object info");
5539 context->isCreateByComponent = false;
5540 context->isCreateByAgent = true;
5541 BundleInfo bundleInfo;
5542 string albumUri;
5543 bool isAuthorization = false;
5544 ParseCreateSource(env, context->argv[ARGS_ZERO], bundleInfo);
5545 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
5546 albumUri) == napi_ok, "Failed to get albumUri");
5547 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[ARGS_TWO],
5548 isAuthorization) == napi_ok, "Failed to get isAuthorization");
5549 MediaFileUri fileUri = MediaFileUri(albumUri);
5550 CHECK_COND_WITH_MESSAGE(env, fileUri.GetUriType() == API10_PHOTOALBUM_URI, "Failed to get photoAlbum");
5551 bundleInfo.ownerAlbumId = MediaFileUtils::GetIdFromUri(albumUri);
5552 context->isContainsAlbumUri = true;
5553 if (isAuthorization) {
5554 context->tokenId = bundleInfo.tokenId;
5555 }
5556 napi_value result = nullptr;
5557 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5558
5559 vector<napi_value> napiValues;
5560 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_THREE], napiValues));
5561 if (napiValues.empty() || napiValues.size() > MAX_CREATE_ASSET_LIMIT) {
5562 NAPI_ERR_LOG("the size of albumid is invalid");
5563 return nullptr;
5564 }
5565
5566 for (const auto& napiValue : napiValues) {
5567 CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context,
5568 isAuthorization) == napi_ok, "Parse asset create config failed");
5569 }
5570
5571 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
5572 == napi_ok, "Failed to get callback");
5573 return result;
5574 }
5575
ParseArgsCreateAgentCreateAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5576 static napi_value ParseArgsCreateAgentCreateAssets(napi_env env, napi_callback_info info,
5577 unique_ptr<MediaLibraryAsyncContext> &context)
5578 {
5579 /* Parse the arguments */
5580 BundleInfo bundleInfo;
5581 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO],
5582 bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
5583 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
5584 bundleInfo.packageName) == napi_ok, "Failed to get appName");
5585 CHECK_COND_WITH_MESSAGE(env, ParseTokenId(env, context->argv[ARGS_TWO],
5586 bundleInfo.tokenId) == napi_ok, "Failed to get tokenId");
5587
5588 napi_value result = nullptr;
5589 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5590
5591 vector<napi_value> napiValues;
5592 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_THREE], napiValues));
5593 if (napiValues.empty()) {
5594 return result;
5595 }
5596
5597 for (const auto& napiValue : napiValues) {
5598 CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context) == napi_ok,
5599 "Parse asset create config failed");
5600 }
5601
5602 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
5603 == napi_ok, "Failed to get callback");
5604 return result;
5605 }
5606
ParseArgsAgentCreateAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5607 static napi_value ParseArgsAgentCreateAssets(napi_env env, napi_callback_info info,
5608 unique_ptr<MediaLibraryAsyncContext> &context)
5609 {
5610 constexpr size_t minArgs = ARGS_FOUR;
5611 constexpr size_t maxArgs = ARGS_FOUR;
5612 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5613 napi_ok, "Failed to get object info");
5614
5615 context->isCreateByComponent = false;
5616 context->isCreateByAgent = true;
5617
5618 return ParseArgsCreateAgentCreateAssets(env, info, context);
5619 }
5620
ParseArgsCreateAudioAssetSystem(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5621 static napi_value ParseArgsCreateAudioAssetSystem(napi_env env, napi_callback_info info,
5622 unique_ptr<MediaLibraryAsyncContext> &context)
5623 {
5624 /* Parse the first argument into displayName */
5625 string displayName;
5626 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], displayName) ==
5627 napi_ok, "Failed to get displayName");
5628
5629 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_TYPE_AUDIO);
5630 context->valuesBucket.Put(MEDIA_DATA_DB_NAME, displayName);
5631
5632 napi_value result = nullptr;
5633 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5634 return result;
5635 }
5636
ParseArgsCreateAudioAssetComponent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5637 static napi_value ParseArgsCreateAudioAssetComponent(napi_env env, napi_callback_info info,
5638 unique_ptr<MediaLibraryAsyncContext> &context)
5639 {
5640 /* Parse the first argument into displayName */
5641 napi_valuetype valueType;
5642 MediaType mediaType;
5643 int32_t type = 0;
5644 NAPI_ASSERT(env, napi_get_value_int32(env, context->argv[ARGS_ZERO], &type) == napi_ok,
5645 "Failed to get type value");
5646 mediaType = static_cast<MediaType>(type);
5647 NAPI_ASSERT(env, (mediaType == MEDIA_TYPE_AUDIO), "invalid file type");
5648
5649 /* Parse the second argument into albumUri if exists */
5650 string extention;
5651 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], extention) ==
5652 napi_ok, "Failed to get extention");
5653 context->valuesBucket.Put(ASSET_EXTENTION, extention);
5654
5655 /* Parse the third argument into albumUri if exists */
5656 if (context->argc >= ARGS_THREE) {
5657 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_TWO], &valueType) == napi_ok, "Failed to get napi type");
5658 if (valueType == napi_object) {
5659 NAPI_ASSERT(env, ParseCreateOptions(env, context->argv[ARGS_TWO], *context) == napi_ok,
5660 "Parse asset create option failed");
5661 } else if (valueType != napi_function) {
5662 NAPI_ERR_LOG("Napi type is wrong in create options");
5663 return nullptr;
5664 }
5665 }
5666
5667 context->valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int32_t>(mediaType));
5668 NAPI_ASSERT(env, MediaLibraryNapiUtils::GetParamCallback(env, context) == napi_ok, "Failed to get callback");
5669
5670 napi_value result = nullptr;
5671 NAPI_CALL(env, napi_get_boolean(env, true, &result));
5672 return result;
5673 }
5674
ParseArgsCreateAudioAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5675 static napi_value ParseArgsCreateAudioAsset(napi_env env, napi_callback_info info,
5676 unique_ptr<MediaLibraryAsyncContext> &context)
5677 {
5678 constexpr size_t minArgs = ARGS_ONE;
5679 constexpr size_t maxArgs = ARGS_FOUR;
5680 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
5681 napi_ok, "Failed to get object info");
5682
5683 napi_valuetype valueType;
5684 NAPI_ASSERT(env, napi_typeof(env, context->argv[ARGS_ZERO], &valueType) == napi_ok, "Failed to get napi type");
5685 if (valueType == napi_string) {
5686 context->isCreateByComponent = false;
5687 return ParseArgsCreateAudioAssetSystem(env, info, context);
5688 } else if (valueType == napi_number) {
5689 context->isCreateByComponent = true;
5690 return ParseArgsCreateAudioAssetComponent(env, info, context);
5691 } else {
5692 NAPI_ERR_LOG("JS param type %{public}d is wrong", static_cast<int32_t>(valueType));
5693 return nullptr;
5694 }
5695 }
5696
ParseArgsGetAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5697 static napi_value ParseArgsGetAssets(napi_env env, napi_callback_info info,
5698 unique_ptr<MediaLibraryAsyncContext> &context)
5699 {
5700 constexpr size_t minArgs = ARGS_ONE;
5701 constexpr size_t maxArgs = ARGS_TWO;
5702 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5703 JS_ERR_PARAMETER_INVALID);
5704
5705 /* Parse the first argument */
5706 CHECK_ARGS(env,
5707 MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
5708 JS_INNER_FAIL);
5709
5710 switch (context->assetType) {
5711 case TYPE_AUDIO: {
5712 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5713 AudioColumn::IsAudioColumn, TYPE_AUDIO));
5714 break;
5715 }
5716 case TYPE_PHOTO: {
5717 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5718 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
5719 break;
5720 }
5721 default: {
5722 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
5723 return nullptr;
5724 }
5725 }
5726 auto &predicates = context->predicates;
5727 predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
5728 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5729 if (context->assetType == TYPE_PHOTO) {
5730 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
5731 predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(false));
5732 predicates.EqualTo(
5733 PhotoColumn::PHOTO_BURST_COVER_LEVEL, to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
5734 }
5735 napi_value result = nullptr;
5736 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5737 return result;
5738 }
5739
ParseArgsGetBurstAssets(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5740 static napi_value ParseArgsGetBurstAssets(napi_env env, napi_callback_info info,
5741 unique_ptr<MediaLibraryAsyncContext> &context)
5742 {
5743 constexpr size_t minArgs = ARGS_ONE;
5744 constexpr size_t maxArgs = ARGS_TWO;
5745 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5746 OHOS_INVALID_PARAM_CODE);
5747
5748 /* Parse the first argument */
5749 std::string burstKey;
5750 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], burstKey),
5751 OHOS_INVALID_PARAM_CODE);
5752 if (burstKey.empty()) {
5753 NAPI_ERR_LOG("The input burstkey cannot be empty");
5754 return nullptr;
5755 }
5756 /* Parse the second argument */
5757 CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ASSET_FETCH_OPT, context),
5758 JS_INNER_FAIL);
5759
5760 auto &predicates = context->predicates;
5761 if (context->assetType != TYPE_PHOTO) {
5762 return nullptr;
5763 }
5764 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
5765 PhotoColumn::IsPhotoColumn, TYPE_PHOTO));
5766 predicates.And()->EqualTo(PhotoColumn::PHOTO_BURST_KEY, burstKey);
5767 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5768 predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
5769 predicates.OrderByAsc(MediaColumn::MEDIA_NAME);
5770 context->burstKey = burstKey;
5771
5772 napi_value result = nullptr;
5773 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5774 return result;
5775 }
5776
ParseArgsIndexUri(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,string & uri,string & albumUri)5777 static napi_status ParseArgsIndexUri(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, string &uri,
5778 string &albumUri)
5779 {
5780 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], uri),
5781 "Failed to get first string argument");
5782 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE], albumUri),
5783 "Failed to get second string argument");
5784 return napi_ok;
5785 }
5786
ParseArgsIndexof(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)5787 static napi_value ParseArgsIndexof(napi_env env, napi_callback_info info,
5788 unique_ptr<MediaLibraryAsyncContext> &context)
5789 {
5790 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5791 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5792 return nullptr;
5793 }
5794
5795 constexpr size_t minArgs = ARGS_THREE;
5796 constexpr size_t maxArgs = ARGS_FOUR;
5797 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
5798 JS_ERR_PARAMETER_INVALID);
5799
5800 string uri;
5801 string album;
5802 CHECK_ARGS(env, ParseArgsIndexUri(env, context, uri, album), JS_INNER_FAIL);
5803 CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM2], ASSET_FETCH_OPT, context),
5804 JS_INNER_FAIL);
5805 auto &predicates = context->predicates;
5806 predicates.And()->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
5807 predicates.And()->EqualTo(MediaColumn::MEDIA_TIME_PENDING, to_string(0));
5808 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, to_string(0));
5809 predicates.And()->EqualTo(PhotoColumn::PHOTO_IS_TEMP, to_string(0));
5810
5811 context->fetchColumn.clear();
5812 MediaFileUri photoUri(uri);
5813 CHECK_COND(env, photoUri.GetUriType() == API10_PHOTO_URI, JS_ERR_PARAMETER_INVALID);
5814 context->fetchColumn.emplace_back(photoUri.GetFileId());
5815 NAPI_INFO_LOG("current fileId: %{public}s", photoUri.GetFileId().c_str());
5816 if (!album.empty()) {
5817 MediaFileUri albumUri(album);
5818 CHECK_COND(env, albumUri.GetUriType() == API10_PHOTOALBUM_URI ||
5819 albumUri.GetUriType() == API10_ANALYSISALBUM_URI, JS_ERR_PARAMETER_INVALID);
5820 context->isAnalysisAlbum = (albumUri.GetUriType() == API10_ANALYSISALBUM_URI);
5821 context->fetchColumn.emplace_back(albumUri.GetFileId());
5822 NAPI_INFO_LOG("current albumId: %{public}s", albumUri.GetFileId().c_str());
5823 } else {
5824 context->fetchColumn.emplace_back(album);
5825 }
5826 napi_value result = nullptr;
5827 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
5828 return result;
5829 }
5830
JSGetAssetsExecute(napi_env env,void * data)5831 static void JSGetAssetsExecute(napi_env env, void *data)
5832 {
5833 MediaLibraryTracer tracer;
5834 tracer.Start("JSGetAssetsExecute");
5835
5836 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5837 string queryUri;
5838 switch (context->assetType) {
5839 case TYPE_AUDIO: {
5840 queryUri = UFM_QUERY_AUDIO;
5841 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5842 break;
5843 }
5844 case TYPE_PHOTO: {
5845 queryUri = UFM_QUERY_PHOTO;
5846 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5847 break;
5848 }
5849 default: {
5850 context->SaveError(-EINVAL);
5851 return;
5852 }
5853 }
5854
5855 Uri uri(queryUri);
5856 int errCode = 0;
5857 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
5858 context->predicates, context->fetchColumn, errCode, context->userId);
5859 if (resultSet == nullptr) {
5860 context->SaveError(errCode);
5861 return;
5862 }
5863 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
5864 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
5865 context->fetchFileResult->SetUserId(context->userId);
5866 }
5867
GetPhotoIndexAsyncCallbackComplete(napi_env env,napi_status status,void * data)5868 static void GetPhotoIndexAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5869 {
5870 MediaLibraryTracer tracer;
5871 tracer.Start("GetPhotoIndexAsyncCallbackComplete");
5872
5873 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5874 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5875
5876 auto jsContext = make_unique<JSAsyncContextOutput>();
5877 jsContext->status = false;
5878 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
5879 if (context->error != ERR_DEFAULT) {
5880 context->HandleError(env, jsContext->error);
5881 } else {
5882 int32_t count = -1;
5883 if (context->fetchFileResult != nullptr) {
5884 auto fileAsset = context->fetchFileResult->GetFirstObject();
5885 if (fileAsset != nullptr) {
5886 count = fileAsset->GetPhotoIndex();
5887 }
5888 }
5889 jsContext->status = true;
5890 napi_create_int32(env, count, &jsContext->data);
5891 }
5892
5893 tracer.Finish();
5894 if (context->work != nullptr) {
5895 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5896 context->work, *jsContext);
5897 }
5898 delete context;
5899 }
5900
GetPhotoIndexExec(napi_env env,void * data,ResultNapiType type)5901 static void GetPhotoIndexExec(napi_env env, void *data, ResultNapiType type)
5902 {
5903 MediaLibraryTracer tracer;
5904 tracer.Start("JsGetPhotoIndexExec");
5905 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5906 string queryUri = context->isAnalysisAlbum ? PAH_GET_ANALYSIS_INDEX : UFM_GET_INDEX;
5907 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5908 Uri uri(queryUri);
5909 int errCode = 0;
5910 if (context->fetchColumn.size() < 2) { // 2: photoId, albumId
5911 context->SaveError(E_ERR);
5912 return;
5913 }
5914 GetPhotoIndexReqBody reqBody;
5915 reqBody.predicates = context->predicates;
5916 reqBody.photoId = context->fetchColumn[0];
5917 reqBody.albumId = context->fetchColumn[1];
5918 reqBody.isAnalysisAlbum = context->isAnalysisAlbum;
5919 QueryResultRespBody respBody;
5920 errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(
5921 static_cast<uint32_t>(MediaLibraryBusinessCode::GET_PHOTO_INDEX), reqBody, respBody);
5922 auto resultSet = respBody.resultSet;
5923 if (resultSet == nullptr) {
5924 NAPI_ERR_LOG("resultSet is nullptr");
5925 context->SaveError(errCode);
5926 return;
5927 }
5928 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
5929 context->fetchFileResult->SetResultNapiType(type);
5930 }
5931
PhotoAccessGetPhotoIndexExec(napi_env env,void * data)5932 static void PhotoAccessGetPhotoIndexExec(napi_env env, void *data)
5933 {
5934 GetPhotoIndexExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
5935 }
5936
JsGetPhotoIndexExec(napi_env env,void * data)5937 static void JsGetPhotoIndexExec(napi_env env, void *data)
5938 {
5939 GetPhotoIndexExec(env, data, ResultNapiType::TYPE_USERFILE_MGR);
5940 }
5941
JSGetPhotoIndex(napi_env env,napi_callback_info info)5942 napi_value MediaLibraryNapi::JSGetPhotoIndex(napi_env env, napi_callback_info info)
5943 {
5944 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5945 CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
5946
5947 SetUserIdFromObjectInfo(asyncContext);
5948 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
5949 JsGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
5950 }
5951
PhotoAccessGetPhotoIndex(napi_env env,napi_callback_info info)5952 napi_value MediaLibraryNapi::PhotoAccessGetPhotoIndex(napi_env env, napi_callback_info info)
5953 {
5954 MediaLibraryTracer tracer;
5955 tracer.Start("PhotoAccessGetPhotoIndex");
5956
5957 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
5958 CHECK_NULLPTR_RET(ParseArgsIndexof(env, info, asyncContext));
5959
5960 SetUserIdFromObjectInfo(asyncContext);
5961 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoIndex",
5962 PhotoAccessGetPhotoIndexExec, GetPhotoIndexAsyncCallbackComplete);
5963 }
5964
GetIndexConstructProgressAsyncCallbackComplete(napi_env env,napi_status status,void * data)5965 static void GetIndexConstructProgressAsyncCallbackComplete(napi_env env, napi_status status, void *data)
5966 {
5967 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
5968 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5969 auto jsContext = make_unique<JSAsyncContextOutput>();
5970 jsContext->status = false;
5971
5972 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
5973 if (context->error != ERR_DEFAULT) {
5974 context->HandleError(env, jsContext->error);
5975 } else {
5976 CHECK_ARGS_RET_VOID(
5977 env, napi_create_string_utf8(env, context->indexProgress.c_str(), NAPI_AUTO_LENGTH, &jsContext->data),
5978 JS_INNER_FAIL);
5979 jsContext->status = true;
5980 }
5981
5982 if (context->work != nullptr) {
5983 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5984 context->work, *jsContext);
5985 }
5986 delete context;
5987 }
5988
PhotoAccessGetIndexConstructProgressExec(napi_env env,void * data)5989 static void PhotoAccessGetIndexConstructProgressExec(napi_env env, void *data)
5990 {
5991 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
5992 CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
5993
5994 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::GET_INDEX_CONSTRUCT_PROGRESS);
5995 GetIndexConstructProgressRespBody respBody;
5996 int32_t errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Get(businessCode, respBody);
5997
5998 if (errCode != E_OK) {
5999 NAPI_ERR_LOG("get index construct progress failed, errCode is %{public}d", errCode);
6000 context->SaveError(errCode);
6001 return;
6002 }
6003 context->indexProgress = respBody.indexProgress;
6004 }
6005
PhotoAccessGetIndexConstructProgress(napi_env env,napi_callback_info info)6006 napi_value MediaLibraryNapi::PhotoAccessGetIndexConstructProgress(napi_env env, napi_callback_info info)
6007 {
6008 if (!MediaLibraryNapiUtils::IsSystemApp()) {
6009 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6010 return nullptr;
6011 }
6012
6013 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6014
6015 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, 0, 0),
6016 JS_ERR_PARAMETER_INVALID);
6017
6018 SetUserIdFromObjectInfo(asyncContext);
6019 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetIndexConstructProgress",
6020 PhotoAccessGetIndexConstructProgressExec, GetIndexConstructProgressAsyncCallbackComplete);
6021 }
6022
CheckFormId(string & formId)6023 static napi_status CheckFormId(string &formId)
6024 {
6025 if (formId.empty() || formId.length() > FORMID_MAX_LEN) {
6026 return napi_invalid_arg;
6027 }
6028 for (uint32_t i = 0; i < formId.length(); i++) {
6029 if (!isdigit(formId[i])) {
6030 return napi_invalid_arg;
6031 }
6032 }
6033 unsigned long long num = stoull(formId);
6034 if (num > MAX_INT64) {
6035 return napi_invalid_arg;
6036 }
6037 return napi_ok;
6038 }
6039
ParseUpdateGalleryFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)6040 static napi_status ParseUpdateGalleryFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
6041 {
6042 const std::string formIdKey = "formId";
6043 const std::string assetUrisKey = "assetUris";
6044
6045 bool formIdPresent = false;
6046 napi_status result = napi_has_named_property(env, arg, formIdKey.c_str(), &formIdPresent);
6047 CHECK_COND_RET(result == napi_ok, result, "failed to check formId property");
6048 if (!formIdPresent) {
6049 return napi_invalid_arg;
6050 }
6051 napi_value formIdValue;
6052 result = napi_get_named_property(env, arg, formIdKey.c_str(), &formIdValue);
6053 CHECK_COND_RET(result == napi_ok, result, "failed to get formId property");
6054 char formIdBuffer[ARG_BUF_SIZE];
6055 size_t formIdLength = 0;
6056 result = napi_get_value_string_utf8(env, formIdValue, formIdBuffer, ARG_BUF_SIZE, &formIdLength);
6057 CHECK_COND_RET(result == napi_ok, result, "failed to get formId string");
6058 std::string formId = std::string(formIdBuffer);
6059 if (CheckFormId(formId) != napi_ok) {
6060 return napi_invalid_arg;
6061 }
6062 context.formId = formId;
6063
6064 bool urisPresent = false;
6065 result = napi_has_named_property(env, arg, assetUrisKey.c_str(), &urisPresent);
6066 CHECK_COND_RET(result == napi_ok, result, "failed to check uris property");
6067 if (!urisPresent) {
6068 return napi_invalid_arg;
6069 }
6070 napi_value urisValue;
6071 result = napi_get_named_property(env, arg, assetUrisKey.c_str(), &urisValue);
6072 CHECK_COND_RET(result == napi_ok, result, "failed to get uris property");
6073 bool isArray = false;
6074 result = napi_is_array(env, urisValue, &isArray);
6075 CHECK_COND_RET(result == napi_ok && isArray, napi_invalid_arg, "uris is not an array");
6076
6077 uint32_t arrayLength = 0;
6078 result = napi_get_array_length(env, urisValue, &arrayLength);
6079 CHECK_COND_RET(result == napi_ok, result, "failed to get array length");
6080 if (arrayLength == 0) {
6081 return napi_invalid_arg;
6082 }
6083
6084 for (uint32_t i = 0; i < arrayLength; ++i) {
6085 napi_value uriValue;
6086 result = napi_get_element(env, urisValue, i, &uriValue);
6087 CHECK_COND_RET(result == napi_ok, result, "failed to get array element");
6088 char uriBuffer[ARG_BUF_SIZE];
6089 size_t uriLength = 0;
6090 result = napi_get_value_string_utf8(env, uriValue, uriBuffer, ARG_BUF_SIZE, &uriLength);
6091 CHECK_COND_RET(result == napi_ok, result, "failed to get URI string");
6092 std::string assetUri = std::string(uriBuffer);
6093 OHOS::DataShare::DataShareValuesBucket bucket;
6094 bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, formId);
6095 bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, assetUri);
6096 context.valuesBucketArray.push_back(move(bucket));
6097 }
6098 return napi_ok;
6099 }
6100
ParseSaveGalleryFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)6101 static napi_status ParseSaveGalleryFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
6102 {
6103 const std::string formIdKey = "formId";
6104 const std::string assetUrisKey = "assetUris";
6105
6106 bool formIdPresent = false;
6107 napi_status result = napi_has_named_property(env, arg, formIdKey.c_str(), &formIdPresent);
6108 CHECK_COND_RET(result == napi_ok, result, "failed to check formId property");
6109 if (!formIdPresent) {
6110 NAPI_ERR_LOG("ParseSaveGalleryFormInfoOption formIdPresent is false");
6111 return napi_invalid_arg;
6112 }
6113
6114 napi_value formIdValue;
6115 result = napi_get_named_property(env, arg, formIdKey.c_str(), &formIdValue);
6116 CHECK_COND_RET(result == napi_ok, result, "failed to get formId property");
6117
6118 char formIdBuffer[ARG_BUF_SIZE];
6119 size_t formIdLength = 0;
6120 result = napi_get_value_string_utf8(env, formIdValue, formIdBuffer, ARG_BUF_SIZE, &formIdLength);
6121 CHECK_COND_RET(result == napi_ok, result, "failed to get formId string");
6122
6123 std::string formId = std::string(formIdBuffer);
6124 if (CheckFormId(formId) != napi_ok) {
6125 return napi_invalid_arg;
6126 }
6127
6128 bool urisPresent = false;
6129 result = napi_has_named_property(env, arg, assetUrisKey.c_str(), &urisPresent);
6130 CHECK_COND_RET(result == napi_ok, result, "failed to check uris property");
6131 if (!urisPresent) {
6132 NAPI_ERR_LOG("ParseSaveGalleryFormInfoOption urisPresent is false");
6133 return napi_invalid_arg;
6134 }
6135
6136 napi_value urisValue;
6137 result = napi_get_named_property(env, arg, assetUrisKey.c_str(), &urisValue);
6138 CHECK_COND_RET(result == napi_ok, result, "failed to get uris property");
6139
6140 bool isArray = false;
6141 result = napi_is_array(env, urisValue, &isArray);
6142 CHECK_COND_RET(result == napi_ok && isArray, napi_invalid_arg, "uris is not an array");
6143
6144 uint32_t arrayLength = 0;
6145 result = napi_get_array_length(env, urisValue, &arrayLength);
6146 CHECK_COND_RET(result == napi_ok, result, "failed to get array length");
6147 if (arrayLength == 0) {
6148 return napi_invalid_arg;
6149 }
6150
6151 for (uint32_t i = 0; i < arrayLength; ++i) {
6152 napi_value uriValue;
6153 result = napi_get_element(env, urisValue, i, &uriValue);
6154 CHECK_COND_RET(result == napi_ok, result, "failed to get array element");
6155
6156 char uriBuffer[ARG_BUF_SIZE];
6157 size_t uriLength = 0;
6158 result = napi_get_value_string_utf8(env, uriValue, uriBuffer, ARG_BUF_SIZE, &uriLength);
6159 CHECK_COND_RET(result == napi_ok, result, "failed to get URI string");
6160 std::string assetUri = std::string(uriBuffer);
6161 OHOS::DataShare::DataShareValuesBucket bucket;
6162 bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, formId);
6163 bucket.Put(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, assetUri);
6164 context.valuesBucketArray.push_back(move(bucket));
6165 }
6166 return napi_ok;
6167 }
6168
ParseSaveFormInfoOption(napi_env env,napi_value arg,MediaLibraryAsyncContext & context)6169 static napi_status ParseSaveFormInfoOption(napi_env env, napi_value arg, MediaLibraryAsyncContext &context)
6170 {
6171 const std::string formId = "formId";
6172 const std::string uri = "uri";
6173 const std::map<std::string, std::string> saveFormInfoOptionsParam = {
6174 { formId, FormMap::FORMMAP_FORM_ID },
6175 { uri, FormMap::FORMMAP_URI }
6176 };
6177 for (const auto &iter : saveFormInfoOptionsParam) {
6178 string param = iter.first;
6179 bool present = false;
6180 napi_status result = napi_has_named_property(env, arg, param.c_str(), &present);
6181 CHECK_COND_RET(result == napi_ok, result, "failed to check named property");
6182 if (!present) {
6183 return napi_invalid_arg;
6184 }
6185 napi_value value;
6186 result = napi_get_named_property(env, arg, param.c_str(), &value);
6187 CHECK_COND_RET(result == napi_ok, result, "failed to get named property");
6188 char buffer[ARG_BUF_SIZE];
6189 size_t res = 0;
6190 result = napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res);
6191 CHECK_COND_RET(result == napi_ok, result, "failed to get string");
6192 context.valuesBucket.Put(iter.second, string(buffer));
6193 }
6194 bool isValid = false;
6195 string tempFormId = context.valuesBucket.Get(FormMap::FORMMAP_FORM_ID, isValid);
6196 if (!isValid) {
6197 return napi_invalid_arg;
6198 }
6199 return CheckFormId(tempFormId);
6200 }
6201
ParseArgsUpdateGalleryFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6202 static napi_value ParseArgsUpdateGalleryFormInfo(napi_env env, napi_callback_info info,
6203 unique_ptr<MediaLibraryAsyncContext> &context)
6204 {
6205 constexpr size_t minArgs = ARGS_ONE;
6206 constexpr size_t maxArgs = ARGS_TWO;
6207 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6208 maxArgs) == napi_ok, "Failed to get object info");
6209
6210 if (!MediaLibraryNapiUtils::IsSystemApp()) {
6211 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6212 return nullptr;
6213 }
6214
6215 CHECK_COND_WITH_MESSAGE(env, ParseUpdateGalleryFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
6216 "Parse formInfo Option failed");
6217
6218 napi_value result = nullptr;
6219 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6220 return result;
6221 }
6222
ParseArgsSaveGalleryFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6223 static napi_value ParseArgsSaveGalleryFormInfo(napi_env env, napi_callback_info info,
6224 unique_ptr<MediaLibraryAsyncContext> &context)
6225 {
6226 constexpr size_t minArgs = ARGS_ONE;
6227 constexpr size_t maxArgs = ARGS_TWO;
6228 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6229 maxArgs) == napi_ok, "Failed to get object info");
6230
6231 if (!MediaLibraryNapiUtils::IsSystemApp()) {
6232 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6233 return nullptr;
6234 }
6235
6236 CHECK_COND_WITH_MESSAGE(env, ParseSaveGalleryFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
6237 "Parse formInfo Option failed");
6238
6239 napi_value result = nullptr;
6240 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6241 return result;
6242 }
6243
ParseArgsSaveFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6244 static napi_value ParseArgsSaveFormInfo(napi_env env, napi_callback_info info,
6245 unique_ptr<MediaLibraryAsyncContext> &context)
6246 {
6247 constexpr size_t minArgs = ARGS_ONE;
6248 constexpr size_t maxArgs = ARGS_TWO;
6249 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6250 maxArgs) == napi_ok, "Failed to get object info");
6251
6252 CHECK_COND_WITH_MESSAGE(env, ParseSaveFormInfoOption(env, context->argv[ARGS_ZERO], *context) == napi_ok,
6253 "Parse formInfo Option failed");
6254
6255 napi_value result = nullptr;
6256 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6257 return result;
6258 }
6259
SaveGalleryFormInfoExec(napi_env env,void * data,ResultNapiType type)6260 static void SaveGalleryFormInfoExec(napi_env env, void *data, ResultNapiType type)
6261 {
6262 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6263 context->resultNapiType = type;
6264 vector<string> formIds;
6265 vector<string> fileUris;
6266 bool isValid = false;
6267 for (const auto& valueBucket : context->valuesBucketArray) {
6268 formIds.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, isValid));
6269 fileUris.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, isValid));
6270 }
6271 FormInfoReqBody reqBody;
6272 reqBody.formIds = formIds;
6273 reqBody.fileUris = fileUris;
6274 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::SAVE_GALLERY_FORM_INFO);
6275 int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6276 if (ret < 0) {
6277 if (ret == E_PERMISSION_DENIED) {
6278 context->error = OHOS_PERMISSION_DENIED_CODE;
6279 } else if (ret == E_GET_PRAMS_FAIL) {
6280 context->error = OHOS_INVALID_PARAM_CODE;
6281 } else {
6282 context->SaveError(ret);
6283 }
6284 NAPI_INFO_LOG("store formInfo failed, ret: %{public}d", ret);
6285 }
6286 }
6287
SaveFormInfoExec(napi_env env,void * data,ResultNapiType type)6288 static void SaveFormInfoExec(napi_env env, void *data, ResultNapiType type)
6289 {
6290 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6291 context->resultNapiType = type;
6292 bool isValid = false;
6293 string formId = context->valuesBucket.Get(FormMap::FORMMAP_FORM_ID, isValid);
6294 string fileUri = context->valuesBucket.Get(FormMap::FORMMAP_URI, isValid);
6295 FormInfoReqBody reqBody;
6296 reqBody.formIds.emplace_back(formId);
6297 reqBody.fileUris.emplace_back(fileUri);
6298 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::SAVE_FORM_INFO);
6299 int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6300 if (ret < 0) {
6301 if (ret == E_PERMISSION_DENIED) {
6302 context->error = OHOS_PERMISSION_DENIED_CODE;
6303 } else if (ret == E_GET_PRAMS_FAIL) {
6304 context->error = OHOS_INVALID_PARAM_CODE;
6305 } else {
6306 context->SaveError(ret);
6307 }
6308 NAPI_ERR_LOG("store formInfo failed, ret: %{public}d", ret);
6309 }
6310 }
6311
SaveFormInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)6312 static void SaveFormInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
6313 {
6314 MediaLibraryTracer tracer;
6315 tracer.Start("SaveFormInfoAsyncCallbackComplete");
6316
6317 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6318 auto jsContext = make_unique<JSAsyncContextOutput>();
6319 jsContext->status = false;
6320 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6321 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6322 if (context->error != ERR_DEFAULT) {
6323 context->HandleError(env, jsContext->error);
6324 } else {
6325 jsContext->status = true;
6326 }
6327 tracer.Finish();
6328 if (context->work != nullptr) {
6329 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6330 context->work, *jsContext);
6331 }
6332 delete context;
6333 }
6334
ParseArgsRemoveGalleryFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6335 static napi_value ParseArgsRemoveGalleryFormInfo(napi_env env, napi_callback_info info,
6336 unique_ptr<MediaLibraryAsyncContext> &context)
6337 {
6338 constexpr size_t minArgs = ARGS_ONE;
6339 constexpr size_t maxArgs = ARGS_TWO;
6340 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6341 maxArgs) == napi_ok, "Failed to get object info");
6342
6343 if (!MediaLibraryNapiUtils::IsSystemApp()) {
6344 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6345 return nullptr;
6346 }
6347
6348 bool present = false;
6349 CHECK_COND_WITH_MESSAGE(env, napi_has_named_property(env, context->argv[ARGS_ZERO], "formId", &present) == napi_ok,
6350 "Failed to get object info");
6351 if (!present) {
6352 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check empty formId!");
6353 return nullptr;
6354 }
6355
6356 napi_value value;
6357 CHECK_COND_WITH_MESSAGE(env, napi_get_named_property(env, context->argv[ARGS_ZERO], "formId", &value) == napi_ok,
6358 "failed to get named property");
6359 char buffer[ARG_BUF_SIZE];
6360 size_t res = 0;
6361 CHECK_COND_WITH_MESSAGE(env, napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res) == napi_ok,
6362 "failed to get string param");
6363 context->formId = string(buffer);
6364 CHECK_COND_WITH_MESSAGE(env, CheckFormId(context->formId) == napi_ok, "FormId is invalid");
6365 napi_value result = nullptr;
6366 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6367 return result;
6368 }
6369
ParseArgsRemoveFormInfo(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6370 static napi_value ParseArgsRemoveFormInfo(napi_env env, napi_callback_info info,
6371 unique_ptr<MediaLibraryAsyncContext> &context)
6372 {
6373 constexpr size_t minArgs = ARGS_ONE;
6374 constexpr size_t maxArgs = ARGS_TWO;
6375 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
6376 maxArgs) == napi_ok, "Failed to get object info");
6377
6378 bool present = false;
6379 CHECK_COND_WITH_MESSAGE(env, napi_has_named_property(env, context->argv[ARGS_ZERO], "formId", &present) == napi_ok,
6380 "Failed to get object info");
6381 if (!present) {
6382 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check empty formId!");
6383 return nullptr;
6384 }
6385
6386 napi_value value;
6387 CHECK_COND_WITH_MESSAGE(env, napi_get_named_property(env, context->argv[ARGS_ZERO], "formId", &value) == napi_ok,
6388 "failed to get named property");
6389 char buffer[ARG_BUF_SIZE];
6390 size_t res = 0;
6391 CHECK_COND_WITH_MESSAGE(env, napi_get_value_string_utf8(env, value, buffer, ARG_BUF_SIZE, &res) == napi_ok,
6392 "failed to get string param");
6393 context->formId = string(buffer);
6394 CHECK_COND_WITH_MESSAGE(env, CheckFormId(context->formId) == napi_ok, "FormId is invalid");
6395 napi_value result = nullptr;
6396 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6397 return result;
6398 }
6399
UpdateGalleryFormInfoExec(napi_env env,void * data,ResultNapiType type)6400 static void UpdateGalleryFormInfoExec(napi_env env, void *data, ResultNapiType type)
6401 {
6402 MediaLibraryTracer tracer;
6403 tracer.Start("UpdateGalleryFormInfoExec");
6404
6405 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6406 context->resultNapiType = type;
6407 vector<string> formIds;
6408 vector<string> fileUris;
6409 bool isValid = false;
6410 for (auto valueBucket : context->valuesBucketArray) {
6411 formIds.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_FORM_ID, isValid));
6412 fileUris.emplace_back(valueBucket.Get(TabFaCardPhotosColumn::FACARD_PHOTOS_ASSET_URI, isValid));
6413 }
6414 FormInfoReqBody reqBody;
6415 reqBody.formIds = formIds;
6416 reqBody.fileUris = fileUris;
6417 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::UPDATE_GALLERY_FORM_INFO);
6418 NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
6419 int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6420 NAPI_INFO_LOG("after IPC::UserDefineIPCClient().Call");
6421 if (ret < 0) {
6422 if (ret == E_PERMISSION_DENIED) {
6423 context->error = OHOS_PERMISSION_DENIED_CODE;
6424 } else if (ret == E_GET_PRAMS_FAIL) {
6425 context->error = OHOS_INVALID_PARAM_CODE;
6426 } else {
6427 context->SaveError(ret);
6428 }
6429 NAPI_INFO_LOG("store formInfo failed, ret: %{public}d", ret);
6430 }
6431 }
6432
RemoveGalleryFormInfoExec(napi_env env,void * data,ResultNapiType type)6433 static void RemoveGalleryFormInfoExec(napi_env env, void *data, ResultNapiType type)
6434 {
6435 MediaLibraryTracer tracer;
6436 tracer.Start("RemoveGalleryFormInfoExec");
6437
6438 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6439 context->resultNapiType = type;
6440 string formId = context->formId;
6441 if (formId.empty()) {
6442 context->error = OHOS_INVALID_PARAM_CODE;
6443 return;
6444 }
6445 FormInfoReqBody reqBody;
6446 reqBody.formIds.emplace_back(formId);
6447 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::REMOVE_GALLERY_FORM_INFO);
6448 int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6449 if (ret < 0) {
6450 if (ret == E_PERMISSION_DENIED) {
6451 context->error = OHOS_PERMISSION_DENIED_CODE;
6452 } else {
6453 context->SaveError(ret);
6454 }
6455 NAPI_ERR_LOG("remove formInfo failed, ret: %{public}d", ret);
6456 }
6457 }
6458
RemoveFormInfoExec(napi_env env,void * data,ResultNapiType type)6459 static void RemoveFormInfoExec(napi_env env, void *data, ResultNapiType type)
6460 {
6461 MediaLibraryTracer tracer;
6462 tracer.Start("RemoveFormInfoExec");
6463
6464 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6465 context->resultNapiType = type;
6466 string formId = context->formId;
6467 if (formId.empty()) {
6468 context->error = OHOS_INVALID_PARAM_CODE;
6469 return;
6470 }
6471 FormInfoReqBody reqBody;
6472 reqBody.formIds.emplace_back(formId);
6473 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::REMOVE_FORM_INFO);
6474 int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6475 if (ret < 0) {
6476 if (ret == E_PERMISSION_DENIED) {
6477 context->error = OHOS_PERMISSION_DENIED_CODE;
6478 } else {
6479 context->SaveError(ret);
6480 }
6481 NAPI_ERR_LOG("remove formInfo failed, ret: %{public}d", ret);
6482 }
6483 }
6484
RemoveFormInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)6485 static void RemoveFormInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
6486 {
6487 MediaLibraryTracer tracer;
6488 tracer.Start("RemoveFormInfoAsyncCallbackComplete");
6489
6490 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
6491 auto jsContext = make_unique<JSAsyncContextOutput>();
6492 jsContext->status = false;
6493 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6494 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6495 if (context->error != ERR_DEFAULT) {
6496 context->HandleError(env, jsContext->error);
6497 } else {
6498 jsContext->status = true;
6499 }
6500 tracer.Finish();
6501 if (context->work != nullptr) {
6502 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
6503 context->work, *jsContext);
6504 }
6505 delete context;
6506 }
6507
PhotoAccessSaveFormInfoExec(napi_env env,void * data)6508 static void PhotoAccessSaveFormInfoExec(napi_env env, void *data)
6509 {
6510 SaveFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6511 }
6512
PhotoAccessSaveFormInfo(napi_env env,napi_callback_info info)6513 napi_value MediaLibraryNapi::PhotoAccessSaveFormInfo(napi_env env, napi_callback_info info)
6514 {
6515 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6516 CHECK_NULLPTR_RET(ParseArgsSaveFormInfo(env, info, asyncContext));
6517
6518 SetUserIdFromObjectInfo(asyncContext);
6519 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessSaveFormInfo",
6520 PhotoAccessSaveFormInfoExec, SaveFormInfoAsyncCallbackComplete);
6521 }
6522
PhotoAccessSaveGalleryFormInfoExec(napi_env env,void * data)6523 static void PhotoAccessSaveGalleryFormInfoExec(napi_env env, void *data)
6524 {
6525 SaveGalleryFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6526 }
6527
PhotoAccessSaveGalleryFormInfo(napi_env env,napi_callback_info info)6528 napi_value MediaLibraryNapi::PhotoAccessSaveGalleryFormInfo(napi_env env, napi_callback_info info)
6529 {
6530 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6531 CHECK_NULLPTR_RET(ParseArgsSaveGalleryFormInfo(env, info, asyncContext));
6532
6533 SetUserIdFromObjectInfo(asyncContext);
6534 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessSaveGalleryFormInfo",
6535 PhotoAccessSaveGalleryFormInfoExec, SaveFormInfoAsyncCallbackComplete);
6536 }
6537
PhotoAccessRemoveFormInfoExec(napi_env env,void * data)6538 static void PhotoAccessRemoveFormInfoExec(napi_env env, void *data)
6539 {
6540 RemoveFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6541 }
6542
PhotoAccessRemoveGalleryFormInfoExec(napi_env env,void * data)6543 static void PhotoAccessRemoveGalleryFormInfoExec(napi_env env, void *data)
6544 {
6545 RemoveGalleryFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6546 }
6547
PhotoAccessUpdateGalleryFormInfoExec(napi_env env,void * data)6548 static void PhotoAccessUpdateGalleryFormInfoExec(napi_env env, void *data)
6549 {
6550 UpdateGalleryFormInfoExec(env, data, ResultNapiType::TYPE_PHOTOACCESS_HELPER);
6551 }
6552
PhotoAccessRemoveGalleryFormInfo(napi_env env,napi_callback_info info)6553 napi_value MediaLibraryNapi::PhotoAccessRemoveGalleryFormInfo(napi_env env, napi_callback_info info)
6554 {
6555 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6556 CHECK_NULLPTR_RET(ParseArgsRemoveGalleryFormInfo(env, info, asyncContext));
6557
6558 SetUserIdFromObjectInfo(asyncContext);
6559 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveGalleryFormInfo",
6560 PhotoAccessRemoveGalleryFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
6561 }
6562
PhotoAccessUpdateGalleryFormInfo(napi_env env,napi_callback_info info)6563 napi_value MediaLibraryNapi::PhotoAccessUpdateGalleryFormInfo(napi_env env, napi_callback_info info)
6564 {
6565 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6566 CHECK_NULLPTR_RET(ParseArgsUpdateGalleryFormInfo(env, info, asyncContext));
6567
6568 SetUserIdFromObjectInfo(asyncContext);
6569 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveGalleryFormInfo",
6570 PhotoAccessUpdateGalleryFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
6571 }
6572
PhotoAccessRemoveFormInfo(napi_env env,napi_callback_info info)6573 napi_value MediaLibraryNapi::PhotoAccessRemoveFormInfo(napi_env env, napi_callback_info info)
6574 {
6575 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
6576 CHECK_NULLPTR_RET(ParseArgsRemoveFormInfo(env, info, asyncContext));
6577
6578 SetUserIdFromObjectInfo(asyncContext);
6579 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessRemoveFormInfo",
6580 PhotoAccessRemoveFormInfoExec, RemoveFormInfoAsyncCallbackComplete);
6581 }
6582
ParseArgsStartCreateThumbnailTask(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6583 static napi_value ParseArgsStartCreateThumbnailTask(napi_env env,
6584 napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
6585 {
6586 if (!MediaLibraryNapiUtils::IsSystemApp()) {
6587 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6588 return nullptr;
6589 }
6590
6591 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
6592 env, info, context, ARGS_TWO, ARGS_TWO), JS_ERR_PARAMETER_INVALID);
6593 CHECK_COND_WITH_MESSAGE(env, context->callbackRef, "Can not get callback function");
6594 CHECK_ARGS(env, MediaLibraryNapiUtils::ParsePredicates(env,
6595 context->argv[PARAM0], context, ASSET_FETCH_OPT), JS_INNER_FAIL);
6596
6597 napi_value result = nullptr;
6598 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6599 return result;
6600 }
6601
RegisterThumbnailGenerateObserver(napi_env env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)6602 static void RegisterThumbnailGenerateObserver(napi_env env,
6603 std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
6604 {
6605 std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
6606 if (thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
6607 NAPI_INFO_LOG("RequestId: %{public}d exist in observer map, no need to register", requestId);
6608 return;
6609 }
6610 dataObserver = std::make_shared<ThumbnailBatchGenerateObserver>();
6611 std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
6612 UserFileClient::RegisterObserverExt(Uri(observerUri), dataObserver, false);
6613 thumbnailGenerateObserverMap.Insert(requestId, dataObserver);
6614 }
6615
UnregisterThumbnailGenerateObserver(int32_t requestId)6616 static void UnregisterThumbnailGenerateObserver(int32_t requestId)
6617 {
6618 std::shared_ptr<ThumbnailBatchGenerateObserver> dataObserver;
6619 if (!thumbnailGenerateObserverMap.Find(requestId, dataObserver)) {
6620 return;
6621 }
6622
6623 std::string observerUri = PhotoColumn::PHOTO_URI_PREFIX + std::to_string(requestId);
6624 UserFileClient::UnregisterObserverExt(Uri(observerUri), dataObserver);
6625 thumbnailGenerateObserverMap.Erase(requestId);
6626 }
6627
DeleteThumbnailHandler(int32_t requestId)6628 static void DeleteThumbnailHandler(int32_t requestId)
6629 {
6630 std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6631 if (!thumbnailGenerateHandlerMap.Find(requestId, dataHandler)) {
6632 return;
6633 }
6634 napi_release_threadsafe_function(dataHandler->threadSafeFunc_, napi_tsfn_release);
6635 thumbnailGenerateHandlerMap.Erase(requestId);
6636 }
6637
ReleaseThumbnailTask(int32_t requestId)6638 static void ReleaseThumbnailTask(int32_t requestId)
6639 {
6640 UnregisterThumbnailGenerateObserver(requestId);
6641 DeleteThumbnailHandler(requestId);
6642 }
6643
CreateThumbnailHandler(napi_env env,std::unique_ptr<MediaLibraryAsyncContext> & asyncContext,int32_t requestId)6644 static void CreateThumbnailHandler(napi_env env,
6645 std::unique_ptr<MediaLibraryAsyncContext> &asyncContext, int32_t requestId)
6646 {
6647 napi_value workName = nullptr;
6648 napi_create_string_utf8(env, "ThumbSafeThread", NAPI_AUTO_LENGTH, &workName);
6649 napi_threadsafe_function threadSafeFunc;
6650 napi_status status = napi_create_threadsafe_function(env, asyncContext->argv[PARAM1], NULL, workName, 0, 1,
6651 NULL, NULL, NULL, MediaLibraryNapi::OnThumbnailGenerated, &threadSafeFunc);
6652 if (status != napi_ok) {
6653 NAPI_ERR_LOG("napi_create_threadsafe_function fail");
6654 ReleaseThumbnailTask(requestId);
6655 asyncContext->SaveError(JS_INNER_FAIL);
6656 return;
6657 }
6658 std::shared_ptr<ThumbnailGenerateHandler> dataHandler =
6659 std::make_shared<ThumbnailGenerateHandler>(asyncContext->callbackRef, threadSafeFunc);
6660 thumbnailGenerateHandlerMap.Insert(requestId, dataHandler);
6661 }
6662
OnThumbnailGenerated(napi_env env,napi_value cb,void * context,void * data)6663 void MediaLibraryNapi::OnThumbnailGenerated(napi_env env, napi_value cb, void *context, void *data)
6664 {
6665 if (env == nullptr) {
6666 return;
6667 }
6668 std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6669 if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
6670 return;
6671 }
6672
6673 napi_status status = napi_get_reference_value(env, dataHandler->callbackRef_, &cb);
6674 if (status != napi_ok) {
6675 NapiError::ThrowError(env, JS_INNER_FAIL, "napi_get_reference_value fail");
6676 return;
6677 }
6678
6679 napi_value result = nullptr;
6680 status = napi_call_function(env, nullptr, cb, 0, nullptr, &result);
6681 if (status != napi_ok) {
6682 NapiError::ThrowError(env, JS_INNER_FAIL, "calling onDataPrepared failed");
6683 }
6684 }
6685
AssignRequestId()6686 static int32_t AssignRequestId()
6687 {
6688 return ++requestIdCounter_;
6689 }
6690
GetRequestId()6691 static int32_t GetRequestId()
6692 {
6693 return requestIdCounter_;
6694 }
6695
PhotoAccessStartCreateThumbnailTask(napi_env env,napi_callback_info info)6696 napi_value MediaLibraryNapi::PhotoAccessStartCreateThumbnailTask(napi_env env, napi_callback_info info)
6697 {
6698 MediaLibraryTracer tracer;
6699 tracer.Start("PhotoAccessStartCreateThumbnailTask");
6700 std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
6701 CHECK_NULLPTR_RET(ParseArgsStartCreateThumbnailTask(env, info, asyncContext));
6702
6703 ReleaseThumbnailTask(GetRequestId());
6704 int32_t requestId = AssignRequestId();
6705 RegisterThumbnailGenerateObserver(env, asyncContext, requestId);
6706 CreateThumbnailHandler(env, asyncContext, requestId);
6707
6708 StartThumbnailCreationTaskReqBody reqBody;
6709 reqBody.predicates = asyncContext->predicates;
6710 reqBody.requestId = requestId;
6711 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_START_THUMBNAIL_CREATION_TASK);
6712 NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call, %{public}d", requestId);
6713 int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6714 NAPI_INFO_LOG("after IPC::UserDefineIPCClient().Call");
6715
6716 napi_value result = nullptr;
6717 NAPI_CALL(env, napi_get_undefined(env, &result));
6718 if (changedRows < 0) {
6719 ReleaseThumbnailTask(requestId);
6720 asyncContext->SaveError(changedRows);
6721 NAPI_ERR_LOG("Create thumbnail task, update failed, err: %{public}d", changedRows);
6722 napi_create_int32(env, changedRows, &result);
6723 return result;
6724 }
6725 napi_create_int32(env, requestId, &result);
6726 return result;
6727 }
6728
OnChange(const ChangeInfo & changeInfo)6729 void ThumbnailBatchGenerateObserver::OnChange(const ChangeInfo &changeInfo)
6730 {
6731 if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_THUMB_UPDATE)) {
6732 return;
6733 }
6734
6735 for (auto &uri : changeInfo.uris_) {
6736 string uriString = uri.ToString();
6737 auto pos = uriString.find_last_of('/');
6738 if (pos == std::string::npos) {
6739 continue;
6740 }
6741 if (!MediaFileUtils::IsValidInteger(uriString.substr(pos + 1))) {
6742 continue;
6743 }
6744 requestIdCallback_ = std::stoi(uriString.substr(pos + 1));
6745 std::shared_ptr<ThumbnailGenerateHandler> dataHandler;
6746 if (!thumbnailGenerateHandlerMap.Find(requestIdCallback_, dataHandler)) {
6747 continue;
6748 }
6749
6750 napi_status status = napi_acquire_threadsafe_function(dataHandler->threadSafeFunc_);
6751 if (status != napi_ok) {
6752 ReleaseThumbnailTask(requestIdCallback_);
6753 NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
6754 continue;
6755 }
6756 status = napi_call_threadsafe_function(dataHandler->threadSafeFunc_, NULL, napi_tsfn_blocking);
6757 if (status != napi_ok) {
6758 ReleaseThumbnailTask(requestIdCallback_);
6759 NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
6760 continue;
6761 }
6762 }
6763 }
6764
ParseArgsStopCreateThumbnailTask(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)6765 static napi_value ParseArgsStopCreateThumbnailTask(napi_env env,
6766 napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
6767 {
6768 if (!MediaLibraryNapiUtils::IsSystemApp()) {
6769 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
6770 return nullptr;
6771 }
6772
6773 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env,
6774 info, context, ARGS_ONE, ARGS_ONE), JS_ERR_PARAMETER_INVALID);
6775 napi_value result = nullptr;
6776 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
6777 return result;
6778 }
6779
PhotoAccessStopCreateThumbnailTask(napi_env env,napi_callback_info info)6780 napi_value MediaLibraryNapi::PhotoAccessStopCreateThumbnailTask(napi_env env, napi_callback_info info)
6781 {
6782 MediaLibraryTracer tracer;
6783 tracer.Start("PhotoAccessStopCreateThumbnailTask");
6784 std::unique_ptr<MediaLibraryAsyncContext> asyncContext = std::make_unique<MediaLibraryAsyncContext>();
6785 CHECK_NULLPTR_RET(ParseArgsStopCreateThumbnailTask(env, info, asyncContext));
6786
6787 int32_t requestId = 0;
6788 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetInt32(env,
6789 asyncContext->argv[PARAM0], requestId) == napi_ok, "Failed to get requestId");
6790 if (requestId <= 0) {
6791 NAPI_WARN_LOG("Invalid requestId: %{public}d", requestId);
6792 RETURN_NAPI_UNDEFINED(env);
6793 }
6794 ReleaseThumbnailTask(requestId);
6795
6796 StopThumbnailCreationTaskReqBody reqBody;
6797 reqBody.requestId = requestId;
6798 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_STOP_THUMBNAIL_CREATION_TASK);
6799 NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
6800 int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
6801 NAPI_INFO_LOG("after IPC::UserDefineIPCClient().Call");
6802 if (changedRows < 0) {
6803 asyncContext->SaveError(changedRows);
6804 NAPI_ERR_LOG("Stop create thumbnail task, update failed, err: %{public}d", changedRows);
6805 }
6806 RETURN_NAPI_UNDEFINED(env);
6807 }
6808
GetMediaAnalysisServiceProgress(nlohmann::json & jsonObj,unordered_map<int,string> & idxToCount)6809 static void GetMediaAnalysisServiceProgress(nlohmann::json& jsonObj, unordered_map<int, string>& idxToCount)
6810 {
6811 int errCode = 0;
6812 GetAnalysisProcessReqBody reqBody;
6813 reqBody.analysisType = AnalysisType::ANALYSIS_LABEL;
6814 QueryResultRespBody respBody;
6815 errCode = IPC::UserDefineIPCClient().Call(
6816 static_cast<uint32_t>(MediaLibraryBusinessCode::GET_ANALYSIS_PROCESS), reqBody, respBody);
6817 shared_ptr<DataShare::DataShareResultSet> ret = respBody.resultSet;
6818 if (ret == nullptr) {
6819 NAPI_ERR_LOG("ret is nullptr");
6820 return;
6821 }
6822 if (ret->GoToFirstRow() != NativeRdb::E_OK) {
6823 NAPI_ERR_LOG("GotoFirstRow failed, errCode is %{public}d", errCode);
6824 ret->Close();
6825 return;
6826 }
6827 for (size_t i = 0; i < idxToCount.size(); ++i) {
6828 int tmp = -1;
6829 ret->GetInt(i, tmp);
6830 jsonObj[idxToCount[i]] = tmp;
6831 }
6832 ret->Close();
6833 }
6834
GetLabelAnalysisProgress()6835 static std::string GetLabelAnalysisProgress()
6836 {
6837 unordered_map<int, string> idxToCount = {
6838 {0, "totalCount"}, {1, "finishedCount"}, {2, "LabelCount"}
6839 };
6840 nlohmann::json jsonObj;
6841 GetMediaAnalysisServiceProgress(jsonObj, idxToCount);
6842 NAPI_INFO_LOG("Progress json is %{public}s", jsonObj.dump().c_str());
6843 return jsonObj.dump();
6844 }
6845
GetTotalCount()6846 static std::string GetTotalCount()
6847 {
6848 Uri uri(URI_TOTAL);
6849 string clause = VISION_TOTAL_TABLE + "." + MediaColumn::MEDIA_ID + " = " + PhotoColumn::PHOTOS_TABLE+ "." +
6850 MediaColumn::MEDIA_ID;
6851 DataShare::DataSharePredicates predicates;
6852 predicates.InnerJoin(PhotoColumn::PHOTOS_TABLE)->On({ clause });
6853 predicates.EqualTo(PhotoColumn::PHOTO_HIDDEN_TIME, 0)->And()
6854 ->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, 0)->And()
6855 ->EqualTo(MediaColumn::MEDIA_TIME_PENDING, 0);
6856
6857 vector<string> column = {
6858 "SUM(CASE WHEN (media_type = 1 OR (media_type = 2 AND (position = 1 OR position = 3))) THEN 1 ELSE 0 END) AS "
6859 "totalCount"
6860 };
6861
6862 int errCode = 0;
6863 shared_ptr<DataShare::DataShareResultSet> ret = UserFileClient::Query(uri, predicates, column, errCode);
6864 if (ret == nullptr) {
6865 NAPI_ERR_LOG("ret is nullptr");
6866 return "";
6867 }
6868 if (ret->GoToFirstRow() != NativeRdb::E_OK) {
6869 ret->Close();
6870 NAPI_ERR_LOG("GotoFirstRow failed, errCode is %{public}d", errCode);
6871 return "";
6872 }
6873 int totalCount = 0;
6874 ret->GetInt(0, totalCount);
6875 ret->Close();
6876 return to_string(totalCount);
6877 }
6878
GetFaceAnalysisProgress()6879 static std::string GetFaceAnalysisProgress()
6880 {
6881 string curTotalCount = GetTotalCount();
6882
6883 int errCode = 0;
6884 GetAnalysisProcessReqBody reqBody;
6885 reqBody.analysisType = AnalysisType::ANALYSIS_FACE;
6886 QueryResultRespBody respBody;
6887 errCode = IPC::UserDefineIPCClient().Call(
6888 static_cast<uint32_t>(MediaLibraryBusinessCode::GET_ANALYSIS_PROCESS), reqBody, respBody);
6889 shared_ptr<DataShare::DataShareResultSet> ret = respBody.resultSet;
6890 if (ret == nullptr) {
6891 NAPI_ERR_LOG("ret is nullptr");
6892 return "";
6893 }
6894 if (ret->GoToNextRow() != NativeRdb::E_OK) {
6895 ret->Close();
6896 nlohmann::json jsonObj;
6897 jsonObj["cvFinishedCount"] = 0;
6898 jsonObj["geoFinishedCount"] = 0;
6899 jsonObj["searchFinishedCount"] = 0;
6900 jsonObj["totalCount"] = curTotalCount;
6901 string retJson = jsonObj.dump();
6902 NAPI_ERR_LOG("GetFaceAnalysisProgress failed, errCode is %{public}d, json is %{public}s", errCode,
6903 retJson.c_str());
6904 return retJson;
6905 }
6906 string retJson = MediaLibraryNapiUtils::GetStringValueByColumn(ret, HIGHLIGHT_ANALYSIS_PROGRESS);
6907 if (retJson == "" || !nlohmann::json::accept(retJson)) {
6908 ret->Close();
6909 NAPI_ERR_LOG("retJson is empty or invalid");
6910 return "";
6911 }
6912 nlohmann::json curJsonObj = nlohmann::json::parse(retJson);
6913 int preTotalCount = curJsonObj["totalCount"];
6914 if (to_string(preTotalCount) != curTotalCount) {
6915 NAPI_ERR_LOG("preTotalCount != curTotalCount, curTotalCount is %{public}s, preTotalCount is %{public}d",
6916 curTotalCount.c_str(), preTotalCount);
6917 curJsonObj["totalCount"] = curTotalCount;
6918 }
6919 retJson = curJsonObj.dump();
6920 NAPI_INFO_LOG("GoToNextRow successfully and json is %{public}s", retJson.c_str());
6921 ret->Close();
6922 return retJson;
6923 }
6924
GetHighlightAnalysisProgress()6925 static std::string GetHighlightAnalysisProgress()
6926 {
6927 unordered_map<int, string> idxToCount = {
6928 {0, "ClearCount"}, {1, "DeleteCount"}, {2, "NotProduceCount"}, {3, "ProduceCount"}, {4, "PushCount"}
6929 };
6930 int errCode = 0;
6931 GetAnalysisProcessReqBody reqBody;
6932 reqBody.analysisType = AnalysisType::ANALYSIS_HIGHLIGHT;
6933 QueryResultRespBody respBody;
6934 errCode = IPC::UserDefineIPCClient().Call(
6935 static_cast<uint32_t>(MediaLibraryBusinessCode::GET_ANALYSIS_PROCESS), reqBody, respBody);
6936 shared_ptr<DataShare::DataShareResultSet> ret = respBody.resultSet;
6937 if (ret == nullptr) {
6938 NAPI_ERR_LOG("ret is nullptr");
6939 return "";
6940 }
6941 if (ret->GoToFirstRow() != NativeRdb::E_OK) {
6942 NAPI_ERR_LOG("GotoFirstRow failed, errCode is %{public}d", errCode);
6943 ret->Close();
6944 return "";
6945 }
6946 nlohmann::json jsonObj;
6947 for (size_t i = 0; i < idxToCount.size(); ++i) {
6948 int tmp = -1;
6949 ret->GetInt(i, tmp);
6950 jsonObj[idxToCount[i]] = tmp;
6951 }
6952 ret->Close();
6953 string retStr = jsonObj.dump();
6954 NAPI_INFO_LOG("Progress json is %{public}s", retStr.c_str());
6955 return retStr;
6956 }
6957
JSGetAnalysisProgressExecute(MediaLibraryAsyncContext * context)6958 static void JSGetAnalysisProgressExecute(MediaLibraryAsyncContext* context)
6959 {
6960 MediaLibraryTracer tracer;
6961 tracer.Start("JSGetAnalysisProgressExecute");
6962 std::vector<std::string> fetchColumn;
6963 DataShare::DataSharePredicates predicates;
6964 switch (context->analysisType) {
6965 case ANALYSIS_LABEL: {
6966 context->analysisProgress = GetLabelAnalysisProgress();
6967 break;
6968 }
6969 case ANALYSIS_FACE: {
6970 context->analysisProgress = GetFaceAnalysisProgress();
6971 break;
6972 }
6973 case ANALYSIS_HIGHLIGHT: {
6974 context->analysisProgress = GetHighlightAnalysisProgress();
6975 break;
6976 }
6977 default:
6978 break;
6979 }
6980 }
6981
JSGetDataAnalysisProgressCompleteCallback(napi_env env,napi_status status,void * data)6982 static void JSGetDataAnalysisProgressCompleteCallback(napi_env env, napi_status status, void *data)
6983 {
6984 MediaLibraryTracer tracer;
6985 tracer.Start("JSGetDataAnalysisProgressCompleteCallback");
6986 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
6987 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
6988 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
6989 jsContext->status = false;
6990 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
6991 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
6992 if (context->error == ERR_DEFAULT) {
6993 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, context->analysisProgress.c_str(),
6994 NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
6995 jsContext->status = true;
6996 } else {
6997 context->HandleError(env, jsContext->error);
6998 }
6999 tracer.Finish();
7000 if (context->work != nullptr) {
7001 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work,
7002 *jsContext);
7003 }
7004 delete context;
7005 }
7006
PhotoAccessHelperGetDataAnalysisProgress(napi_env env,napi_callback_info info)7007 napi_value MediaLibraryNapi::PhotoAccessHelperGetDataAnalysisProgress(napi_env env, napi_callback_info info)
7008 {
7009 MediaLibraryTracer tracer;
7010 tracer.Start("PhotoAccessHelperGetDataAnalysisProgress");
7011
7012 napi_value result = nullptr;
7013 NAPI_CALL(env, napi_get_undefined(env, &result));
7014 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7015 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
7016 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7017 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->analysisType),
7018 JS_ERR_PARAMETER_INVALID);
7019
7020 SetUserIdFromObjectInfo(asyncContext);
7021 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetDataAnalysisProgress",
7022 [](napi_env env, void *data) {
7023 auto context = static_cast<MediaLibraryAsyncContext*>(data);
7024 JSGetAnalysisProgressExecute(context);
7025 }, reinterpret_cast<CompleteCallback>(JSGetDataAnalysisProgressCompleteCallback));
7026 }
7027
JSGetAnalysisDataCompleteCallback(napi_env env,napi_status status,void * data)7028 static void JSGetAnalysisDataCompleteCallback(napi_env env, napi_status status, void *data)
7029 {
7030 MediaLibraryTracer tracer;
7031 tracer.Start("JSGetAnalysisDataCompleteCallback");
7032
7033 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
7034 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
7035
7036 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7037 jsContext->status = false;
7038
7039 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7040 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7041 if (context->error == ERR_DEFAULT) {
7042 napi_value returnArray;
7043 napi_create_array(env, &returnArray);
7044 for (size_t i = 0; i < context->analysisDatas.size(); ++i) {
7045 napi_value element;
7046 napi_create_string_utf8(env, context->analysisDatas[i].c_str(), NAPI_AUTO_LENGTH, &element);
7047 napi_set_element(env, returnArray, i, element);
7048 }
7049 jsContext->data = returnArray;
7050 jsContext->status = true;
7051 } else {
7052 context->HandleError(env, jsContext->error);
7053 }
7054
7055 tracer.Finish();
7056 if (context->work != nullptr) {
7057 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7058 context->work, *jsContext);
7059 }
7060 delete context;
7061 }
7062
JSGetAnalysisDataExecute(napi_env env,MediaLibraryAsyncContext * context)7063 static void JSGetAnalysisDataExecute(napi_env env, MediaLibraryAsyncContext *context)
7064 {
7065 MediaLibraryTracer tracer;
7066 tracer.Start("JSGetAnalysisDataExecute");
7067
7068 std::string analysisUri;
7069 if (context->isForce) {
7070 analysisUri = PAH_QUERY_ANA_ADDRESS_ASSETS_ACTIVE;
7071 } else {
7072 analysisUri = PAH_QUERY_ANA_ADDRESS_ASSETS;
7073 }
7074 Uri uri(analysisUri);
7075 DataSharePredicates predicates;
7076 vector<string> columns;
7077
7078 if (context->analysisType == ANALYSIS_DETAIL_ADDRESS) {
7079 columns = { PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, PhotoColumn::PHOTOS_TABLE + "." + LATITUDE,
7080 PhotoColumn::PHOTOS_TABLE + "." + LONGITUDE, LANGUAGE, COUNTRY, ADMIN_AREA, SUB_ADMIN_AREA, LOCALITY,
7081 SUB_LOCALITY, THOROUGHFARE, SUB_THOROUGHFARE, FEATURE_NAME, CITY_NAME, ADDRESS_DESCRIPTION, LOCATION_TYPE,
7082 AOI, POI, FIRST_AOI, FIRST_POI, LOCATION_VERSION, FIRST_AOI_CATEGORY, FIRST_POI_CATEGORY};
7083 string language = Global::I18n::LocaleConfig::GetSystemLanguage();
7084 //Chinese and English supported. Other languages English default.
7085 language = (language.find(LANGUAGE_ZH) == 0 || language.find(LANGUAGE_ZH_TR) == 0) ? LANGUAGE_ZH : LANGUAGE_EN;
7086 vector<string> onClause = { PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::MEDIA_ID + " = " +
7087 GEO_KNOWLEDGE_TABLE + "." + FILE_ID + " AND " +
7088 GEO_KNOWLEDGE_TABLE + "." + LANGUAGE + " = \'" + language + "\'" };
7089 predicates.LeftOuterJoin(GEO_KNOWLEDGE_TABLE)->On(onClause);
7090 predicates.In(PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, context->uris);
7091 } else {
7092 predicates.In(MediaColumn::MEDIA_ID, context->uris);
7093 }
7094
7095 int errCode = 0;
7096 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode,
7097 context->userId);
7098 if (resultSet == nullptr) {
7099 NAPI_ERR_LOG("Query geo assets list failed");
7100 return;
7101 }
7102 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
7103 nlohmann::json jsonObject;
7104 for (uint32_t i = 0; i < columns.size(); i++) {
7105 string columnName = columns[i];
7106 auto it = NEED_COMPATIBLE_COLUMN_MAP.find(context->analysisType);
7107 if (it != NEED_COMPATIBLE_COLUMN_MAP.end() && columnName == it->second) {
7108 jsonObject[columnName] = MediaLibraryNapiUtils::ParseColumnNeedCompatible(resultSet,
7109 context->analysisType, columnName);
7110 } else {
7111 jsonObject[columnName] = MediaLibraryNapiUtils::GetStringValueByColumn(resultSet, columnName);
7112 }
7113 }
7114 context->analysisDatas.push_back(jsonObject.dump());
7115 }
7116 }
7117
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)7118 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
7119 {
7120 bool isArray = false;
7121 CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
7122 if (!isArray) {
7123 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array type");
7124 return nullptr;
7125 }
7126
7127 uint32_t len = 0;
7128 CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
7129 if (len <= 0) {
7130 NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
7131 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array length");
7132 return nullptr;
7133 }
7134
7135 for (uint32_t i = 0; i < len; i++) {
7136 napi_value asset = nullptr;
7137 CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
7138 if (asset == nullptr) {
7139 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset element");
7140 return nullptr;
7141 }
7142
7143 FileAssetNapi *obj = nullptr;
7144 CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
7145 if (obj == nullptr) {
7146 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset napi object");
7147 return nullptr;
7148 }
7149 if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
7150 NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
7151 continue;
7152 }
7153 assetsArray.push_back(to_string(obj->GetFileId()));
7154 }
7155
7156 napi_value result = nullptr;
7157 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7158 return result;
7159 }
7160
ParseArgsStartAssetAnalysis(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7161 static napi_value ParseArgsStartAssetAnalysis(napi_env env, napi_callback_info info,
7162 unique_ptr<MediaLibraryAsyncContext> &context)
7163 {
7164 constexpr size_t minArgs = ARGS_ONE;
7165 constexpr size_t maxArgs = ARGS_TWO;
7166 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs,
7167 maxArgs) == napi_ok, "Failed to get object info");
7168
7169 if (!MediaLibraryNapiUtils::IsSystemApp()) {
7170 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7171 return nullptr;
7172 }
7173
7174 // Parse analysis type
7175 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_ZERO],
7176 context->analysisType) == napi_ok, "analysisType invalid");
7177 CHECK_COND_WITH_MESSAGE(env, context->analysisType > AnalysisType::ANALYSIS_INVALID,
7178 "analysisType invalid:" + std::to_string(context->analysisType));
7179 CHECK_COND_WITH_MESSAGE(env,
7180 FOREGROUND_ANALYSIS_ASSETS_MAP.find(context->analysisType) != FOREGROUND_ANALYSIS_ASSETS_MAP.end(),
7181 "analysisType is not supported:" + std::to_string(context->analysisType));
7182
7183 // Parse asset uris
7184 if (context->argc == ARGS_TWO) {
7185 vector<string> uris;
7186 CHECK_ARGS(env, MediaLibraryNapiUtils::GetStringArray(env, context->argv[ARGS_ONE], uris),
7187 OHOS_INVALID_PARAM_CODE);
7188 for (const auto &uri : uris) {
7189 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
7190 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check uri format, not a photo uri!");
7191 return nullptr;
7192 }
7193 }
7194 if (!uris.empty()) {
7195 context->uris = uris;
7196 }
7197 } else if (context->argc == ARGS_ONE) {
7198 context->isFullAnalysis = true;
7199 }
7200
7201 if (context->objectInfo) {
7202 context->userId = context->objectInfo->GetUserId();
7203 } else {
7204 NAPI_ERR_LOG("objectInfo is nullptr.");
7205 }
7206
7207 napi_value result = nullptr;
7208 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7209 return result;
7210 }
7211
JSStartAssetAnalysisCallback(napi_env env,napi_status status,void * data)7212 static void JSStartAssetAnalysisCallback(napi_env env, napi_status status, void *data)
7213 {
7214 MediaLibraryTracer tracer;
7215 tracer.Start("JSStartAssetAnalysisCallback");
7216
7217 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
7218 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
7219
7220 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7221 jsContext->status = false;
7222
7223 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7224 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7225
7226 if (context->error == ERR_DEFAULT) {
7227 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->taskId, &jsContext->data), JS_INNER_FAIL);
7228 jsContext->status = true;
7229 } else {
7230 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, -1, &jsContext->data), JS_INNER_FAIL);
7231 context->HandleError(env, jsContext->error);
7232 }
7233
7234 tracer.Finish();
7235 if (context->work != nullptr) {
7236 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7237 context->work, *jsContext);
7238 }
7239 delete context;
7240 }
7241
ParseArgsAnalysisData(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7242 static napi_value ParseArgsAnalysisData(napi_env env, napi_callback_info info,
7243 unique_ptr<MediaLibraryAsyncContext> &context)
7244 {
7245 constexpr size_t minArgs = ARGS_ONE;
7246 constexpr size_t maxArgs = ARGS_THREE;
7247 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
7248 napi_ok, "Failed to get object info");
7249
7250 if (!MediaLibraryNapiUtils::IsSystemApp()) {
7251 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
7252 return nullptr;
7253 }
7254
7255 // Parse analysis type
7256 CHECK_ARGS(env, MediaLibraryNapiUtils::GetInt32(env, context->argv[ARGS_ZERO], context->analysisType),
7257 JS_ERR_PARAMETER_INVALID);
7258
7259 // Parse asset uris
7260 vector<string> uris;
7261 CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[ARGS_ONE], uris));
7262 if (uris.empty()) {
7263 NAPI_ERR_LOG("Geo assets list empty");
7264 return nullptr;
7265 }
7266 context->uris = uris;
7267
7268 //Parse isForce
7269 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[ARGS_TWO], context->isForce),
7270 JS_ERR_PARAMETER_INVALID);
7271
7272 napi_value result = nullptr;
7273 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7274 return result;
7275 }
7276
PhotoAccessHelperGetAnalysisData(napi_env env,napi_callback_info info)7277 napi_value MediaLibraryNapi::PhotoAccessHelperGetAnalysisData(napi_env env, napi_callback_info info)
7278 {
7279 MediaLibraryTracer tracer;
7280 tracer.Start("PhotoAccessHelperGetAnalysisData");
7281
7282 napi_value result = nullptr;
7283 NAPI_CALL(env, napi_get_undefined(env, &result));
7284 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7285 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
7286
7287 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
7288 CHECK_NULLPTR_RET(ParseArgsAnalysisData(env, info, asyncContext));
7289
7290 SetUserIdFromObjectInfo(asyncContext);
7291 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetAnalysisData",
7292 [](napi_env env, void *data) {
7293 auto context = static_cast<MediaLibraryAsyncContext*>(data);
7294 JSGetAnalysisDataExecute(env, context);
7295 }, reinterpret_cast<CompleteCallback>(JSGetAnalysisDataCompleteCallback));
7296 }
7297
JSGetPhotoAssets(napi_env env,napi_callback_info info)7298 napi_value MediaLibraryNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
7299 {
7300 MediaLibraryTracer tracer;
7301 tracer.Start("JSGetPhotoAssets");
7302
7303 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7304 asyncContext->assetType = TYPE_PHOTO;
7305 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7306
7307 SetUserIdFromObjectInfo(asyncContext);
7308 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
7309 JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7310 }
7311
7312 // Easter egg operation: query duplicate assets
EasterEgg(MediaLibraryAsyncContext * context)7313 static bool EasterEgg(MediaLibraryAsyncContext* context)
7314 {
7315 if (context->uri == URI_FIND_ALL_DUPLICATE_ASSETS) {
7316 context->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_ALL_DUPLICATE_ASSETS);
7317 } else if (context->uri == URI_FIND_ALL_DUPLICATE_ASSETS_TO_DELETE) {
7318 context->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_DUPLICATE_ASSETS_TO_DELETE);
7319 } else {
7320 return false;
7321 }
7322 if (!MediaLibraryNapiUtils::IsSystemApp()) {
7323 NAPI_ERR_LOG("Easter egg operation failed, target is not system app");
7324 return false;
7325 };
7326 bool isQueryCount = find(context->fetchColumn.begin(), context->fetchColumn.end(), MEDIA_COLUMN_COUNT)
7327 != context->fetchColumn.end();
7328 int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
7329 NAPI_INFO_LOG(
7330 "Easter egg operation start: %{public}s, is query count: %{public}d",
7331 context->businessCode == static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_ALL_DUPLICATE_ASSETS) ?
7332 "find all duplicate assets" : "find all duplicate assets to delete", isQueryCount);
7333
7334 GetAssetsReqBody reqBody;
7335 reqBody.predicates = context->predicates;
7336 reqBody.columns = context->fetchColumn;
7337 GetAssetsRespBody respBody;
7338 int32_t errCode =
7339 IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
7340
7341 if (errCode != E_OK || respBody.resultSet == nullptr) {
7342 context->SaveError(errCode);
7343 NAPI_ERR_LOG("Easter egg operation failed, errCode: %{public}d", errCode);
7344 return true;
7345 }
7346
7347 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(respBody.resultSet));
7348 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7349 NAPI_INFO_LOG(
7350 "Easter egg operation end: %{public}s, is query count: %{public}d, cost time: %{public}" PRId64 "ms",
7351 context->businessCode == static_cast<uint32_t>(MediaLibraryBusinessCode::FIND_ALL_DUPLICATE_ASSETS) ?
7352 "find all duplicate assets" : "find all duplicate assets to delete", isQueryCount,
7353 MediaFileUtils::UTCTimeMilliSeconds() - startTime);
7354 return true;
7355 }
7356
PhotoAccessGetAssetsExecute(napi_env env,void * data)7357 static void PhotoAccessGetAssetsExecute(napi_env env, void *data)
7358 {
7359 MediaLibraryTracer tracer;
7360 tracer.Start("PhotoAccessGetAssetsExecute");
7361
7362 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
7363 CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
7364
7365 if (EasterEgg(context)) {
7366 return;
7367 }
7368 string queryUri = PAH_QUERY_PHOTO;
7369 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7370 Uri uri(queryUri);
7371 int errCode = 0;
7372 auto [accessSandbox, resultSet] = UserFileClient::QueryAccessibleViaSandBox(
7373 uri, context->predicates, context->fetchColumn, errCode, context->userId);
7374 if (accessSandbox) {
7375 if (resultSet == nullptr) {
7376 NAPI_ERR_LOG("QueryAccessibleViaSandBox failed, resultSet is nullptr");
7377 }
7378 } else {
7379 GetAssetsReqBody reqBody;
7380 reqBody.predicates = context->predicates;
7381 reqBody.columns = context->fetchColumn;
7382 reqBody.burstKey = context->burstKey;
7383 GetAssetsRespBody respBody;
7384 errCode = IPC::UserDefineIPCClient()
7385 .SetUserId(context->userId)
7386 .Call(context->businessCode, reqBody, respBody);
7387 if (errCode == E_OK) {
7388 resultSet = respBody.resultSet;
7389 } else {
7390 NAPI_ERR_LOG("UserDefineIPCClient Call failed, errCode is %{public}d", errCode);
7391 }
7392 }
7393
7394 if (resultSet == nullptr) {
7395 NAPI_ERR_LOG("resultSet is nullptr, errCode is %{public}d", errCode);
7396 context->SaveError(errCode);
7397 return;
7398 }
7399 tracer.Start("MakeFetchResult");
7400 context->fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
7401 tracer.Finish();
7402 context->fetchFileResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7403 context->fetchFileResult->SetUserId(context->userId);
7404 }
7405
PhotoAccessGetAssetsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)7406 static napi_value PhotoAccessGetAssetsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
7407 {
7408 auto context = &asyncContext;
7409 if (context->assetType != TYPE_PHOTO) {
7410 return nullptr;
7411 }
7412 string queryUri = PAH_QUERY_PHOTO;
7413 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7414 Uri uri(queryUri);
7415 int errCode = 0;
7416 RdbPredicates rdbPredicates = RdbDataShareAdapter::RdbUtils::ToPredicates(context->predicates, "Photos");
7417 NAPI_INFO_LOG("Predicates: %{public}s", rdbPredicates.ToString().c_str());
7418 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri,
7419 context->predicates, context->fetchColumn, errCode, context->userId);
7420 if (resultSet == nullptr && !context->uri.empty() && errCode == E_PERMISSION_DENIED) {
7421 Uri queryWithUri(context->uri);
7422 resultSet = UserFileClient::Query(queryWithUri, context->predicates, context->fetchColumn, errCode);
7423 }
7424 CHECK_NULLPTR_RET(resultSet);
7425 auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
7426 fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7427 fetchResult->SetUserId(context->userId);
7428 CHECK_NULLPTR_RET(fetchResult);
7429
7430 std::vector<std::unique_ptr<FileAsset>> fileAssetArray;
7431 auto file = fetchResult->GetFirstObject();
7432 while (file != nullptr) {
7433 fileAssetArray.push_back(move(file));
7434 file = fetchResult->GetNextObject();
7435 }
7436 size_t len = fileAssetArray.size();
7437 napi_value jsFileArray = nullptr;
7438 napi_create_array_with_length(env, len, &jsFileArray);
7439 size_t i = 0;
7440 for (i = 0; i < len; i++) {
7441 fileAssetArray[i]->SetUserId(context->userId);
7442 napi_value jsFileAsset = FileAssetNapi::CreateFileAsset(env, fileAssetArray[i]);
7443 if ((jsFileAsset == nullptr) || (napi_set_element(env, jsFileArray, i, jsFileAsset) != napi_ok)) {
7444 NAPI_ERR_LOG("Failed to get file asset napi object");
7445 break;
7446 }
7447 }
7448 return (i == len) ? jsFileArray : nullptr;
7449 }
7450
PhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)7451 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
7452 {
7453 MediaLibraryTracer tracer;
7454 tracer.Start("PhotoAccessGetPhotoAssets");
7455
7456 NAPI_DEBUG_LOG("MediaLibraryNapi::PhotoAccessGetPhotoAssets start");
7457 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7458 asyncContext->assetType = TYPE_PHOTO;
7459 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7460 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GET_ASSETS);
7461
7462 SetUserIdFromObjectInfo(asyncContext);
7463 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
7464 PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7465 }
7466
PhotoAccessGetBurstAssets(napi_env env,napi_callback_info info)7467 napi_value MediaLibraryNapi::PhotoAccessGetBurstAssets(napi_env env, napi_callback_info info)
7468 {
7469 NAPI_INFO_LOG("MediaLibraryNapi::PhotoAccessGetBurstAssets start");
7470 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7471 asyncContext->assetType = TYPE_PHOTO;
7472 CHECK_NULLPTR_RET(ParseArgsGetBurstAssets(env, info, asyncContext));
7473 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::GET_BURST_ASSETS);
7474
7475 SetUserIdFromObjectInfo(asyncContext);
7476 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
7477 PhotoAccessGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7478 }
7479
PhotoAccessGetFileAssetsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)7480 static napi_value PhotoAccessGetFileAssetsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
7481 {
7482 auto context = &asyncContext;
7483 if (context->assetType != TYPE_PHOTO) {
7484 return nullptr;
7485 }
7486 string queryUri = PAH_QUERY_PHOTO;
7487 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
7488
7489 Uri uri(queryUri);
7490 shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
7491 context->predicates, context->fetchColumn);
7492 CHECK_NULLPTR_RET(resultSet);
7493
7494 napi_value jsFileArray = 0;
7495 napi_create_array(env, &jsFileArray);
7496
7497 int count = 0;
7498 while (!resultSet->GoToNextRow()) {
7499 napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet);
7500 napi_set_element(env, jsFileArray, count++, item);
7501 }
7502 return jsFileArray;
7503 }
7504
PhotoAccessGetFileAssetsInfo(napi_env env,napi_callback_info info)7505 napi_value MediaLibraryNapi::PhotoAccessGetFileAssetsInfo(napi_env env, napi_callback_info info)
7506 {
7507 unique_ptr<MediaLibraryAsyncContext> context = make_unique<MediaLibraryAsyncContext>();
7508 context->assetType = TYPE_PHOTO;
7509 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, context));
7510
7511 return PhotoAccessGetFileAssetsExecuteSync(env, *context);
7512 }
7513
PhotoAccessGetPhotoAssetsSync(napi_env env,napi_callback_info info)7514 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAssetsSync(napi_env env, napi_callback_info info)
7515 {
7516 MediaLibraryTracer tracer;
7517 tracer.Start("PhotoAccessGetPhotoAssetsSync");
7518
7519 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7520 asyncContext->assetType = TYPE_PHOTO;
7521 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7522 SetUserIdFromObjectInfo(asyncContext);
7523 return PhotoAccessGetAssetsExecuteSync(env, *asyncContext);
7524 }
7525
JSGetAudioAssets(napi_env env,napi_callback_info info)7526 napi_value MediaLibraryNapi::JSGetAudioAssets(napi_env env, napi_callback_info info)
7527 {
7528 MediaLibraryTracer tracer;
7529 tracer.Start("JSGetAudioAssets");
7530
7531 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7532 asyncContext->assetType = TYPE_AUDIO;
7533 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
7534
7535 SetUserIdFromObjectInfo(asyncContext);
7536 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetAudioAssets",
7537 JSGetAssetsExecute, GetFileAssetsAsyncCallbackComplete);
7538 }
7539
GetPhotoAlbumMap(napi_env env,std::unordered_map<int32_t,unique_ptr<PhotoAlbum>> fileResult)7540 static napi_value GetPhotoAlbumMap(napi_env env, std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> fileResult)
7541 {
7542 napi_status status;
7543 napi_value mapNapiValue {nullptr};
7544 status = napi_create_map(env, &mapNapiValue);
7545 CHECK_COND_RET(status == napi_ok && mapNapiValue != nullptr, nullptr,
7546 "Failed to create map napi value, napi status: %{public}d", static_cast<int>(status));
7547
7548 NAPI_INFO_LOG("PhotoAlbumMap size: %{public}d", static_cast<int32_t>(fileResult.size()));
7549 for (auto &iter : fileResult) {
7550 napi_value albumId {nullptr};
7551 status = napi_create_int32(env, iter.first, &albumId);
7552 CHECK_COND_RET(status == napi_ok && albumId != nullptr, nullptr,
7553 "Failed to create album id, napi status: %{public}d", static_cast<int>(status));
7554 napi_value albumPhoto = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, iter.second);
7555 status = napi_map_set_property(env, mapNapiValue, albumId, albumPhoto);
7556 CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set albumMap, napi status: %{public}d",
7557 static_cast<int>(status));
7558 }
7559 return mapNapiValue;
7560 }
7561
GetPhotoAlbumQueryResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)7562 static void GetPhotoAlbumQueryResult(napi_env env, MediaLibraryAsyncContext *context,
7563 unique_ptr<JSAsyncContextOutput> &jsContext)
7564 {
7565 napi_value fileResult;
7566 if (context->albumIds.empty()) {
7567 fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
7568 } else {
7569 fileResult = GetPhotoAlbumMap(env, move(context->albumMap));
7570 }
7571 if (fileResult == nullptr) {
7572 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7573 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
7574 "Failed to create js object for Fetch Album Result");
7575 return;
7576 }
7577 jsContext->data = fileResult;
7578 jsContext->status = true;
7579 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7580 }
7581
SetPhotoAlbum(PhotoAlbum * photoAlbumData,shared_ptr<DataShareResultSet> & resultSet)7582 static void SetPhotoAlbum(PhotoAlbum* photoAlbumData, shared_ptr<DataShareResultSet> &resultSet)
7583 {
7584 int32_t albumId = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
7585 TYPE_INT32));
7586 photoAlbumData->SetAlbumId(albumId);
7587 photoAlbumData->SetPhotoAlbumType(static_cast<PhotoAlbumType>(
7588 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_TYPE, resultSet, TYPE_INT32))));
7589 photoAlbumData->SetPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(
7590 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet, TYPE_INT32))));
7591 photoAlbumData->SetLPath(get<string>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_LPATH, resultSet,
7592 TYPE_STRING)));
7593 photoAlbumData->SetAlbumName(get<string>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_NAME,
7594 resultSet, TYPE_STRING)));
7595 photoAlbumData->SetDateAdded(get<int64_t>(ResultSetUtils::GetValFromColumn(
7596 PhotoAlbumColumns::ALBUM_DATE_ADDED, resultSet, TYPE_INT64)));
7597 photoAlbumData->SetDateModified(get<int64_t>(ResultSetUtils::GetValFromColumn(
7598 PhotoAlbumColumns::ALBUM_DATE_MODIFIED, resultSet, TYPE_INT64)));
7599 photoAlbumData->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
7600
7601 string countColumn = PhotoAlbumColumns::ALBUM_COUNT;
7602 string coverColumn = PhotoAlbumColumns::ALBUM_COVER_URI;
7603 string albumUriPrefix = PhotoAlbumColumns::ALBUM_URI_PREFIX;
7604 string coverUriSource = PhotoAlbumColumns::COVER_URI_SOURCE;
7605 photoAlbumData->SetAlbumUri(albumUriPrefix + to_string(albumId));
7606 photoAlbumData->SetCount(get<int32_t>(ResultSetUtils::GetValFromColumn(countColumn, resultSet, TYPE_INT32)));
7607 photoAlbumData->SetCoverUri(get<string>(ResultSetUtils::GetValFromColumn(coverColumn, resultSet, TYPE_STRING)));
7608 photoAlbumData->SetCoverUriSource(get<int32_t>(ResultSetUtils::GetValFromColumn(coverUriSource, resultSet, TYPE_INT32)));
7609
7610 // Albums of hidden types (except hidden album itself) don't support image count and video count,
7611 // return -1 instead
7612 int32_t imageCount = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT,
7613 resultSet, TYPE_INT32));
7614 int32_t videoCount = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT,
7615 resultSet, TYPE_INT32));
7616 photoAlbumData->SetImageCount(imageCount);
7617 photoAlbumData->SetVideoCount(videoCount);
7618 }
7619
BuildAlbumMap(std::unordered_map<int32_t,unique_ptr<PhotoAlbum>> & albumMap,shared_ptr<DataShareResultSet> resultSet)7620 static void BuildAlbumMap(std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> &albumMap,
7621 shared_ptr<DataShareResultSet> resultSet)
7622 {
7623 int32_t count = 0;
7624 auto ret = resultSet->GetRowCount(count);
7625 if (ret != NativeRdb::E_OK) {
7626 NAPI_ERR_LOG("get rdbstore failed");
7627 return;
7628 }
7629 if (count == 0) {
7630 NAPI_ERR_LOG("albumid not find");
7631 return;
7632 }
7633 NAPI_INFO_LOG("build album map size: %{public}d", count);
7634 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
7635 unique_ptr<PhotoAlbum> albumAssetPtr = make_unique<PhotoAlbum>();
7636 SetPhotoAlbum(albumAssetPtr.get(), resultSet);
7637 albumMap[albumAssetPtr->GetAlbumId()] = std::move(albumAssetPtr);
7638 }
7639 }
7640
JSGetPhotoAlbumsExecute(napi_env env,void * data)7641 static void JSGetPhotoAlbumsExecute(napi_env env, void *data)
7642 {
7643 MediaLibraryTracer tracer;
7644 tracer.Start("JSGetPhotoAlbumsExecute");
7645
7646 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7647 string queryUri;
7648 if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
7649 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7650 UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
7651 } else if (context->isAnalysisAlbum) {
7652 queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
7653 PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
7654 } else {
7655 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7656 UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
7657 }
7658 Uri uri(queryUri);
7659 int errCode = 0;
7660 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode,
7661 context->userId);
7662 if (resultSet == nullptr) {
7663 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
7664 if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
7665 context->SaveError(errCode);
7666 } else {
7667 context->SaveError(E_HAS_DB_ERROR);
7668 }
7669 return;
7670 }
7671
7672 if (context->albumIds.empty()) {
7673 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
7674 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
7675 context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
7676 context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
7677 PhotoAlbumSubType::GEOGRAPHY_LOCATION);
7678 context->fetchPhotoAlbumResult->SetUserId(context->userId);
7679 } else {
7680 std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> albumMap;
7681 BuildAlbumMap(context->albumMap, resultSet);
7682 }
7683 }
7684
JSGetPhotoAlbumsByIdsExecute(napi_env env,void * data)7685 static void JSGetPhotoAlbumsByIdsExecute(napi_env env, void *data)
7686 {
7687 MediaLibraryTracer tracer;
7688 tracer.Start("JSGetPhotoAlbumsByIdsExecute");
7689
7690 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7691 GetAlbumsByIdsReqBody reqBody;
7692 GetAlbumsByIdsRespBody respBody;
7693 shared_ptr<DataShareResultSet> resultSet;
7694 reqBody.predicates = context->predicates;
7695 reqBody.columns = context->fetchColumn;
7696 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_QUERY_GET_ALBUMS_BY_IDS);
7697 int errCode = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
7698 resultSet = respBody.resultSet;
7699
7700 if (resultSet == nullptr) {
7701 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
7702 if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
7703 context->SaveError(errCode);
7704 } else {
7705 context->SaveError(E_HAS_DB_ERROR);
7706 }
7707 return;
7708 }
7709
7710 if (context->albumIds.empty()) {
7711 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
7712 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
7713 context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
7714 context->fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum ==
7715 PhotoAlbumSubType::GEOGRAPHY_LOCATION);
7716 context->fetchPhotoAlbumResult->SetUserId(context->userId);
7717 } else {
7718 std::unordered_map<int32_t, unique_ptr<PhotoAlbum>> albumMap;
7719 BuildAlbumMap(context->albumMap, resultSet);
7720 }
7721 }
7722
JSGetPhotoAlbumsExecuteSync(napi_env env,MediaLibraryAsyncContext & asyncContext)7723 static napi_value JSGetPhotoAlbumsExecuteSync(napi_env env, MediaLibraryAsyncContext& asyncContext)
7724 {
7725 auto context = &asyncContext;
7726 string queryUri;
7727 if (context->hiddenOnly || context->hiddenAlbumFetchMode == ASSETS_MODE) {
7728 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7729 UFM_QUERY_HIDDEN_ALBUM : PAH_QUERY_HIDDEN_ALBUM;
7730 } else if (context->isAnalysisAlbum) {
7731 queryUri = context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION ?
7732 PAH_QUERY_GEO_PHOTOS : PAH_QUERY_ANA_PHOTO_ALBUM;
7733 } else {
7734 queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
7735 UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
7736 }
7737 Uri uri(queryUri);
7738 int errCode = 0;
7739 auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode,
7740 context->userId);
7741 CHECK_NULLPTR_RET(resultSet);
7742
7743 auto fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
7744 fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
7745 fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenOnly);
7746 fetchPhotoAlbumResult->SetLocationOnly(context->isLocationAlbum == PhotoAlbumSubType::GEOGRAPHY_LOCATION);
7747 fetchPhotoAlbumResult->SetUserId(context->userId);
7748 context->photoAlbumData->SetUserId(context->userId);
7749 if (fetchPhotoAlbumResult->GetCount() <= 0) {
7750 return nullptr;
7751 }
7752 auto photoAlbum = fetchPhotoAlbumResult->GetFirstObject();
7753 CHECK_NULLPTR_RET(photoAlbum);
7754 return PhotoAlbumNapi::CreatePhotoAlbumNapi(env, photoAlbum);
7755 }
7756
JSGetPhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)7757 static void JSGetPhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
7758 {
7759 MediaLibraryTracer tracer;
7760 tracer.Start("JSGetPhotoAlbumsCompleteCallback");
7761
7762 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
7763 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
7764 jsContext->status = false;
7765 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7766 if (context->error == ERR_DEFAULT && context->albumMap.empty() && context->albumIds.size() > 0) {
7767 napi_status status;
7768 napi_value mapNapiValue {nullptr};
7769 status = napi_create_map(env, &mapNapiValue);
7770 if (status != napi_ok || mapNapiValue == nullptr) {
7771 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7772 context->HandleError(env, jsContext->error);
7773 } else {
7774 jsContext->data = mapNapiValue;
7775 jsContext->status = true;
7776 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
7777 }
7778 } else if (context->error != ERR_DEFAULT ||
7779 (context->fetchPhotoAlbumResult == nullptr && context->albumMap.empty())) {
7780 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
7781 context->HandleError(env, jsContext->error);
7782 } else {
7783 GetPhotoAlbumQueryResult(env, context, jsContext);
7784 }
7785
7786 tracer.Finish();
7787 if (context->work != nullptr) {
7788 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
7789 context->work, *jsContext);
7790 }
7791 delete context;
7792 }
7793
JSGetPhotoAlbums(napi_env env,napi_callback_info info)7794 napi_value MediaLibraryNapi::JSGetPhotoAlbums(napi_env env, napi_callback_info info)
7795 {
7796 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7797 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAlbumFetchOptCallback(env, info, asyncContext),
7798 JS_ERR_PARAMETER_INVALID);
7799 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7800
7801 SetUserIdFromObjectInfo(asyncContext);
7802 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAlbums", JSGetPhotoAlbumsExecute,
7803 JSGetPhotoAlbumsCompleteCallback);
7804 }
7805
UserFileMgrCreatePhotoAsset(napi_env env,napi_callback_info info)7806 napi_value MediaLibraryNapi::UserFileMgrCreatePhotoAsset(napi_env env, napi_callback_info info)
7807 {
7808 MediaLibraryTracer tracer;
7809 tracer.Start("UserFileMgrCreatePhotoAsset");
7810
7811 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7812 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7813 asyncContext->assetType = TYPE_PHOTO;
7814 NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
7815
7816 SetUserIdFromObjectInfo(asyncContext);
7817 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreatePhotoAsset",
7818 JSCreateAssetExecute, JSCreateAssetCompleteCallback);
7819 }
7820
UserFileMgrCreateAudioAsset(napi_env env,napi_callback_info info)7821 napi_value MediaLibraryNapi::UserFileMgrCreateAudioAsset(napi_env env, napi_callback_info info)
7822 {
7823 MediaLibraryTracer tracer;
7824 tracer.Start("UserFileMgrCreateAudioAsset");
7825
7826 napi_value ret = nullptr;
7827 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7828 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
7829 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7830 asyncContext->assetType = TYPE_AUDIO;
7831 NAPI_ASSERT(env, ParseArgsCreateAudioAsset(env, info, asyncContext), "Failed to parse js args");
7832
7833 SetUserIdFromObjectInfo(asyncContext);
7834 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCreateAudioAsset",
7835 JSCreateAssetExecute, JSCreateAssetCompleteCallback);
7836 }
7837
ParseArgsTrashAsset(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)7838 napi_value ParseArgsTrashAsset(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
7839 {
7840 string uri;
7841 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
7842 JS_ERR_PARAMETER_INVALID);
7843 if (uri.empty()) {
7844 NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
7845 return nullptr;
7846 }
7847 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos &&
7848 uri.find(AudioColumn::AUDIO_URI_PREFIX) == string::npos) {
7849 NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo or audio uri");
7850 return nullptr;
7851 }
7852 context->uri = uri;
7853
7854 napi_value result = nullptr;
7855 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
7856 return result;
7857 }
7858
UserFileMgrTrashAsset(napi_env env,napi_callback_info info)7859 napi_value MediaLibraryNapi::UserFileMgrTrashAsset(napi_env env, napi_callback_info info)
7860 {
7861 MediaLibraryTracer tracer;
7862 tracer.Start("UserFileMgrTrashAsset");
7863
7864 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7865 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7866 CHECK_NULLPTR_RET(ParseArgsTrashAsset(env, info, asyncContext));
7867
7868 SetUserIdFromObjectInfo(asyncContext);
7869 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrTrashAsset", JSTrashAssetExecute,
7870 JSTrashAssetCompleteCallback);
7871 }
7872
UserFileMgrGetPrivateAlbum(napi_env env,napi_callback_info info)7873 napi_value MediaLibraryNapi::UserFileMgrGetPrivateAlbum(napi_env env, napi_callback_info info)
7874 {
7875 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
7876 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
7877 CHECK_NULLPTR_RET(ParseArgsGetPrivateAlbum(env, info, asyncContext));
7878
7879 SetUserIdFromObjectInfo(asyncContext);
7880 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetPrivateAlbum",
7881 JSGetPhotoAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
7882 }
7883
CreateMediaTypeEnum(napi_env env)7884 napi_value MediaLibraryNapi::CreateMediaTypeEnum(napi_env env)
7885 {
7886 return CreateNumberEnumProperty(env, mediaTypesEnum, sMediaTypeEnumRef_);
7887 }
7888
CreateKeyFrameThumbnailTypeEnum(napi_env env)7889 napi_value MediaLibraryNapi::CreateKeyFrameThumbnailTypeEnum(napi_env env)
7890 {
7891 const int32_t startIdx = 1;
7892 return CreateNumberEnumProperty(env, keyFrameThumbnailTypeEnum, sKeyFrameThumbnailTypeRef_, startIdx);
7893 }
7894
CreateMediaTypeUserFileEnum(napi_env env)7895 napi_value MediaLibraryNapi::CreateMediaTypeUserFileEnum(napi_env env)
7896 {
7897 const int32_t startIdx = 1;
7898 return CreateNumberEnumProperty(env, mediaTypesUserFileEnum, sMediaTypeEnumRef_, startIdx);
7899 }
7900
CreateDirectoryTypeEnum(napi_env env)7901 napi_value MediaLibraryNapi::CreateDirectoryTypeEnum(napi_env env)
7902 {
7903 return CreateNumberEnumProperty(env, directoryEnum, sDirectoryEnumRef_);
7904 }
7905
CreateVirtualAlbumTypeEnum(napi_env env)7906 napi_value MediaLibraryNapi::CreateVirtualAlbumTypeEnum(napi_env env)
7907 {
7908 return CreateNumberEnumProperty(env, virtualAlbumTypeEnum, sVirtualAlbumTypeEnumRef_);
7909 }
7910
CreatePrivateAlbumTypeEnum(napi_env env)7911 napi_value MediaLibraryNapi::CreatePrivateAlbumTypeEnum(napi_env env)
7912 {
7913 return CreateNumberEnumProperty(env, privateAlbumTypeNameEnum, sPrivateAlbumEnumRef_);
7914 }
7915
CreateHiddenPhotosDisplayModeEnum(napi_env env)7916 napi_value MediaLibraryNapi::CreateHiddenPhotosDisplayModeEnum(napi_env env)
7917 {
7918 return CreateNumberEnumProperty(env, HIDDEN_PHOTOS_DISPLAY_MODE_ENUM, sHiddenPhotosDisplayModeEnumRef_);
7919 }
7920
CreateFileKeyEnum(napi_env env)7921 napi_value MediaLibraryNapi::CreateFileKeyEnum(napi_env env)
7922 {
7923 return CreateStringEnumProperty(env, FILE_KEY_ENUM_PROPERTIES, sFileKeyEnumRef_);
7924 }
7925
UserFileMgrCreateFileKeyEnum(napi_env env)7926 napi_value MediaLibraryNapi::UserFileMgrCreateFileKeyEnum(napi_env env)
7927 {
7928 return CreateStringEnumProperty(env, USERFILEMGR_FILEKEY_ENUM_PROPERTIES, sUserFileMgrFileKeyEnumRef_);
7929 }
7930
CreateAudioKeyEnum(napi_env env)7931 napi_value MediaLibraryNapi::CreateAudioKeyEnum(napi_env env)
7932 {
7933 return CreateStringEnumProperty(env, AUDIOKEY_ENUM_PROPERTIES, sAudioKeyEnumRef_);
7934 }
7935
CreateImageVideoKeyEnum(napi_env env)7936 napi_value MediaLibraryNapi::CreateImageVideoKeyEnum(napi_env env)
7937 {
7938 return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sImageVideoKeyEnumRef_);
7939 }
7940
CreatePhotoKeysEnum(napi_env env)7941 napi_value MediaLibraryNapi::CreatePhotoKeysEnum(napi_env env)
7942 {
7943 return CreateStringEnumProperty(env, IMAGEVIDEOKEY_ENUM_PROPERTIES, sPhotoKeysEnumRef_);
7944 }
7945
CreateAlbumKeyEnum(napi_env env)7946 napi_value MediaLibraryNapi::CreateAlbumKeyEnum(napi_env env)
7947 {
7948 return CreateStringEnumProperty(env, ALBUMKEY_ENUM_PROPERTIES, sAlbumKeyEnumRef_);
7949 }
7950
CreateImageFileTypeEnum(napi_env env)7951 napi_value MediaLibraryNapi::CreateImageFileTypeEnum(napi_env env)
7952 {
7953 const int32_t startIdx = 1;
7954 return CreateNumberEnumProperty(env, imageFileTypeEnum, sImageFileTypeEnumEnumRef_, startIdx);
7955 }
7956
CreateAlbumTypeEnum(napi_env env)7957 napi_value MediaLibraryNapi::CreateAlbumTypeEnum(napi_env env)
7958 {
7959 napi_value result = nullptr;
7960 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
7961
7962 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER", PhotoAlbumType::USER), JS_INNER_FAIL);
7963 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SYSTEM", PhotoAlbumType::SYSTEM), JS_INNER_FAIL);
7964 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SMART", PhotoAlbumType::SMART), JS_INNER_FAIL);
7965 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE", PhotoAlbumType::SOURCE), JS_INNER_FAIL);
7966
7967 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumType_), JS_INNER_FAIL);
7968 return result;
7969 }
7970
CreateAlbumSubTypeEnum(napi_env env)7971 napi_value MediaLibraryNapi::CreateAlbumSubTypeEnum(napi_env env)
7972 {
7973 napi_value result = nullptr;
7974 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
7975
7976 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "USER_GENERIC", PhotoAlbumSubType::USER_GENERIC),
7977 JS_INNER_FAIL);
7978 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "SOURCE_GENERIC", PhotoAlbumSubType::SOURCE_GENERIC),
7979 JS_INNER_FAIL);
7980 for (size_t i = 0; i < systemAlbumSubType.size(); i++) {
7981 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, systemAlbumSubType[i],
7982 PhotoAlbumSubType::SYSTEM_START + i), JS_INNER_FAIL);
7983 }
7984 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "CLASSIFY", PhotoAlbumSubType::CLASSIFY),
7985 JS_INNER_FAIL);
7986 for (size_t i = 0; i < analysisAlbumSubType.size(); i++) {
7987 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, analysisAlbumSubType[i],
7988 PhotoAlbumSubType::GEOGRAPHY_LOCATION + i), JS_INNER_FAIL);
7989 }
7990 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "ANY", PhotoAlbumSubType::ANY), JS_INNER_FAIL);
7991
7992 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAlbumSubType_), JS_INNER_FAIL);
7993 return result;
7994 }
7995
CreateAnalysisTypeEnum(napi_env env)7996 napi_value MediaLibraryNapi::CreateAnalysisTypeEnum(napi_env env)
7997 {
7998 struct AnalysisProperty property[] = {
7999 { "ANALYSIS_AESTHETICS_SCORE", AnalysisType::ANALYSIS_AESTHETICS_SCORE },
8000 { "ANALYSIS_LABEL", AnalysisType::ANALYSIS_LABEL },
8001 { "ANALYSIS_VIDEO_LABEL", AnalysisType::ANALYSIS_VIDEO_LABEL },
8002 { "ANALYSIS_OCR", AnalysisType::ANALYSIS_OCR },
8003 { "ANALYSIS_FACE", AnalysisType::ANALYSIS_FACE },
8004 { "ANALYSIS_OBJECT", AnalysisType::ANALYSIS_OBJECT },
8005 { "ANALYSIS_RECOMMENDATION", AnalysisType::ANALYSIS_RECOMMENDATION },
8006 { "ANALYSIS_SEGMENTATION", AnalysisType::ANALYSIS_SEGMENTATION },
8007 { "ANALYSIS_COMPOSITION", AnalysisType::ANALYSIS_COMPOSITION },
8008 { "ANALYSIS_SALIENCY", AnalysisType::ANALYSIS_SALIENCY },
8009 { "ANALYSIS_DETAIL_ADDRESS", AnalysisType::ANALYSIS_DETAIL_ADDRESS },
8010 { "ANALYSIS_HUMAN_FACE_TAG", AnalysisType::ANALYSIS_HUMAN_FACE_TAG },
8011 { "ANALYSIS_HEAD_POSITION", AnalysisType::ANALYSIS_HEAD_POSITION },
8012 { "ANALYSIS_BONE_POSE", AnalysisType::ANALYSIS_BONE_POSE },
8013 { "ANALYSIS_MULTI_CROP", AnalysisType::ANALYSIS_MULTI_CROP },
8014 { "ANALYSIS_HIGHLIGHT", AnalysisType::ANALYSIS_HIGHLIGHT },
8015 { "ANALYSIS_SEARCH_INDEX", AnalysisType::ANALYSIS_SEARCH_INDEX },
8016 };
8017
8018 napi_value result = nullptr;
8019 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8020
8021 for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
8022 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
8023 JS_INNER_FAIL);
8024 }
8025
8026 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sAnalysisType_), JS_INNER_FAIL);
8027 return result;
8028 }
8029
CreateHighlightAlbumInfoTypeEnum(napi_env env)8030 napi_value MediaLibraryNapi::CreateHighlightAlbumInfoTypeEnum(napi_env env)
8031 {
8032 struct AnalysisProperty property[] = {
8033 { "COVER_INFO", HighlightAlbumInfoType::COVER_INFO },
8034 { "PLAY_INFO", HighlightAlbumInfoType::PLAY_INFO },
8035 };
8036
8037 napi_value result = nullptr;
8038 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8039
8040 for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
8041 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
8042 JS_INNER_FAIL);
8043 }
8044
8045 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sHighlightUserActionType_), JS_INNER_FAIL);
8046 return result;
8047 }
8048
CreateHighlightUserActionTypeEnum(napi_env env)8049 napi_value MediaLibraryNapi::CreateHighlightUserActionTypeEnum(napi_env env)
8050 {
8051 struct AnalysisProperty property[] = {
8052 { "INSERTED_PIC_COUNT", HighlightUserActionType::INSERTED_PIC_COUNT },
8053 { "REMOVED_PIC_COUNT", HighlightUserActionType::REMOVED_PIC_COUNT },
8054 { "SHARED_SCREENSHOT_COUNT", HighlightUserActionType::SHARED_SCREENSHOT_COUNT },
8055 { "SHARED_COVER_COUNT", HighlightUserActionType::SHARED_COVER_COUNT },
8056 { "RENAMED_COUNT", HighlightUserActionType::RENAMED_COUNT },
8057 { "CHANGED_COVER_COUNT", HighlightUserActionType::CHANGED_COVER_COUNT },
8058 { "RENDER_VIEWED_TIMES", HighlightUserActionType::RENDER_VIEWED_TIMES },
8059 { "RENDER_VIEWED_DURATION", HighlightUserActionType::RENDER_VIEWED_DURATION },
8060 { "ART_LAYOUT_VIEWED_TIMES", HighlightUserActionType::ART_LAYOUT_VIEWED_TIMES },
8061 { "ART_LAYOUT_VIEWED_DURATION", HighlightUserActionType::ART_LAYOUT_VIEWED_DURATION },
8062 };
8063
8064 napi_value result = nullptr;
8065 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8066
8067 for (uint32_t i = 0; i < sizeof(property) / sizeof(property[0]); i++) {
8068 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, property[i].enumName, property[i].enumValue),
8069 JS_INNER_FAIL);
8070 }
8071
8072 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sHighlightAlbumInfoType_), JS_INNER_FAIL);
8073 return result;
8074 }
8075
CreateDefaultChangeUriEnum(napi_env env)8076 napi_value MediaLibraryNapi::CreateDefaultChangeUriEnum(napi_env env)
8077 {
8078 return CreateStringEnumProperty(env, DEFAULT_URI_ENUM_PROPERTIES, sDefaultChangeUriRef_);
8079 }
8080
CreateNotifyTypeEnum(napi_env env)8081 napi_value MediaLibraryNapi::CreateNotifyTypeEnum(napi_env env)
8082 {
8083 return CreateNumberEnumProperty(env, notifyTypeEnum, sNotifyType_);
8084 }
8085
CreateRequestPhotoTypeEnum(napi_env env)8086 napi_value MediaLibraryNapi::CreateRequestPhotoTypeEnum(napi_env env)
8087 {
8088 return CreateNumberEnumProperty(env, requestPhotoTypeEnum, sRequestPhotoTypeEnumRef_);
8089 }
8090
CreateDeliveryModeEnum(napi_env env)8091 napi_value MediaLibraryNapi::CreateDeliveryModeEnum(napi_env env)
8092 {
8093 return CreateNumberEnumProperty(env, deliveryModeEnum, sDeliveryModeEnumRef_);
8094 }
8095
CreateSourceModeEnum(napi_env env)8096 napi_value MediaLibraryNapi::CreateSourceModeEnum(napi_env env)
8097 {
8098 return CreateNumberEnumProperty(env, sourceModeEnum, sSourceModeEnumRef_);
8099 }
8100
CreateAuthorizationModeEnum(napi_env env)8101 napi_value MediaLibraryNapi::CreateAuthorizationModeEnum(napi_env env)
8102 {
8103 return CreateNumberEnumProperty(env, AuthorizationModeEnum, sAuthorizationModeEnumRef_);
8104 }
8105
CreateCompatibleModeEnum(napi_env env)8106 napi_value MediaLibraryNapi::CreateCompatibleModeEnum(napi_env env)
8107 {
8108 return CreateNumberEnumProperty(env, compatibleModeEnum, sCompatibleModeEnumRef_);
8109 }
8110
CreateResourceTypeEnum(napi_env env)8111 napi_value MediaLibraryNapi::CreateResourceTypeEnum(napi_env env)
8112 {
8113 const int32_t startIdx = 1;
8114 return CreateNumberEnumProperty(env, resourceTypeEnum, sResourceTypeEnumRef_, startIdx);
8115 }
8116
CreateCloudEnhancementTaskStageEnum(napi_env env)8117 napi_value MediaLibraryNapi::CreateCloudEnhancementTaskStageEnum(napi_env env)
8118 {
8119 return CreateNumberEnumProperty(env, cloudEnhancementTaskStageEnum, sCloudEnhancementTaskStageEnumRef_, -1);
8120 }
8121
CreateCloudEnhancementStateEnum(napi_env env)8122 napi_value MediaLibraryNapi::CreateCloudEnhancementStateEnum(napi_env env)
8123 {
8124 return CreateNumberEnumProperty(env, cloudEnhancementStateEnum, sCloudEnhancementStateEnumRef_);
8125 }
8126
CreateVideoEnhancementTypeEnum(napi_env env)8127 napi_value MediaLibraryNapi::CreateVideoEnhancementTypeEnum(napi_env env)
8128 {
8129 return CreateNumberEnumProperty(env, videoEnhancementTypeEnum, sVideoEnhancementTypeEnumRef_);
8130 }
8131
CreateMovingPhotoEffectModeEnum(napi_env env)8132 napi_value MediaLibraryNapi::CreateMovingPhotoEffectModeEnum(napi_env env)
8133 {
8134 napi_value result = nullptr;
8135 CHECK_ARGS(env, napi_create_object(env, &result), JS_INNER_FAIL);
8136 for (size_t i = 0; i < movingPhotoEffectModeEnum.size(); i++) {
8137 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, movingPhotoEffectModeEnum[i], static_cast<int32_t>(i)),
8138 JS_INNER_FAIL);
8139 }
8140 CHECK_ARGS(env, AddIntegerNamedProperty(env, result, "IMAGE_ONLY",
8141 static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY)), JS_INNER_FAIL);
8142 CHECK_ARGS(env, napi_create_reference(env, result, NAPI_INIT_REF_COUNT, &sMovingPhotoEffectModeEnumRef_),
8143 JS_INNER_FAIL);
8144 return result;
8145 }
8146
CreateSupportedWatermarkTypeEnum(napi_env env)8147 napi_value MediaLibraryNapi::CreateSupportedWatermarkTypeEnum(napi_env env)
8148 {
8149 return CreateNumberEnumProperty(env, watermarkTypeEnum, sSupportedWatermarkTypeEnumRef_);
8150 }
8151
CreateCloudMediaDownloadTypeEnum(napi_env env)8152 napi_value MediaLibraryNapi::CreateCloudMediaDownloadTypeEnum(napi_env env)
8153 {
8154 return CreateNumberEnumProperty(env, cloudMediaDownloadTypeEnum, sCloudMediaDownloadTypeEnumRef_);
8155 }
8156
CreateCloudMediaRetainTypeEnum(napi_env env)8157 napi_value MediaLibraryNapi::CreateCloudMediaRetainTypeEnum(napi_env env)
8158 {
8159 return CreateNumberEnumProperty(env, cloudMediaRetainTypeEnum, sCloudMediaRetainTypeEnumRef_);
8160 }
8161
CreateCloudMediaAssetTaskStatusEnum(napi_env env)8162 napi_value MediaLibraryNapi::CreateCloudMediaAssetTaskStatusEnum(napi_env env)
8163 {
8164 return CreateNumberEnumProperty(env, cloudMediaAssetTaskStatusEnum, sCloudMediaAssetTaskStatusEnumRef_);
8165 }
8166
CreateCloudMediaTaskPauseCauseEnum(napi_env env)8167 napi_value MediaLibraryNapi::CreateCloudMediaTaskPauseCauseEnum(napi_env env)
8168 {
8169 return CreateNumberEnumProperty(env, cloudMediaTaskPauseCauseEnum, sCloudMediaTaskPauseCauseEnumRef_);
8170 }
8171
CreateNotifyChangeTypeEnum(napi_env env)8172 napi_value MediaLibraryNapi::CreateNotifyChangeTypeEnum(napi_env env)
8173 {
8174 return CreateNumberEnumProperty(env, notifyChangeTypeEnum, sNotifyChangeTypeEnumRef_);
8175 }
8176
CreateThumbnailChangeStatusEnum(napi_env env)8177 napi_value MediaLibraryNapi::CreateThumbnailChangeStatusEnum(napi_env env)
8178 {
8179 return CreateNumberEnumProperty(env, thumbnailChangeStatusEnum, sThumbnailChangeStatusEnumRef_);
8180 }
8181
CreateStrongAssociationTypeEnum(napi_env env)8182 napi_value MediaLibraryNapi::CreateStrongAssociationTypeEnum(napi_env env)
8183 {
8184 return CreateNumberEnumProperty(env, strongAssociationTypeEnum, sStrongAssociationTypeEnumRef_);
8185 }
8186
ParseArgsCreatePhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8187 static napi_value ParseArgsCreatePhotoAlbum(napi_env env, napi_callback_info info,
8188 unique_ptr<MediaLibraryAsyncContext> &context)
8189 {
8190 if (!MediaLibraryNapiUtils::IsSystemApp()) {
8191 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
8192 return nullptr;
8193 }
8194
8195 constexpr size_t minArgs = ARGS_ONE;
8196 constexpr size_t maxArgs = ARGS_TWO;
8197 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
8198 JS_ERR_PARAMETER_INVALID);
8199
8200 /* Parse the first argument into albumName */
8201 string albumName;
8202 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO], albumName),
8203 JS_ERR_PARAMETER_INVALID);
8204
8205 if (MediaFileUtils::CheckAlbumName(albumName) < 0) {
8206 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8207 return nullptr;
8208 }
8209 context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, albumName);
8210 context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_IS_LOCAL, 1); // local album is 1.
8211
8212 napi_value result = nullptr;
8213 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8214 return result;
8215 }
8216
GetExistsPhotoAlbum(const string & albumName,MediaLibraryAsyncContext * context)8217 static void GetExistsPhotoAlbum(const string &albumName, MediaLibraryAsyncContext *context)
8218 {
8219 string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
8220 UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
8221 Uri uri(queryUri);
8222 DataSharePredicates predicates;
8223 predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
8224 vector<string> columns;
8225 int errCode = 0;
8226 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
8227 auto fetchResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
8228 fetchResult->SetResultNapiType(context->resultNapiType);
8229 context->photoAlbumData = fetchResult->GetFirstObject();
8230 }
8231
GetPhotoAlbumById(const int32_t id,const string & albumName,MediaLibraryAsyncContext * context)8232 static void GetPhotoAlbumById(const int32_t id, const string &albumName, MediaLibraryAsyncContext *context)
8233 {
8234 auto photoAlbum = make_unique<PhotoAlbum>();
8235 photoAlbum->SetAlbumId(id);
8236 photoAlbum->SetPhotoAlbumType(USER);
8237 photoAlbum->SetPhotoAlbumSubType(USER_GENERIC);
8238 photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(id));
8239 photoAlbum->SetAlbumName(albumName);
8240 photoAlbum->SetResultNapiType(context->resultNapiType);
8241 context->photoAlbumData = move(photoAlbum);
8242 }
8243
CallPhotoAccessCreateAlbum(MediaLibraryAsyncContext * context,const std::string & albumName)8244 int32_t CallPhotoAccessCreateAlbum(MediaLibraryAsyncContext *context, const std::string &albumName)
8245 {
8246 CreateAlbumReqBody reqBody;
8247 reqBody.albumName = albumName;
8248 int32_t errCode = IPC::UserDefineIPCClient().Call(context->businessCode, reqBody);
8249 if (errCode < 0) {
8250 NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
8251 }
8252 return errCode;
8253 }
8254
JSCreatePhotoAlbumExecute(napi_env env,void * data)8255 static void JSCreatePhotoAlbumExecute(napi_env env, void *data)
8256 {
8257 MediaLibraryTracer tracer;
8258 tracer.Start("JSCreatePhotoAlbumExecute");
8259
8260 bool isValid = false;
8261 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8262 string albumName = context->valuesBucket.Get(PhotoAlbumColumns::ALBUM_NAME, isValid);
8263 if (!isValid) {
8264 context->SaveError(-EINVAL);
8265 return;
8266 }
8267
8268 int32_t ret = -EINVAL;
8269 if (context->businessCode != 0) {
8270 ret = CallPhotoAccessCreateAlbum(context, albumName);
8271 } else {
8272 string createAlbumUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
8273 UFM_CREATE_PHOTO_ALBUM : PAH_CREATE_PHOTO_ALBUM;
8274 Uri createPhotoAlbumUri(createAlbumUri);
8275 ret = UserFileClient::Insert(createPhotoAlbumUri, context->valuesBucket);
8276 }
8277
8278 if (ret == -1) {
8279 // The album is already existed
8280 context->SaveError(-EEXIST);
8281 GetExistsPhotoAlbum(albumName, context);
8282 return;
8283 }
8284 if (ret < 0) {
8285 context->SaveError(ret);
8286 return;
8287 }
8288 GetPhotoAlbumById(ret, albumName, context);
8289 }
8290
GetPhotoAlbumCreateResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)8291 static void GetPhotoAlbumCreateResult(napi_env env, MediaLibraryAsyncContext *context,
8292 unique_ptr<JSAsyncContextOutput> &jsContext)
8293 {
8294 if (context->photoAlbumData == nullptr) {
8295 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8296 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
8297 "Obtain photo album asset failed");
8298 return;
8299 }
8300 context->photoAlbumData->SetUserId(context->userId);
8301 napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
8302 if (jsPhotoAlbum == nullptr) {
8303 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8304 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
8305 "Failed to create js object for PhotoAlbum");
8306 return;
8307 }
8308 jsContext->data = jsPhotoAlbum;
8309 jsContext->status = true;
8310 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8311 }
8312
HandleExistsError(napi_env env,MediaLibraryAsyncContext * context,napi_value & error)8313 static void HandleExistsError(napi_env env, MediaLibraryAsyncContext *context, napi_value &error)
8314 {
8315 if (context->photoAlbumData == nullptr) {
8316 MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_INVALID_OUTPUT,
8317 "Obtain photo album asset failed");
8318 return;
8319 }
8320 context->photoAlbumData->SetUserId(context->userId);
8321 napi_value jsPhotoAlbum = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, context->photoAlbumData);
8322 if (jsPhotoAlbum == nullptr) {
8323 MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, ERR_MEM_ALLOCATION,
8324 "Failed to create js object for PhotoAlbum");
8325 return;
8326 }
8327 MediaLibraryNapiUtils::CreateNapiErrorObject(env, error, JS_ERR_FILE_EXIST, "Album has existed");
8328 napi_value propertyName;
8329 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, "data", NAPI_AUTO_LENGTH, &propertyName), JS_INNER_FAIL);
8330 CHECK_ARGS_RET_VOID(env, napi_set_property(env, error, propertyName, jsPhotoAlbum), JS_INNER_FAIL);
8331 }
8332
JSCreatePhotoAlbumCompleteCallback(napi_env env,napi_status status,void * data)8333 static void JSCreatePhotoAlbumCompleteCallback(napi_env env, napi_status status, void *data)
8334 {
8335 MediaLibraryTracer tracer;
8336 tracer.Start("JSCreatePhotoAlbumCompleteCallback");
8337
8338 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8339 auto jsContext = make_unique<JSAsyncContextOutput>();
8340 jsContext->status = false;
8341 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8342 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8343 if (context->error == ERR_DEFAULT) {
8344 GetPhotoAlbumCreateResult(env, context, jsContext);
8345 } else if (context->error == JS_ERR_FILE_EXIST) {
8346 HandleExistsError(env, context, jsContext->error);
8347 } else {
8348 context->HandleError(env, jsContext->error);
8349 }
8350
8351 tracer.Finish();
8352 if (context->work != nullptr) {
8353 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
8354 context->work, *jsContext);
8355 }
8356 delete context;
8357 }
8358
CreatePhotoAlbum(napi_env env,napi_callback_info info)8359 napi_value MediaLibraryNapi::CreatePhotoAlbum(napi_env env, napi_callback_info info)
8360 {
8361 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8362 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
8363 CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
8364
8365 SetUserIdFromObjectInfo(asyncContext);
8366 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
8367 JSCreatePhotoAlbumCompleteCallback);
8368 }
8369
PhotoAccessCreatePhotoAlbum(napi_env env,napi_callback_info info)8370 napi_value MediaLibraryNapi::PhotoAccessCreatePhotoAlbum(napi_env env, napi_callback_info info)
8371 {
8372 MediaLibraryTracer tracer;
8373 tracer.Start("PhotoAccessCreatePhotoAlbum");
8374
8375 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8376 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ALBUM);
8377 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8378 CHECK_NULLPTR_RET(ParseArgsCreatePhotoAlbum(env, info, asyncContext));
8379
8380 SetUserIdFromObjectInfo(asyncContext);
8381 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreatePhotoAlbum", JSCreatePhotoAlbumExecute,
8382 JSCreatePhotoAlbumCompleteCallback);
8383 }
8384
ParseArgsDeletePhotoAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8385 static napi_value ParseArgsDeletePhotoAlbums(napi_env env, napi_callback_info info,
8386 unique_ptr<MediaLibraryAsyncContext> &context)
8387 {
8388 if (!MediaLibraryNapiUtils::IsSystemApp()) {
8389 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
8390 return nullptr;
8391 }
8392
8393 constexpr size_t minArgs = ARGS_ONE;
8394 constexpr size_t maxArgs = ARGS_TWO;
8395 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
8396 JS_ERR_PARAMETER_INVALID);
8397
8398 /* Parse the first argument into delete album id array */
8399 vector<string> deleteIds;
8400 uint32_t len = 0;
8401 CHECK_ARGS(env, napi_get_array_length(env, context->argv[PARAM0], &len), JS_INNER_FAIL);
8402 for (uint32_t i = 0; i < len; i++) {
8403 napi_value album = nullptr;
8404 CHECK_ARGS(env, napi_get_element(env, context->argv[PARAM0], i, &album), JS_INNER_FAIL);
8405 if (album == nullptr) {
8406 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8407 return nullptr;
8408 }
8409 PhotoAlbumNapi *obj = nullptr;
8410 CHECK_ARGS(env, napi_unwrap(env, album, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
8411 if (obj == nullptr) {
8412 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8413 return nullptr;
8414 }
8415 if (!PhotoAlbum::IsUserPhotoAlbum(obj->GetPhotoAlbumType(), obj->GetPhotoAlbumSubType())) {
8416 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8417 return nullptr;
8418 }
8419 deleteIds.push_back(to_string(obj->GetAlbumId()));
8420 }
8421 if (deleteIds.empty()) {
8422 napi_value result = nullptr;
8423 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8424 return result;
8425 }
8426 context->albumIds = deleteIds;
8427
8428 napi_value result = nullptr;
8429 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8430 return result;
8431 }
8432
JSDeletePhotoAlbumsExecute(napi_env env,void * data)8433 static void JSDeletePhotoAlbumsExecute(napi_env env, void *data)
8434 {
8435 MediaLibraryTracer tracer;
8436 tracer.Start("JSDeletePhotoAlbumsExecute");
8437
8438 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
8439
8440 CHECK_NULL_PTR_RETURN_VOID(context, "context is null");
8441 CHECK_IF_EQUAL(!context->albumIds.empty(), "albumIds is empty");
8442
8443 int ret = E_OK;
8444 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
8445 context->predicates.In(PhotoAlbumColumns::ALBUM_ID, context->albumIds);
8446 string deleteAlbumUri = UFM_DELETE_PHOTO_ALBUM;
8447 Uri uri(deleteAlbumUri);
8448 ret = UserFileClient::Delete(uri, context->predicates);
8449 } else {
8450 DeleteAlbumsReqBody reqBody;
8451 reqBody.albumIds = context->albumIds;
8452 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_DELETE_PHOTO_ALBUMS);
8453 ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
8454 }
8455
8456 if (ret < 0) {
8457 context->SaveError(ret);
8458 } else {
8459 context->retVal = ret;
8460 }
8461 }
8462
JSDeletePhotoAlbumsCompleteCallback(napi_env env,napi_status status,void * data)8463 static void JSDeletePhotoAlbumsCompleteCallback(napi_env env, napi_status status, void *data)
8464 {
8465 MediaLibraryTracer tracer;
8466 tracer.Start("JSDeletePhotoAlbumsCompleteCallback");
8467
8468 MediaLibraryAsyncContext *context = static_cast<MediaLibraryAsyncContext*>(data);
8469 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
8470
8471 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
8472 jsContext->status = false;
8473
8474 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8475 if (context->error != ERR_DEFAULT) {
8476 context->HandleError(env, jsContext->error);
8477 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
8478 } else {
8479 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->retVal, &jsContext->data), JS_INNER_FAIL);
8480 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
8481 jsContext->status = true;
8482 }
8483
8484 tracer.Finish();
8485 if (context->work != nullptr) {
8486 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
8487 context->work, *jsContext);
8488 }
8489 delete context;
8490 }
8491
DeletePhotoAlbums(napi_env env,napi_callback_info info)8492 napi_value MediaLibraryNapi::DeletePhotoAlbums(napi_env env, napi_callback_info info)
8493 {
8494 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8495 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
8496 CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
8497
8498 SetUserIdFromObjectInfo(asyncContext);
8499 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
8500 JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
8501 }
8502
PhotoAccessDeletePhotoAlbums(napi_env env,napi_callback_info info)8503 napi_value MediaLibraryNapi::PhotoAccessDeletePhotoAlbums(napi_env env, napi_callback_info info)
8504 {
8505 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8506 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8507 CHECK_NULLPTR_RET(ParseArgsDeletePhotoAlbums(env, info, asyncContext));
8508
8509 SetUserIdFromObjectInfo(asyncContext);
8510 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "DeletePhotoAlbums",
8511 JSDeletePhotoAlbumsExecute, JSDeletePhotoAlbumsCompleteCallback);
8512 }
8513
GetAlbumFetchOption(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)8514 static napi_value GetAlbumFetchOption(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
8515 {
8516 if (context->argc < (ARGS_ONE + hasCallback)) {
8517 NAPI_ERR_LOG("No arguments to parse");
8518 return nullptr;
8519 }
8520
8521 // The index of fetchOption should always be the last arg besides callback
8522 uint32_t argIndex = context->argc - ARGS_ONE - hasCallback;
8523 if (argIndex >= NAPI_ARGC_MAX) {
8524 NAPI_ERR_LOG("argIndex ilegal");
8525 return nullptr;
8526 }
8527 napi_value fetchOption = context->argv[argIndex];
8528 CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, fetchOption, ALBUM_FETCH_OPT, context), JS_INNER_FAIL);
8529 if (!context->uri.empty()) {
8530 if (context->uri.find(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX) != std::string::npos) {
8531 context->isAnalysisAlbum = PARAM1; // 1:is an analysis album
8532 }
8533 }
8534 napi_value result = nullptr;
8535 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8536 return result;
8537 }
8538
GetAlbumIds(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)8539 static napi_value GetAlbumIds(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
8540 {
8541 if (context->argc < (ARGS_ONE + hasCallback)) {
8542 NAPI_ERR_LOG("No arguments to parse");
8543 return nullptr;
8544 }
8545 MediaLibraryNapiUtils::GetStringArrayFromInt32(env, context->argv[PARAM0], context->albumIds);
8546 if (context->albumIds.empty() || context->albumIds.size() > MAX_QUERY_ALBUM_LIMIT) {
8547 NAPI_ERR_LOG("the size of albumid is invalid");
8548 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8549 return nullptr;
8550 }
8551 napi_value result = nullptr;
8552 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8553 NAPI_INFO_LOG("GetAlbumIds: %{public}d", static_cast<int32_t>(context->albumIds.size()));
8554 context->predicates.In(PhotoAlbumColumns::ALBUM_ID, context->albumIds);
8555 return result;
8556 }
8557
HandleOneArgAlbum(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,bool hasCallback)8558 static napi_value HandleOneArgAlbum(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context, bool hasCallback)
8559 {
8560 bool hasFetchOpt = false;
8561 CHECK_ARGS(env, MediaLibraryNapiUtils::hasFetchOpt(env, context->argv[PARAM0], hasFetchOpt), JS_INNER_FAIL);
8562 if (hasFetchOpt) {
8563 return GetAlbumFetchOption(env, context, hasCallback);
8564 } else {
8565 if (!MediaLibraryNapiUtils::IsSystemApp()) {
8566 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
8567 return nullptr;
8568 }
8569 return GetAlbumIds(env, context, hasCallback);
8570 }
8571 }
8572
ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> & context,const int32_t albumSubType)8573 static bool ParseLocationAlbumTypes(unique_ptr<MediaLibraryAsyncContext> &context, const int32_t albumSubType)
8574 {
8575 if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
8576 context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_LOCATION;
8577 context->fetchColumn.insert(context->fetchColumn.end(),
8578 PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.begin(),
8579 PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS.end());
8580 MediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
8581 return false;
8582 } else if (albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8583 context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
8584 context->isLocationAlbum = PhotoAlbumSubType::GEOGRAPHY_CITY;
8585 string onClause = PhotoAlbumColumns::ALBUM_NAME + " = " + CITY_ID;
8586 context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
8587 context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
8588 }
8589 return true;
8590 }
8591
ApplyTablePrefixToAlbumIdPredicates(DataSharePredicates & predicates)8592 static void ApplyTablePrefixToAlbumIdPredicates(DataSharePredicates& predicates)
8593 {
8594 constexpr int32_t fieldIdx = 0;
8595 auto& items = predicates.GetOperationList();
8596 string targetColumn = "AnalysisAlbum.album_id";
8597 std::vector<DataShare::OperationItem> tmpOperations = {};
8598 for (const DataShare::OperationItem& item : items) {
8599 if (item.singleParams.empty()) {
8600 tmpOperations.push_back(item);
8601 continue;
8602 }
8603 if (static_cast<string>(item.GetSingle(fieldIdx)) == PhotoAlbumColumns::ALBUM_ID) {
8604 DataShare::OperationItem tmpItem = item;
8605 tmpItem.singleParams[fieldIdx] = targetColumn;
8606 tmpOperations.push_back(tmpItem);
8607 continue;
8608 }
8609 tmpOperations.push_back(item);
8610 }
8611 predicates = DataSharePredicates(move(tmpOperations));
8612 }
8613
AddHighlightAlbumPredicates(DataSharePredicates & predicates,int32_t albumSubType)8614 static void AddHighlightAlbumPredicates(DataSharePredicates& predicates, int32_t albumSubType)
8615 {
8616 vector<string> onClause = {
8617 ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
8618 HIGHLIGHT_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID,
8619 };
8620 if (albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
8621 onClause = {
8622 ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " = " +
8623 HIGHLIGHT_ALBUM_TABLE + "." + AI_ALBUM_ID,
8624 };
8625 }
8626 predicates.InnerJoin(HIGHLIGHT_ALBUM_TABLE)->On(onClause);
8627 predicates.OrderByDesc(MAX_DATE_ADDED + ", " + GENERATE_TIME);
8628 ApplyTablePrefixToAlbumIdPredicates(predicates);
8629 }
8630
ParseAlbumTypes(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context)8631 static napi_value ParseAlbumTypes(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context)
8632 {
8633 if (context->argc < ARGS_TWO) {
8634 NAPI_ERR_LOG("No arguments to parse");
8635 return nullptr;
8636 }
8637
8638 /* Parse the first argument to photo album type */
8639 int32_t albumType;
8640 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumType));
8641 if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(albumType))) {
8642 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8643 return nullptr;
8644 }
8645 context->isAnalysisAlbum = (albumType == PhotoAlbumType::SMART) ? 1 : 0;
8646
8647 /* Parse the second argument to photo album subType */
8648 int32_t albumSubType;
8649 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], albumSubType));
8650 if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(albumSubType))) {
8651 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8652 return nullptr;
8653 }
8654
8655 if (!ParseLocationAlbumTypes(context, albumSubType)) {
8656 napi_value result = nullptr;
8657 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8658 return result;
8659 }
8660
8661 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
8662 if (albumSubType != ANY) {
8663 context->predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
8664 }
8665 if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8666 context->predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
8667 }
8668 if (albumSubType == PhotoAlbumSubType::HIGHLIGHT || albumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
8669 context->isHighlightAlbum = albumSubType;
8670 AddHighlightAlbumPredicates(context->predicates, albumSubType);
8671 }
8672
8673 napi_value result = nullptr;
8674 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8675 return result;
8676 }
8677
RestrictAlbumSubtypeOptions(DataSharePredicates & predicates)8678 static void RestrictAlbumSubtypeOptions(DataSharePredicates &predicates)
8679 {
8680 if (!MediaLibraryNapiUtils::IsSystemApp()) {
8681 predicates.And()->In(PhotoAlbumColumns::ALBUM_SUBTYPE, vector<string>({
8682 to_string(PhotoAlbumSubType::USER_GENERIC),
8683 to_string(PhotoAlbumSubType::FAVORITE),
8684 to_string(PhotoAlbumSubType::VIDEO),
8685 to_string(PhotoAlbumSubType::IMAGE),
8686 }));
8687 } else {
8688 predicates.And()->NotEqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::HIDDEN));
8689 }
8690 }
8691
ParseArgsGetPhotoAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8692 static napi_value ParseArgsGetPhotoAlbum(napi_env env, napi_callback_info info,
8693 unique_ptr<MediaLibraryAsyncContext> &context)
8694 {
8695 constexpr size_t minArgs = ARGS_ZERO;
8696 constexpr size_t maxArgs = ARGS_FOUR;
8697 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
8698 JS_ERR_PARAMETER_INVALID);
8699
8700 bool hasCallback = false;
8701 CHECK_ARGS(env, MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback),
8702 JS_ERR_PARAMETER_INVALID);
8703 if (context->argc == ARGS_THREE) {
8704 napi_valuetype valueType = napi_undefined;
8705 if (napi_typeof(env, context->argv[PARAM2], &valueType) == napi_ok &&
8706 (valueType == napi_undefined || valueType == napi_null)) {
8707 context->argc -= 1;
8708 }
8709 }
8710 switch (context->argc - hasCallback) {
8711 case ARGS_ZERO:
8712 break;
8713 case ARGS_ONE:
8714 CHECK_NULLPTR_RET(HandleOneArgAlbum(env, context, hasCallback));
8715 break;
8716 case ARGS_TWO:
8717 CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
8718 break;
8719 case ARGS_THREE:
8720 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
8721 CHECK_NULLPTR_RET(ParseAlbumTypes(env, context));
8722 break;
8723 default:
8724 return nullptr;
8725 }
8726 RestrictAlbumSubtypeOptions(context->predicates);
8727 if (context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
8728 context->isLocationAlbum != PhotoAlbumSubType::GEOGRAPHY_CITY) {
8729 CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
8730 AddDefaultPhotoAlbumColumns(context->fetchColumn);
8731 AddDefaultColumnsForNonAnalysisAlbums(*context);
8732 if (context->isHighlightAlbum) {
8733 context->fetchColumn.erase(std::remove(context->fetchColumn.begin(), context->fetchColumn.end(),
8734 PhotoAlbumColumns::ALBUM_ID), context->fetchColumn.end());
8735 context->fetchColumn.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID + " AS " +
8736 PhotoAlbumColumns::ALBUM_ID);
8737 }
8738 }
8739 napi_value result = nullptr;
8740 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8741 return result;
8742 }
8743
GetPhotoAlbums(napi_env env,napi_callback_info info)8744 napi_value MediaLibraryNapi::GetPhotoAlbums(napi_env env, napi_callback_info info)
8745 {
8746 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8747 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
8748 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8749
8750 SetUserIdFromObjectInfo(asyncContext);
8751 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
8752 JSGetPhotoAlbumsCompleteCallback);
8753 }
8754
ReplaceFetchColumn(std::vector<std::string> & fetchColumn,const std::string & oldColumn,const std::string & newColumn)8755 static void ReplaceFetchColumn(std::vector<std::string> &fetchColumn,
8756 const std::string &oldColumn, const std::string &newColumn)
8757 {
8758 auto it = std::find(fetchColumn.begin(), fetchColumn.end(), oldColumn);
8759 if (it != fetchColumn.end()) {
8760 it->assign(newColumn);
8761 }
8762 }
8763
AddNoSmartFetchColumns(std::vector<std::string> & fetchColumn)8764 static void AddNoSmartFetchColumns(std::vector<std::string> &fetchColumn)
8765 {
8766 AddDefaultPhotoAlbumColumns(fetchColumn);
8767 fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
8768 fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
8769 fetchColumn.push_back(PhotoAlbumColumns::ALBUM_LPATH);
8770 fetchColumn.push_back(PhotoAlbumColumns::ALBUM_DATE_ADDED);
8771 }
8772
AddPhotoAlbumTypeFilter(DataSharePredicates & predicates,int32_t albumType,int32_t albumSubType)8773 static void AddPhotoAlbumTypeFilter(DataSharePredicates &predicates, int32_t albumType, int32_t albumSubType)
8774 {
8775 if (albumType != PhotoAlbumType::INVALID) {
8776 predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(albumType));
8777 }
8778 if (albumSubType != PhotoAlbumSubType::ANY) {
8779 predicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubType));
8780 if (albumSubType == PhotoAlbumSubType::SHOOTING_MODE || albumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8781 predicates.OrderByDesc(PhotoAlbumColumns::ALBUM_COUNT);
8782 }
8783 }
8784 RestrictAlbumSubtypeOptions(predicates);
8785 }
8786
ParseArgsPahGetAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)8787 static napi_value ParseArgsPahGetAlbums(napi_env env, napi_callback_info info,
8788 unique_ptr<MediaLibraryAsyncContext> &context)
8789 {
8790 napi_value result = nullptr;
8791 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
8792 napi_status status = MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, ARGS_ZERO, ARGS_FOUR);
8793 CHECK_ARGS(env, status, JS_ERR_PARAMETER_INVALID);
8794
8795 bool hasCallback = false;
8796 status = MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback);
8797 CHECK_ARGS(env, status, JS_ERR_PARAMETER_INVALID);
8798
8799 context->photoAlbumType = PhotoAlbumType::INVALID;
8800 context->photoAlbumSubType = PhotoAlbumSubType::ANY;
8801 if (context->argc < ARGS_TWO) {
8802 bool hasFetchOpt = false;
8803 CHECK_ARGS(env, MediaLibraryNapiUtils::hasFetchOpt(env, context->argv[PARAM0], hasFetchOpt), JS_INNER_FAIL);
8804 if (!hasFetchOpt) {
8805 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8806 return nullptr;
8807 }
8808 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
8809 CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
8810 if (context->isAnalysisAlbum) {
8811 context->photoAlbumType = PhotoAlbumType::SMART;
8812 }
8813 return result;
8814 }
8815
8816 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], context->photoAlbumType));
8817 if (!PhotoAlbum::CheckPhotoAlbumType(static_cast<PhotoAlbumType>(context->photoAlbumType))) {
8818 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8819 return nullptr;
8820 }
8821
8822 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM1], context->photoAlbumSubType));
8823 if (!PhotoAlbum::CheckPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(context->photoAlbumSubType))) {
8824 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
8825 return nullptr;
8826 }
8827
8828 if ((context->argc - hasCallback) == ARGS_THREE) {
8829 CHECK_NULLPTR_RET(GetAlbumFetchOption(env, context, hasCallback));
8830 if (context->photoAlbumSubType != PhotoAlbumSubType::GEOGRAPHY_LOCATION &&
8831 context->photoAlbumSubType != PhotoAlbumSubType::GEOGRAPHY_CITY) {
8832 CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
8833 }
8834 }
8835
8836 return result;
8837 }
8838
CallPahGetAlbums(MediaLibraryAsyncContext * context,int32_t & errCode)8839 static std::shared_ptr<DataShareResultSet> CallPahGetAlbums(MediaLibraryAsyncContext *context, int32_t &errCode)
8840 {
8841 if (context->businessCode != 0) {
8842 QueryAlbumsReqBody reqBody;
8843 QueryAlbumsRespBody respBody;
8844 reqBody.albumType = context->photoAlbumType;
8845 reqBody.albumSubType = context->photoAlbumSubType;
8846 reqBody.columns = context->fetchColumn;
8847 reqBody.predicates = context->predicates;
8848 errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
8849 if (errCode != 0) {
8850 NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
8851 return nullptr;
8852 }
8853 return respBody.resultSet;
8854 }
8855
8856 if (context->photoAlbumType != PhotoAlbumType::SMART) {
8857 Uri uri(PAH_QUERY_PHOTO_ALBUM);
8858 AddNoSmartFetchColumns(context->fetchColumn);
8859 AddPhotoAlbumTypeFilter(context->predicates, context->photoAlbumType, context->photoAlbumSubType);
8860 return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
8861 }
8862
8863 if (context->photoAlbumSubType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
8864 Uri uri(PAH_QUERY_GEO_PHOTOS);
8865 MediaLibraryNapiUtils::GetAllLocationPredicates(context->predicates);
8866 const auto &locations = PhotoAlbumColumns::LOCATION_DEFAULT_FETCH_COLUMNS;
8867 context->fetchColumn.insert(context->fetchColumn.end(), locations.begin(), locations.end());
8868 return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
8869 }
8870
8871 if (context->photoAlbumSubType == PhotoAlbumSubType::GEOGRAPHY_CITY) {
8872 context->fetchColumn = PhotoAlbumColumns::CITY_DEFAULT_FETCH_COLUMNS;
8873 std::string onClause = PhotoAlbumColumns::ALBUM_NAME + " = " + CITY_ID;
8874 context->predicates.InnerJoin(GEO_DICTIONARY_TABLE)->On({ onClause });
8875 context->predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_COUNT, to_string(0));
8876 } else {
8877 AddDefaultPhotoAlbumColumns(context->fetchColumn);
8878 if (context->photoAlbumSubType == PhotoAlbumSubType::HIGHLIGHT ||
8879 context->photoAlbumSubType == PhotoAlbumSubType::HIGHLIGHT_SUGGESTIONS) {
8880 AddHighlightAlbumPredicates(context->predicates, context->photoAlbumSubType);
8881 std::string highLightAlbumId = ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_ID +
8882 " AS " + PhotoAlbumColumns::ALBUM_ID;
8883 ReplaceFetchColumn(context->fetchColumn, PhotoAlbumColumns::ALBUM_ID, highLightAlbumId);
8884 }
8885 }
8886
8887 Uri uri(PAH_QUERY_ANA_PHOTO_ALBUM);
8888 AddPhotoAlbumTypeFilter(context->predicates, context->photoAlbumType, context->photoAlbumSubType);
8889 return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
8890 }
8891
JSPahGetAlbumsExecute(napi_env env,void * data)8892 static void JSPahGetAlbumsExecute(napi_env env, void *data)
8893 {
8894 MediaLibraryTracer tracer;
8895 tracer.Start("JSPahGetAlbumsExecute");
8896
8897 int errCode = 0;
8898 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
8899 std::shared_ptr<DataShareResultSet> resultSet = CallPahGetAlbums(context, errCode);
8900 if (resultSet == nullptr) {
8901 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
8902 if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
8903 context->SaveError(errCode);
8904 } else {
8905 context->SaveError(E_HAS_DB_ERROR);
8906 }
8907 return;
8908 }
8909
8910 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
8911 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
8912 context->fetchPhotoAlbumResult->SetHiddenOnly(false);
8913 context->fetchPhotoAlbumResult->SetLocationOnly(false);
8914 context->fetchPhotoAlbumResult->SetUserId(context->userId);
8915 }
8916
PahGetAlbums(napi_env env,napi_callback_info info)8917 napi_value MediaLibraryNapi::PahGetAlbums(napi_env env, napi_callback_info info)
8918 {
8919 MediaLibraryTracer tracer;
8920 tracer.Start("PahGetAlbums");
8921
8922 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8923 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8924 CHECK_NULLPTR_RET(ParseArgsPahGetAlbums(env, info, asyncContext));
8925 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_QUERY_PHOTO_ALBUMS);
8926 SetUserIdFromObjectInfo(asyncContext);
8927 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetAlbums", JSPahGetAlbumsExecute,
8928 JSGetPhotoAlbumsCompleteCallback);
8929 }
8930
PhotoAccessGetPhotoAlbums(napi_env env,napi_callback_info info)8931 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbums(napi_env env, napi_callback_info info)
8932 {
8933 MediaLibraryTracer tracer;
8934 tracer.Start("PhotoAccessGetPhotoAlbums");
8935
8936 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8937 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8938 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8939
8940 SetUserIdFromObjectInfo(asyncContext);
8941 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsExecute,
8942 JSGetPhotoAlbumsCompleteCallback);
8943 }
8944
PhotoAccessGetPhotoAlbumsByIds(napi_env env,napi_callback_info info)8945 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsByIds(napi_env env, napi_callback_info info)
8946 {
8947 MediaLibraryTracer tracer;
8948 tracer.Start("PhotoAccessGetPhotoAlbumsByIds");
8949
8950 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8951 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8952 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8953
8954 SetUserIdFromObjectInfo(asyncContext);
8955 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbums", JSGetPhotoAlbumsByIdsExecute,
8956 JSGetPhotoAlbumsCompleteCallback);
8957 }
8958
PhotoAccessGetPhotoAlbumsSync(napi_env env,napi_callback_info info)8959 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsSync(napi_env env, napi_callback_info info)
8960 {
8961 MediaLibraryTracer tracer;
8962 tracer.Start("PhotoAccessGetPhotoAlbumsSync");
8963
8964 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
8965 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
8966 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbum(env, info, asyncContext));
8967 SetUserIdFromObjectInfo(asyncContext);
8968 return JSGetPhotoAlbumsExecuteSync(env, *asyncContext);
8969 }
8970
CreatePositionTypeEnum(napi_env env)8971 napi_value MediaLibraryNapi::CreatePositionTypeEnum(napi_env env)
8972 {
8973 const int32_t startIdx = 1;
8974 return CreateNumberEnumProperty(env, positionTypeEnum, sPositionTypeEnumRef_, startIdx);
8975 }
8976
CreatePhotoSubTypeEnum(napi_env env)8977 napi_value MediaLibraryNapi::CreatePhotoSubTypeEnum(napi_env env)
8978 {
8979 return CreateNumberEnumProperty(env, photoSubTypeEnum, sPhotoSubType_);
8980 }
8981
CreatePhotoPermissionTypeEnum(napi_env env)8982 napi_value MediaLibraryNapi::CreatePhotoPermissionTypeEnum(napi_env env)
8983 {
8984 return CreateNumberEnumProperty(env, photoPermissionTypeEnum, sPhotoPermissionType_);
8985 }
8986
CreateHideSensitiveTypeEnum(napi_env env)8987 napi_value MediaLibraryNapi::CreateHideSensitiveTypeEnum(napi_env env)
8988 {
8989 return CreateNumberEnumProperty(env, hideSensitiveTypeEnum, sHideSensitiveType_);
8990 }
8991
CreateDynamicRangeTypeEnum(napi_env env)8992 napi_value MediaLibraryNapi::CreateDynamicRangeTypeEnum(napi_env env)
8993 {
8994 return CreateNumberEnumProperty(env, dynamicRangeTypeEnum, sDynamicRangeType_);
8995 }
8996
CheckTitleCompatible(MediaLibraryAsyncContext * context)8997 static bool CheckTitleCompatible(MediaLibraryAsyncContext* context)
8998 {
8999 if (!context->isCreateByComponent) {
9000 return true;
9001 }
9002 bool hasTitleParam = false;
9003 const string title = context->valuesBucket.Get(MediaColumn::MEDIA_TITLE, hasTitleParam);
9004 if (!hasTitleParam) {
9005 return true;
9006 }
9007 return MediaFileUtils::CheckTitleCompatible(title) == E_OK;
9008 }
9009
CallPhotoAccessCreateAsset(MediaLibraryAsyncContext * context,std::string & outUri)9010 static int32_t CallPhotoAccessCreateAsset(MediaLibraryAsyncContext* context, std::string &outUri)
9011 {
9012 bool isValid = false;
9013 CreateAssetReqBody reqBody;
9014 reqBody.mediaType = context->valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
9015 if (context->needSystemApp) {
9016 reqBody.photoSubtype = context->valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
9017 string displayName = context->valuesBucket.Get(MEDIA_DATA_DB_NAME, isValid);
9018 string cameraShotKey = context->valuesBucket.Get(PhotoColumn::CAMERA_SHOT_KEY, isValid);
9019 reqBody.displayName = displayName;
9020 reqBody.cameraShotKey = cameraShotKey;
9021 } else {
9022 string title = context->valuesBucket.Get(MediaColumn::MEDIA_TITLE, isValid);
9023 string extension = context->valuesBucket.Get(ASSET_EXTENTION, isValid);
9024 reqBody.title = title;
9025 reqBody.extension = extension;
9026 }
9027
9028 CreateAssetRespBody respBody;
9029 int32_t errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
9030 if (errCode != 0) {
9031 NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
9032 return errCode;
9033 }
9034 outUri = respBody.outUri;
9035 return respBody.fileId;
9036 }
9037
PhotoAccessCreateAssetExecute(napi_env env,void * data)9038 static void PhotoAccessCreateAssetExecute(napi_env env, void *data)
9039 {
9040 OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
9041 MediaLibraryTracer tracer;
9042 tracer.Start("JSCreateAssetExecute");
9043
9044 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9045 if (!CheckDisplayNameParams(context)) {
9046 context->error = JS_E_DISPLAYNAME;
9047 return;
9048 }
9049 if (!CheckTitleCompatible(context)) {
9050 context->error = JS_E_DISPLAYNAME;
9051 return;
9052 }
9053 if ((context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) && (!CheckRelativePathParams(context))) {
9054 context->error = JS_E_RELATIVEPATH;
9055 return;
9056 }
9057
9058 string outUri;
9059 int index = -EINVAL;
9060 if (context->businessCode != 0) {
9061 index = CallPhotoAccessCreateAsset(context, outUri);
9062 } else {
9063 string uri;
9064 GetCreateUri(context, uri);
9065 Uri createFileUri(uri);
9066 index = UserFileClient::InsertExt(createFileUri, context->valuesBucket, outUri, context->userId);
9067 }
9068 if (index < 0) {
9069 context->SaveError(index);
9070 NAPI_ERR_LOG("InsertExt fail, index: %{public}d.", index);
9071 } else {
9072 if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
9073 if (context->isCreateByComponent) {
9074 context->uri = outUri;
9075 } else {
9076 PhotoAccessSetFileAssetByIdV10(index, "", outUri, context);
9077 }
9078 } else {
9079 #ifdef MEDIALIBRARY_COMPATIBILITY
9080 SetFileAssetByIdV9(index, "", context);
9081 #else
9082 getFileAssetById(index, "", context);
9083 #endif
9084 }
9085 }
9086 OHOS::QOS::ResetThreadQos();
9087 }
9088
PhotoAccessGrantPhotoUriPermissionExecute(napi_env env,void * data)9089 static void PhotoAccessGrantPhotoUriPermissionExecute(napi_env env, void *data)
9090 {
9091 MediaLibraryTracer tracer;
9092 tracer.Start("PhotoAccessGrantPhotoUriPermissionExecute");
9093
9094 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9095 if (context == nullptr) {
9096 NAPI_ERR_LOG("Async context is null");
9097 return;
9098 }
9099 GrantUriPermissionReqBody reqBody;
9100 bool isValid = false;
9101 reqBody.tokenId = context->valuesBucket.Get(AppUriPermissionColumn::TARGET_TOKENID, isValid);
9102 CHECK_IF_EQUAL(isValid, "tokenId is empty");
9103 reqBody.srcTokenId = context->valuesBucket.Get(AppUriPermissionColumn::SOURCE_TOKENID, isValid);
9104 CHECK_IF_EQUAL(isValid, "srcTokenId is empty");
9105 reqBody.fileId = context->valuesBucket.Get(AppUriPermissionColumn::FILE_ID, isValid);
9106 CHECK_IF_EQUAL(isValid, "fileId is empty");
9107 reqBody.permissionType = context->valuesBucket.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
9108 CHECK_IF_EQUAL(isValid, "permissionType is empty");
9109 reqBody.hideSensitiveType = context->valuesBucket.Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
9110 CHECK_IF_EQUAL(isValid, "hideSensitiveType is empty");
9111 reqBody.uriType = context->valuesBucket.Get(AppUriPermissionColumn::URI_TYPE, isValid);
9112 CHECK_IF_EQUAL(isValid, "uriType is empty");
9113
9114 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GRANT_PHOTO_URI_PERMISSION);
9115 NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
9116 int32_t result = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
9117 NAPI_INFO_LOG("GrantPhotoUriPermission ret:%{public}d", result);
9118 if (result < 0) {
9119 context->SaveError(result);
9120 NAPI_ERR_LOG("GrantPhotoUriPermission fail, result: %{public}d.", result);
9121 } else {
9122 context->retVal = result;
9123 }
9124 }
9125
PhotoAccessGrantPhotoUrisPermissionExecuteEx(MediaLibraryAsyncContext * context)9126 static void PhotoAccessGrantPhotoUrisPermissionExecuteEx(MediaLibraryAsyncContext *context)
9127 {
9128 if (context == nullptr) {
9129 NAPI_ERR_LOG("Async context is null");
9130 return;
9131 }
9132 GrantUrisPermissionReqBody reqBody;
9133 bool isValid = false;
9134 std::set<std::string> processedColumn;
9135 for (const auto& valueBucket : context->valuesBucketArray) {
9136 if (processedColumn.find(AppUriPermissionColumn::TARGET_TOKENID) == processedColumn.end()) {
9137 reqBody.tokenId = context->valuesBucket.Get(AppUriPermissionColumn::TARGET_TOKENID, isValid);
9138 CHECK_IF_EQUAL(isValid, "tokenId is empty");
9139 processedColumn.insert(AppUriPermissionColumn::TARGET_TOKENID);
9140 }
9141 if (processedColumn.find(AppUriPermissionColumn::SOURCE_TOKENID) == processedColumn.end()) {
9142 reqBody.srcTokenId = context->valuesBucket.Get(AppUriPermissionColumn::SOURCE_TOKENID, isValid);
9143 CHECK_IF_EQUAL(isValid, "srcTokenId is empty");
9144 processedColumn.insert(AppUriPermissionColumn::SOURCE_TOKENID);
9145 }
9146 if (processedColumn.find(AppUriPermissionColumn::PERMISSION_TYPE) == processedColumn.end()) {
9147 reqBody.permissionType = context->valuesBucket.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
9148 CHECK_IF_EQUAL(isValid, "permissionType is empty");
9149 processedColumn.insert(AppUriPermissionColumn::PERMISSION_TYPE);
9150 }
9151 if (processedColumn.find(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE) == processedColumn.end()) {
9152 reqBody.hideSensitiveType = context->valuesBucket.Get(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE, isValid);
9153 CHECK_IF_EQUAL(isValid, "hideSensitiveType is empty");
9154 processedColumn.insert(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE);
9155 }
9156 if (processedColumn.find(AppUriPermissionColumn::URI_TYPE) == processedColumn.end()) {
9157 reqBody.uriType = context->valuesBucket.Get(AppUriPermissionColumn::URI_TYPE, isValid);
9158 CHECK_IF_EQUAL(isValid, "uriType is empty");
9159 processedColumn.insert(AppUriPermissionColumn::URI_TYPE);
9160 }
9161 reqBody.fileIds.emplace_back(valueBucket.Get(AppUriPermissionColumn::FILE_ID, isValid));
9162 }
9163 NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
9164 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GRANT_PHOTO_URIS_PERMISSION);
9165 int32_t result = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
9166 NAPI_INFO_LOG("GrantPhotoUrisPermission ret:%{public}d", result);
9167 if (result < 0) {
9168 context->SaveError(result);
9169 NAPI_ERR_LOG("GrantPhotoUrisPermission fail, result: %{public}d.", result);
9170 } else {
9171 context->retVal = result;
9172 }
9173 }
9174
PhotoAccessGrantPhotoUrisPermissionExecute(napi_env env,void * data)9175 static void PhotoAccessGrantPhotoUrisPermissionExecute(napi_env env, void *data)
9176 {
9177 MediaLibraryTracer tracer;
9178 tracer.Start("PhotoAccessGrantPhotoUrisPermissionExecute");
9179
9180 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9181 if (context == nullptr) {
9182 NAPI_ERR_LOG("Async context is null");
9183 return;
9184 }
9185 if (context->businessCode != 0) {
9186 return PhotoAccessGrantPhotoUrisPermissionExecuteEx(context);
9187 }
9188
9189 string uri = PAH_CREATE_APP_URI_PERMISSION;
9190 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
9191 Uri createUri(uri);
9192
9193 int result = UserFileClient::BatchInsert(createUri, context->valuesBucketArray);
9194 if (result < 0) {
9195 context->SaveError(result);
9196 NAPI_ERR_LOG("BatchInsert fail, result: %{public}d.", result);
9197 } else {
9198 context->retVal = result;
9199 }
9200 }
9201
PhotoAccessCancelPhotoUriPermissionExecute(napi_env env,void * data)9202 static void PhotoAccessCancelPhotoUriPermissionExecute(napi_env env, void *data)
9203 {
9204 MediaLibraryTracer tracer;
9205 tracer.Start("PhotoAccessCancelPhotoUriPermissionExecute");
9206
9207 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9208 if (context == nullptr) {
9209 NAPI_ERR_LOG("Async context is null");
9210 return;
9211 }
9212
9213 CancelUriPermissionReqBody reqBody;
9214 bool isValid = false;
9215 reqBody.tokenId = context->valuesBucket.Get(AppUriPermissionColumn::TARGET_TOKENID, isValid);
9216 CHECK_IF_EQUAL(isValid, "tokenId is empty");
9217 reqBody.srcTokenId = context->valuesBucket.Get(AppUriPermissionColumn::SOURCE_TOKENID, isValid);
9218 CHECK_IF_EQUAL(isValid, "srcTokenId is empty");
9219 reqBody.fileId = context->valuesBucket.Get(AppUriPermissionColumn::FILE_ID, isValid);
9220 CHECK_IF_EQUAL(isValid, "fileId is empty");
9221 reqBody.permissionType = context->valuesBucket.Get(AppUriPermissionColumn::PERMISSION_TYPE, isValid);
9222 CHECK_IF_EQUAL(isValid, "permissionType is empty");
9223 reqBody.uriType = context->valuesBucket.Get(AppUriPermissionColumn::URI_TYPE, isValid);
9224 CHECK_IF_EQUAL(isValid, "uriType is empty");
9225
9226 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_CANCEL_PHOTO_URI_PERMISSION);
9227 NAPI_INFO_LOG("before IPC::UserDefineIPCClient().Call");
9228 int32_t result = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
9229 NAPI_INFO_LOG("CancelPhotoUriPermission ret:%{public}d", result);
9230 if (result < 0) {
9231 context->SaveError(result);
9232 NAPI_ERR_LOG("CancelPhotoUriPermission fail, result: %{public}d.", result);
9233 } else {
9234 context->retVal = result;
9235 }
9236 }
9237
PhotoAccessHelperCreatePhotoAsset(napi_env env,napi_callback_info info)9238 napi_value MediaLibraryNapi::PhotoAccessHelperCreatePhotoAsset(napi_env env, napi_callback_info info)
9239 {
9240 MediaLibraryTracer tracer;
9241 tracer.Start("PhotoAccessHelperCreatePhotoAsset");
9242
9243 NAPI_INFO_LOG("enter");
9244
9245 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9246 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9247 asyncContext->assetType = TYPE_PHOTO;
9248 NAPI_ASSERT(env, ParseArgsCreatePhotoAsset(env, info, asyncContext), "Failed to parse js args");
9249 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_PUBLIC_CREATE_ASSET);
9250 if (asyncContext->needSystemApp) {
9251 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET);
9252 }
9253
9254 SetUserIdFromObjectInfo(asyncContext);
9255 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCreatePhotoAsset",
9256 PhotoAccessCreateAssetExecute, JSCreateAssetCompleteCallback);
9257 }
9258
PhotoAccessGrantPhotoUriPermission(napi_env env,napi_callback_info info)9259 napi_value MediaLibraryNapi::PhotoAccessGrantPhotoUriPermission(napi_env env, napi_callback_info info)
9260 {
9261 MediaLibraryTracer tracer;
9262 tracer.Start("PhotoAccessGrantPhotoUriPermission");
9263
9264 NAPI_INFO_LOG("enter");
9265
9266 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9267 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9268 asyncContext->assetType = TYPE_PHOTO;
9269 NAPI_ASSERT(env, ParseArgsGrantPhotoUriPermission(env, info, asyncContext), "Failed to parse js args");
9270
9271 SetUserIdFromObjectInfo(asyncContext);
9272 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUriPermission",
9273 PhotoAccessGrantPhotoUriPermissionExecute, JSPhotoUriPermissionCallback);
9274 }
9275
PhotoAccessGrantPhotoUrisPermission(napi_env env,napi_callback_info info)9276 napi_value MediaLibraryNapi::PhotoAccessGrantPhotoUrisPermission(napi_env env, napi_callback_info info)
9277 {
9278 MediaLibraryTracer tracer;
9279 tracer.Start("PhotoAccessGrantPhotoUrisPermission");
9280
9281 NAPI_INFO_LOG("enter");
9282
9283 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9284 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9285 asyncContext->assetType = TYPE_PHOTO;
9286 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GRANT_PHOTO_URIS_PERMISSION);
9287 NAPI_ASSERT(env, ParseArgsGrantPhotoUrisPermission(env, info, asyncContext), "Failed to parse js args");
9288
9289 SetUserIdFromObjectInfo(asyncContext);
9290 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUrisPermission",
9291 PhotoAccessGrantPhotoUrisPermissionExecute, JSPhotoUriPermissionCallback);
9292 }
9293
PhotoAccessCancelPhotoUriPermission(napi_env env,napi_callback_info info)9294 napi_value MediaLibraryNapi::PhotoAccessCancelPhotoUriPermission(napi_env env, napi_callback_info info)
9295 {
9296 MediaLibraryTracer tracer;
9297 tracer.Start("PhotoAccessCancelPhotoUriPermission");
9298
9299 NAPI_INFO_LOG("enter");
9300
9301 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9302 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9303 asyncContext->assetType = TYPE_PHOTO;
9304 NAPI_ASSERT(env, ParseArgsCancelPhotoUriPermission(env, info, asyncContext), "Failed to parse js args");
9305
9306 SetUserIdFromObjectInfo(asyncContext);
9307 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessCancelPhotoUriPermission",
9308 PhotoAccessCancelPhotoUriPermissionExecute, JSPhotoUriPermissionCallback);
9309 }
9310
CheckAlbumUri(napi_env env,OHOS::DataShare::DataShareValuesBucket & valueBucket,MediaLibraryAsyncContext * context)9311 static bool CheckAlbumUri(napi_env env, OHOS::DataShare::DataShareValuesBucket &valueBucket,
9312 MediaLibraryAsyncContext *context)
9313 {
9314 bool isValid = false;
9315 string ownerAlbumId = valueBucket.Get(PhotoColumn::PHOTO_OWNER_ALBUM_ID, isValid);
9316 if (!isValid || ownerAlbumId.empty()) {
9317 return false;
9318 }
9319 string queryUri = PAH_QUERY_PHOTO_ALBUM;
9320 Uri uri(queryUri);
9321 DataSharePredicates predicates;
9322 vector selectionArgs = { to_string(PhotoAlbumSubType::USER_GENERIC), to_string(PhotoAlbumSubType::SOURCE_GENERIC) };
9323 predicates.In(PhotoAlbumColumns::ALBUM_SUBTYPE, selectionArgs);
9324 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, ownerAlbumId);
9325 int errCode = 0;
9326 vector<string> columns;
9327 columns.push_back(MEDIA_COLUMN_COUNT_1);
9328 shared_ptr<DataShareResultSet> resultSet =
9329 UserFileClient::Query(uri, predicates, columns, errCode, context->userId);
9330 if (resultSet == nullptr) {
9331 NAPI_ERR_LOG("resultSet is null, errCode: %{public}d", errCode);
9332 return false;
9333 }
9334 int err = resultSet->GoToFirstRow();
9335 if (err != NativeRdb::E_OK) {
9336 NAPI_ERR_LOG("Invalid albumuri, Failed GoToFirstRow %{public}d", err);
9337 resultSet->Close();
9338 return false;
9339 }
9340 int32_t count = 0;
9341 resultSet->GetInt(0, count);
9342 if (count == 0) {
9343 NAPI_ERR_LOG("Invalid albumuri!");
9344 resultSet->Close();
9345 return false;
9346 }
9347 resultSet->Close();
9348 return true;
9349 }
9350
CallPhotoAccessCreateAssetForApp(MediaLibraryAsyncContext * context,const DataShareValuesBucket & valuesBucket,std::string & outUri)9351 static int32_t CallPhotoAccessCreateAssetForApp(MediaLibraryAsyncContext* context,
9352 const DataShareValuesBucket &valuesBucket, std::string &outUri)
9353 {
9354 bool isValid = false;
9355 CreateAssetForAppReqBody reqBody;
9356 reqBody.tokenId = static_cast<int64_t>(context->tokenId);
9357 reqBody.mediaType = valuesBucket.Get(MEDIA_DATA_DB_MEDIA_TYPE, isValid);
9358 reqBody.photoSubtype = valuesBucket.Get(PhotoColumn::PHOTO_SUBTYPE, isValid);
9359
9360 string extension = valuesBucket.Get(ASSET_EXTENTION, isValid);
9361 string title = valuesBucket.Get(MediaColumn::MEDIA_TITLE, isValid);
9362 string appId = valuesBucket.Get(MEDIA_DATA_DB_OWNER_APPID, isValid);
9363 string bundleName = valuesBucket.Get(MEDIA_DATA_DB_OWNER_PACKAGE, isValid);
9364 string packageName = valuesBucket.Get(MEDIA_DATA_DB_PACKAGE_NAME, isValid);
9365 string ownerAlbumId = valuesBucket.Get(PhotoColumn::PHOTO_OWNER_ALBUM_ID, isValid);
9366 reqBody.title = title;
9367 reqBody.extension = extension;
9368 reqBody.bundleName = bundleName;
9369 reqBody.packageName = packageName;
9370 reqBody.appId = appId;
9371 reqBody.ownerAlbumId = ownerAlbumId;
9372
9373 CreateAssetForAppRespBody respBody;
9374 int32_t errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
9375 if (errCode != 0) {
9376 NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
9377 return errCode;
9378 }
9379 outUri = respBody.outUri;
9380 return respBody.fileId;
9381 }
9382
PhotoAccessAgentCreateAssetsExecute(napi_env env,void * data)9383 static void PhotoAccessAgentCreateAssetsExecute(napi_env env, void *data)
9384 {
9385 MediaLibraryTracer tracer;
9386 tracer.Start("JSCreateAssetExecute");
9387
9388 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9389 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
9390
9391 string uri;
9392 GetCreateUri(context, uri);
9393 if (context->isContainsAlbumUri) {
9394 bool isValid = CheckAlbumUri(env, context->valuesBucketArray[0], context);
9395 if (!isValid) {
9396 context->error = JS_ERR_PARAMETER_INVALID;
9397 return;
9398 }
9399 }
9400 if (context->tokenId != 0) {
9401 NAPI_INFO_LOG("tokenId: %{public}d", context->tokenId);
9402 MediaLibraryNapiUtils::UriAppendKeyValue(uri, TOKEN_ID, to_string(context->tokenId));
9403 }
9404 Uri createFileUri(uri);
9405 for (const auto& valuesBucket : context->valuesBucketArray) {
9406 bool inValid = false;
9407 string title = valuesBucket.Get(MediaColumn::MEDIA_TITLE, inValid);
9408 if (!context->isContainsAlbumUri && !title.empty() && MediaFileUtils::CheckTitleCompatible(title) != E_OK) {
9409 NAPI_ERR_LOG("Title contains invalid characters: %{private}s, skipping", title.c_str());
9410 context->uriArray.push_back(to_string(E_INVALID_DISPLAY_NAME));
9411 continue;
9412 }
9413 string outUri;
9414 int index = -EINVAL;
9415 if (context->businessCode != 0) {
9416 index = CallPhotoAccessCreateAssetForApp(context, valuesBucket, outUri);
9417 } else {
9418 index = UserFileClient::InsertExt(createFileUri, valuesBucket, outUri, context->userId);
9419 }
9420 if (index < 0) {
9421 if (index == E_PERMISSION_DENIED || index == -E_CHECK_SYSTEMAPP_FAIL) {
9422 context->SaveError(index);
9423 NAPI_ERR_LOG("PERMISSION_DENIED, index: %{public}d.", index);
9424 return;
9425 }
9426
9427 if (index == E_HAS_DB_ERROR) {
9428 index = OHOS_INVALID_PARAM_CODE;
9429 }
9430 context->uriArray.push_back(to_string(index));
9431
9432 NAPI_ERR_LOG("InsertExt fail, index: %{public}d title: %{public}s.", index, title.c_str());
9433 } else {
9434 context->uriArray.push_back(move(outUri));
9435 }
9436 }
9437 }
9438
JSStartAssetAnalysisExecute(napi_env env,void * data)9439 static void JSStartAssetAnalysisExecute(napi_env env, void *data)
9440 {
9441 MediaLibraryTracer tracer;
9442 tracer.Start("JSStartAssetAnalysisExecute");
9443
9444 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
9445 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
9446
9447 // 1. Start full analysis if need. 2. If uris are non-empty, start analysis for corresponding uris.
9448 if (!context->isFullAnalysis && context->uris.empty()) {
9449 NAPI_INFO_LOG("asset uris are empty");
9450 return;
9451 }
9452
9453 context->taskId = ForegroundAnalysisMeta::GetIncTaskId();
9454 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::QUERY_START_ASSET_ANALYSIS);
9455 StartAssetAnalysisReqBody reqBody;
9456 StartAssetAnalysisRespBody respBody;
9457 std::vector<std::string> fileIds;
9458 for (const auto &uri : context->uris) {
9459 std::string fileId = MediaLibraryNapiUtils::GetFileIdFromUriString(uri);
9460 if (!fileId.empty()) {
9461 fileIds.push_back(fileId);
9462 }
9463 }
9464 if (!fileIds.empty()) {
9465 reqBody.predicates.In(PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::MEDIA_ID, fileIds);
9466 }
9467 int errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(businessCode, reqBody, respBody);
9468 if (respBody.resultSet != nullptr) {
9469 respBody.resultSet->Close();
9470 }
9471 if (errCode != E_OK) {
9472 context->SaveError(errCode);
9473 NAPI_ERR_LOG("Start assets analysis failed! errCode is = %{public}d", errCode);
9474 }
9475 }
9476
ParseArgsCreateAgentCreateAssetsWithMode(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)9477 static napi_value ParseArgsCreateAgentCreateAssetsWithMode(napi_env env, napi_callback_info info,
9478 unique_ptr<MediaLibraryAsyncContext> &context)
9479 {
9480 /* Parse the arguments */
9481 BundleInfo bundleInfo;
9482 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ZERO],
9483 bundleInfo.bundleName) == napi_ok, "Failed to get bundleName");
9484 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_ONE],
9485 bundleInfo.packageName) == napi_ok, "Failed to get appName");
9486 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[ARGS_TWO],
9487 bundleInfo.appId) == napi_ok, "Failed to get appId");
9488
9489 napi_value result = nullptr;
9490 NAPI_CALL(env, napi_get_boolean(env, true, &result));
9491
9492 vector<napi_value> napiValues;
9493 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[ARGS_FIVE], napiValues));
9494 if (napiValues.empty()) {
9495 return result;
9496 }
9497
9498 for (const auto& napiValue : napiValues) {
9499 CHECK_COND_WITH_MESSAGE(env, ParseCreateConfig(env, napiValue, bundleInfo, *context) == napi_ok,
9500 "Parse asset create config failed");
9501 }
9502
9503 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::GetParamCallback(env, context)
9504 == napi_ok, "Failed to get callback");
9505 return result;
9506 }
9507
ParseArgsAgentCreateAssetsWithMode(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)9508 static napi_value ParseArgsAgentCreateAssetsWithMode(napi_env env, napi_callback_info info,
9509 unique_ptr<MediaLibraryAsyncContext> &context)
9510 {
9511 constexpr size_t minArgs = ARGS_SIX;
9512 constexpr size_t maxArgs = ARGS_SIX;
9513 NAPI_ASSERT(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs) ==
9514 napi_ok, "Failed to get object info");
9515
9516 context->isCreateByComponent = false;
9517 context->isCreateByAgent = true;
9518 context->needSystemApp = true;
9519 if (!MediaLibraryNapiUtils::IsSystemApp()) {
9520 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
9521 return nullptr;
9522 }
9523
9524 return ParseArgsCreateAgentCreateAssetsWithMode(env, info, context);
9525 }
9526
PhotoAccessHelperAgentCreateAssetsWithMode(napi_env env,napi_callback_info info)9527 napi_value MediaLibraryNapi::PhotoAccessHelperAgentCreateAssetsWithMode(napi_env env, napi_callback_info info)
9528 {
9529 MediaLibraryTracer tracer;
9530 tracer.Start("PhotoAccessHelperAgentCreateAssetsWithMode");
9531
9532 NAPI_INFO_LOG("enter");
9533 int32_t authorizationMode = -1;
9534 int32_t tokenId = -1;
9535 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9536 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET_FOR_APP_WITH_MODE);
9537 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9538 asyncContext->assetType = TYPE_PHOTO;
9539 NAPI_ASSERT(env, ParseArgsAgentCreateAssetsWithMode(env, info, asyncContext), "Failed to parse js args");
9540 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[ARGS_THREE], tokenId));
9541 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, asyncContext->argv[ARGS_FOUR], authorizationMode));
9542 CHECK_COND_WITH_MESSAGE(env, authorizationMode == SaveType::SHORT_IMAGE_PERM, "authorizationMode is error");
9543
9544 int ret = Security::AccessToken::AccessTokenKit::GrantPermissionForSpecifiedTime(
9545 tokenId, PERM_SHORT_TERM_WRITE_IMAGEVIDEO, SHORT_TERM_PERMISSION_DURATION_300S);
9546 if (ret != E_SUCCESS) {
9547 NapiError::ThrowError(env, OHOS_PERMISSION_DENIED_CODE, "This app have no short permission");
9548 return nullptr;
9549 }
9550
9551 SetUserIdFromObjectInfo(asyncContext);
9552 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssetsWithMode",
9553 PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9554 }
9555
PhotoAccessStartAssetAnalysis(napi_env env,napi_callback_info info)9556 napi_value MediaLibraryNapi::PhotoAccessStartAssetAnalysis(napi_env env, napi_callback_info info)
9557 {
9558 MediaLibraryTracer tracer;
9559 tracer.Start("PhotoAccessStartAssetAnalysis");
9560
9561 NAPI_INFO_LOG("enter");
9562 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9563 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9564 asyncContext->assetType = TYPE_PHOTO;
9565 CHECK_COND_WITH_MESSAGE(env, ParseArgsStartAssetAnalysis(env, info, asyncContext) != nullptr,
9566 "Failed to parse js args");
9567
9568 SetUserIdFromObjectInfo(asyncContext);
9569 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessStartAssetAnalysis",
9570 JSStartAssetAnalysisExecute, JSStartAssetAnalysisCallback);
9571 }
9572
PhotoAccessQueryExecute(napi_env env,void * data)9573 static void PhotoAccessQueryExecute(napi_env env, void *data)
9574 {
9575 MediaLibraryTracer tracer;
9576 tracer.Start("PhotoAccessQueryExecute");
9577 auto *context = static_cast<ResultSetAsyncContext *>(data);
9578 if (context == nullptr) {
9579 return;
9580 }
9581 context->queryRet = UserFileClient::QueryByStep(context->uri);
9582 if (context->queryRet == nullptr) {
9583 context->error = OHOS_PERMISSION_DENIED_CODE;
9584 context->errorMsg = "Permission denied";
9585 return;
9586 }
9587 int count = -1;
9588 context->queryRet->GetRowCount(count);
9589 if (count == -1) {
9590 context->error = JS_E_PARAM_INVALID;
9591 context->errorMsg = "Invalid sql";
9592 return;
9593 }
9594 return;
9595 }
9596
PhotoAccessQueryCompleteCallback(napi_env env,napi_status status,void * data)9597 static void PhotoAccessQueryCompleteCallback(napi_env env, napi_status status, void *data)
9598 {
9599 MediaLibraryTracer tracer;
9600 tracer.Start("PhotoAccessQueryCompleteCallback");
9601 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
9602 jsContext->status = false;
9603 status = napi_get_undefined(env, &jsContext->data);
9604 if (status != napi_ok) {
9605 NAPI_INFO_LOG("Napi env error");
9606 return;
9607 }
9608 napi_get_undefined(env, &jsContext->error);
9609 napi_value errorObj;
9610 napi_create_object(env, &errorObj);
9611 auto *context = static_cast<ResultSetAsyncContext *>(data);
9612 if (context != nullptr) {
9613 if (context->error == ERR_DEFAULT && context->queryRet != nullptr) {
9614 jsContext->data = ResultSetNapi::CreateResultSetNapi(env, context->queryRet, *jsContext);
9615 if (jsContext->data == nullptr) {
9616 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, UFM_SYSCAP_BASE,
9617 "CreateResultSet failed");
9618 } else {
9619 jsContext->status = true;
9620 context->queryRet = nullptr;
9621 }
9622 } else {
9623 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error, context->errorMsg);
9624 }
9625 } else {
9626 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, UFM_SYSCAP_BASE, "AsyncContext is nullptr");
9627 }
9628 tracer.Finish();
9629 if (context->work != nullptr) {
9630 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work,
9631 *jsContext);
9632 }
9633 delete context;
9634 return;
9635 }
9636
PhotoAccessQuery(napi_env env,napi_callback_info info)9637 napi_value MediaLibraryNapi::PhotoAccessQuery(napi_env env, napi_callback_info info)
9638 {
9639 MediaLibraryTracer tracer;
9640 tracer.Start("PhotoAccessQuery");
9641 unique_ptr<ResultSetAsyncContext> asyncContext = make_unique<ResultSetAsyncContext>();
9642 CHECK_COND_WITH_ERR_MESSAGE(
9643 env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->uri) == napi_ok,
9644 UFM_SYSCAP_BASE, "Failed to get resourceUrl from arguments or wrong param");
9645 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessQuery", PhotoAccessQueryExecute,
9646 PhotoAccessQueryCompleteCallback);
9647 }
9648
PhotoAccessHelperAgentCreateAssets(napi_env env,napi_callback_info info)9649 napi_value MediaLibraryNapi::PhotoAccessHelperAgentCreateAssets(napi_env env, napi_callback_info info)
9650 {
9651 MediaLibraryTracer tracer;
9652 tracer.Start("PhotoAccessHelperAgentCreateAssets");
9653
9654 NAPI_INFO_LOG("enter");
9655 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9656 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET_FOR_APP);
9657 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9658 asyncContext->assetType = TYPE_PHOTO;
9659 asyncContext->needSystemApp = true;
9660 if (!MediaLibraryNapiUtils::IsSystemApp()) {
9661 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
9662 return nullptr;
9663 }
9664 NAPI_ASSERT(env, ParseArgsAgentCreateAssets(env, info, asyncContext), "Failed to parse js args");
9665
9666 SetUserIdFromObjectInfo(asyncContext);
9667 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssets",
9668 PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9669 }
9670
CreateAssetsForAppWithAlbum(napi_env env,napi_callback_info info)9671 napi_value MediaLibraryNapi::CreateAssetsForAppWithAlbum(napi_env env, napi_callback_info info)
9672 {
9673 MediaLibraryTracer tracer;
9674 tracer.Start("CreateAssetsForAppWithAlbum");
9675
9676 NAPI_INFO_LOG("enter");
9677 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9678 asyncContext->businessCode =
9679 static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYSTEM_CREATE_ASSET_FOR_APP_WITH_ALBUM);
9680 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9681 asyncContext->assetType = TYPE_PHOTO;
9682 asyncContext->needSystemApp = true;
9683 if (!MediaLibraryNapiUtils::IsSystemApp()) {
9684 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
9685 return nullptr;
9686 }
9687 NAPI_ASSERT(env, ParseArgsCreatePhotoAssetForAppWithAlbum(env, info, asyncContext), "Failed to parse js args");
9688
9689 SetUserIdFromObjectInfo(asyncContext);
9690 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CreateAssetsForAppWithAlbum",
9691 PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9692 }
9693
CreateAssetsHasPermission(napi_env env,napi_callback_info info)9694 napi_value MediaLibraryNapi::CreateAssetsHasPermission(napi_env env, napi_callback_info info)
9695 {
9696 MediaLibraryTracer tracer;
9697 tracer.Start("PhotoAccessHelperAgentCreateAssets");
9698
9699 NAPI_INFO_LOG("enter");
9700 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
9701 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_PUBLIC_CREATE_ASSET_FOR_APP);
9702 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
9703 asyncContext->assetType = TYPE_PHOTO;
9704 NAPI_ASSERT(env, ParseArgsAgentCreateAssets(env, info, asyncContext), "Failed to parse js args");
9705
9706 SetUserIdFromObjectInfo(asyncContext);
9707 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperAgentCreateAssets",
9708 PhotoAccessAgentCreateAssetsExecute, JSCreateAssetCompleteCallback);
9709 }
9710
PhotoAccessHelperOnCallback(napi_env env,napi_callback_info info)9711 napi_value MediaLibraryNapi::PhotoAccessHelperOnCallback(napi_env env, napi_callback_info info)
9712 {
9713 MediaLibraryTracer tracer;
9714 tracer.Start("PhotoAccessHelperOnCallback");
9715 napi_value undefinedResult = nullptr;
9716 napi_get_undefined(env, &undefinedResult);
9717 size_t argc = ARGS_THREE;
9718 napi_value argv[ARGS_THREE] = {nullptr};
9719 napi_value thisVar = nullptr;
9720 GET_JS_ARGS(env, info, argc, argv, thisVar);
9721 if (argc == ARGS_TWO) {
9722 return JSOnCallback(env, info);
9723 }
9724 NAPI_ASSERT(env, argc == ARGS_THREE, "requires 3 parameters");
9725 MediaLibraryNapi *obj = nullptr;
9726 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
9727 if (status == napi_ok && obj != nullptr) {
9728 napi_valuetype valueType = napi_undefined;
9729 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
9730 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_boolean ||
9731 napi_typeof(env, argv[PARAM2], &valueType) != napi_ok || valueType != napi_function) {
9732 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9733 return undefinedResult;
9734 }
9735 char buffer[ARG_BUF_SIZE];
9736 size_t res = 0;
9737 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
9738 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9739 return undefinedResult;
9740 }
9741 string uri = string(buffer);
9742 bool isDerived = false;
9743 if (napi_get_value_bool(env, argv[PARAM1], &isDerived) != napi_ok) {
9744 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9745 return undefinedResult;
9746 }
9747 const int32_t refCount = 1;
9748 napi_ref cbOnRef = nullptr;
9749 napi_create_reference(env, argv[PARAM2], refCount, &cbOnRef);
9750 tracer.Start("RegisterNotifyChange");
9751 if (CheckRef(env, cbOnRef, *g_listObj, false, uri)) {
9752 obj->RegisterNotifyChange(env, uri, isDerived, cbOnRef, *g_listObj);
9753 } else {
9754 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
9755 napi_delete_reference(env, cbOnRef);
9756 cbOnRef = nullptr;
9757 return undefinedResult;
9758 }
9759 tracer.Finish();
9760 }
9761 return undefinedResult;
9762 }
9763
AddClientObserver(napi_env env,napi_ref ref,std::map<Notification::NotifyUriType,std::vector<std::shared_ptr<ClientObserver>>> & clientObservers,const Notification::NotifyUriType uriType)9764 int32_t MediaLibraryNapi::AddClientObserver(napi_env env, napi_ref ref,
9765 std::map<Notification::NotifyUriType, std::vector<std::shared_ptr<ClientObserver>>> &clientObservers,
9766 const Notification::NotifyUriType uriType)
9767 {
9768 auto iter = clientObservers.find(uriType);
9769 if (iter == clientObservers.end()) {
9770 shared_ptr<ClientObserver> clientObserver = make_shared<ClientObserver>(uriType, ref);
9771 clientObservers[uriType].push_back(clientObserver);
9772 return E_OK;
9773 }
9774 napi_value callback = nullptr;
9775 napi_status status = napi_get_reference_value(env, ref, &callback);
9776 if (status != napi_ok) {
9777 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9778 return OHOS_INVALID_PARAM_CODE;
9779 }
9780
9781 bool hasRegister = false;
9782 auto observers = iter->second;
9783 for (auto &observer : observers) {
9784 napi_value onCallback = nullptr;
9785 status = napi_get_reference_value(env, observer->ref_, &onCallback);
9786 if (status != napi_ok) {
9787 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9788 return OHOS_INVALID_PARAM_CODE;
9789 }
9790 napi_strict_equals(env, callback, onCallback, &hasRegister);
9791 if (hasRegister) {
9792 NAPI_INFO_LOG("clientObserver hasRegister");
9793 return JS_E_PARAM_INVALID;
9794 }
9795 }
9796 if (!hasRegister) {
9797 shared_ptr<ClientObserver> clientObserver = make_shared<ClientObserver>(uriType, ref);
9798 clientObservers[uriType].push_back(clientObserver);
9799 }
9800 return E_OK;
9801 }
9802
RegisterObserverExecute(napi_env env,napi_ref ref,ChangeListenerNapi & listObj,const Notification::NotifyUriType uriType)9803 int32_t MediaLibraryNapi::RegisterObserverExecute(napi_env env, napi_ref ref, ChangeListenerNapi &listObj,
9804 const Notification::NotifyUriType uriType)
9805 {
9806 // 根据uri获取对应的 注册uri
9807 Notification::NotifyUriType registerUriType = Notification::NotifyUriType::INVALID;
9808 std::string registerUri = "";
9809 if (MediaLibraryNotifyUtils::GetNotifyTypeAndUri(uriType, registerUriType, registerUri) != E_OK) {
9810 return JS_E_PARAM_INVALID;
9811 }
9812
9813 for (auto it = listObj.newObservers_.begin(); it != listObj.newObservers_.end(); it++) {
9814 Notification::NotifyUriType observerUri = (*it)->uriType_;
9815 if (observerUri == registerUriType) {
9816 //判断是否已有callback,没有则加入,有则返回false
9817 auto& clientObservers = (*it)->clientObservers_;
9818 return AddClientObserver(env, ref, clientObservers, uriType);
9819 }
9820 }
9821 // list 中没有,新建一个,并且服务端注册
9822 shared_ptr<MediaOnNotifyNewObserver> observer =
9823 make_shared<MediaOnNotifyNewObserver>(registerUriType, registerUri, env);
9824 Uri notifyUri(registerUri);
9825 int32_t ret = UserFileClient::RegisterObserverExtProvider(notifyUri,
9826 static_cast<shared_ptr<DataShare::DataShareObserver>>(observer), false);
9827 if (ret != E_OK) {
9828 NAPI_ERR_LOG("failed to register observer, ret: %{public}d, uri: %{public}s", ret, registerUri.c_str());
9829 return ret;
9830 }
9831
9832 shared_ptr<ClientObserver> clientObserver = make_shared<ClientObserver>(uriType, ref);
9833 observer->clientObservers_[uriType].push_back(clientObserver);
9834 listObj.newObservers_.push_back(observer);
9835 NAPI_INFO_LOG("success to register observer, ret: %{public}d, uri: %{public}s", ret, registerUri.c_str());
9836 return ret;
9837 }
9838
PhotoAccessRegisterCallback(napi_env env,napi_callback_info info)9839 napi_value MediaLibraryNapi::PhotoAccessRegisterCallback(napi_env env, napi_callback_info info)
9840 {
9841 NAPI_INFO_LOG("enter PhotoAccessRegisterCallback");
9842 MediaLibraryTracer tracer;
9843 tracer.Start("PhotoAccessRegisterCallback");
9844 napi_value undefinedResult = nullptr;
9845 napi_get_undefined(env, &undefinedResult);
9846 size_t argc = ARGS_TWO;
9847 napi_value argv[ARGS_TWO] = {nullptr};
9848 napi_value thisVar = nullptr;
9849 GET_JS_ARGS(env, info, argc, argv, thisVar);
9850 if (argc != ARGS_TWO) {
9851 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requires 2 parameters.");
9852 return undefinedResult;
9853 }
9854
9855 napi_valuetype valueType = napi_undefined;
9856 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string ||
9857 napi_typeof(env, argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
9858 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9859 return undefinedResult;
9860 }
9861 char buffer[ARG_BUF_SIZE];
9862 size_t res = 0;
9863 if (napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
9864 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9865 return undefinedResult;
9866 }
9867 string type = string(buffer);
9868 Notification::NotifyUriType uriType = Notification::NotifyUriType::INVALID;
9869 if (MediaLibraryNotifyUtils::GetRegisterNotifyType(type, uriType) != E_OK) {
9870 NapiError::ThrowError(env, JS_E_PARAM_INVALID, "The scenario parameter verification fails.");
9871 return undefinedResult;
9872 }
9873
9874 const int32_t refCount = 1;
9875 napi_ref cbOnRef = nullptr;
9876 napi_create_reference(env, argv[PARAM1], refCount, &cbOnRef);
9877 int32_t ret = RegisterObserverExecute(env, cbOnRef, *g_listObj, uriType);
9878 if (ret == E_OK) {
9879 NAPI_INFO_LOG("PhotoAccessRegisterCallback success");
9880 } else {
9881 NapiError::ThrowError(env, MediaLibraryNotifyUtils::ConvertToJsError(ret));
9882 napi_delete_reference(env, cbOnRef);
9883 return undefinedResult;
9884 }
9885 return undefinedResult;
9886 }
9887
RemoveClientObserver(napi_env env,napi_ref ref,map<Notification::NotifyUriType,vector<shared_ptr<ClientObserver>>> & clientObservers,const Notification::NotifyUriType uriType)9888 int32_t MediaLibraryNapi::RemoveClientObserver(napi_env env, napi_ref ref,
9889 map<Notification::NotifyUriType, vector<shared_ptr<ClientObserver>>> &clientObservers,
9890 const Notification::NotifyUriType uriType)
9891 {
9892 if (clientObservers.find(uriType) == clientObservers.end()) {
9893 NAPI_ERR_LOG("invalid register uriType");
9894 return JS_E_PARAM_INVALID;
9895 }
9896 if (ref == nullptr) {
9897 NAPI_ERR_LOG("remove all client observers of uriType");
9898 clientObservers.erase(uriType);
9899 return E_OK;
9900 }
9901 napi_value offCallback = nullptr;
9902 napi_status status = napi_get_reference_value(env, ref, &offCallback);
9903 if (status != napi_ok) {
9904 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9905 return OHOS_INVALID_PARAM_CODE;
9906 }
9907
9908 bool hasRegister = false;
9909 for (auto iter = clientObservers[uriType].begin(); iter != clientObservers[uriType].end(); iter++) {
9910 napi_value onCallback = nullptr;
9911 status = napi_get_reference_value(env, (*iter)->ref_, &onCallback);
9912 if (status != napi_ok) {
9913 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
9914 return OHOS_INVALID_PARAM_CODE;
9915 }
9916 napi_strict_equals(env, offCallback, onCallback, &hasRegister);
9917 if (!hasRegister) {
9918 continue;
9919 }
9920
9921 clientObservers[uriType].erase(iter);
9922 if (clientObservers[uriType].empty()) {
9923 clientObservers.erase(uriType);
9924 }
9925 return E_OK;
9926 }
9927 NAPI_ERR_LOG("failed to find observer");
9928 return JS_E_PARAM_INVALID;
9929 }
9930
UnregisterObserverExecute(napi_env env,const Notification::NotifyUriType uriType,napi_ref ref,ChangeListenerNapi & listObj)9931 int32_t MediaLibraryNapi::UnregisterObserverExecute(napi_env env,
9932 const Notification::NotifyUriType uriType, napi_ref ref, ChangeListenerNapi &listObj)
9933 {
9934 if (listObj.newObservers_.size() == 0) {
9935 NAPI_ERR_LOG("listObj.newObservers_ size 0");
9936 return JS_E_PARAM_INVALID;
9937 }
9938
9939 // 根据uri获取对应的 注册uri
9940 Notification::NotifyUriType registerUriType = Notification::NotifyUriType::INVALID;
9941 std::string registerUri = "";
9942 if (MediaLibraryNotifyUtils::GetNotifyTypeAndUri(uriType, registerUriType, registerUri) != E_OK) {
9943 return JS_E_PARAM_INVALID;
9944 }
9945
9946 // 如果注册uri对应的newObserver不存在,无需解注册
9947 // 如果注册uri对应的newObserver存在
9948 // 参数:对应的newObserver的clientobserver中是否存在对应callback,存在,删除并且看看是否删除为空的对应的newObserver
9949 int32_t ret = JS_E_PARAM_INVALID;
9950 for (auto it = listObj.newObservers_.begin(); it != listObj.newObservers_.end(); it++) {
9951 Notification::NotifyUriType observerUri = (*it)->uriType_;
9952 if (observerUri != registerUriType) {
9953 continue;
9954 }
9955 auto& clientObservers = (*it)->clientObservers_;
9956
9957 ret = RemoveClientObserver(env, ref, clientObservers, uriType);
9958 if (ret == E_OK && clientObservers.empty()) {
9959 ret = UserFileClient::UnregisterObserverExtProvider(Uri(registerUri),
9960 static_cast<shared_ptr<DataShare::DataShareObserver>>(*it));
9961 if (ret != E_OK) {
9962 NAPI_ERR_LOG("failed to unregister observer, ret: %{public}d, uri: %{public}s",
9963 ret, registerUri.c_str());
9964 return ret;
9965 }
9966 std::vector<shared_ptr<MediaOnNotifyNewObserver>>::iterator tmp = it;
9967 listObj.newObservers_.erase(tmp);
9968 NAPI_INFO_LOG("success to unregister observer, ret: %{public}d, uri: %{public}s", ret, registerUri.c_str());
9969 }
9970 return ret;
9971 }
9972 return ret;
9973 }
9974
CheckUnregisterCallbackArgs(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)9975 static napi_value CheckUnregisterCallbackArgs(napi_env env, napi_callback_info info,
9976 unique_ptr<MediaLibraryAsyncContext> &context)
9977 {
9978 napi_value thisVar = nullptr;
9979 context->argc = ARGS_TWO;
9980 GET_JS_ARGS(env, info, context->argc, context->argv, thisVar);
9981
9982 if (context->argc < ARGS_ONE || context->argc > ARGS_TWO) {
9983 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requires one or two parameters.");
9984 return nullptr;
9985 }
9986
9987 if (thisVar == nullptr || context->argv[PARAM0] == nullptr) {
9988 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9989 return nullptr;
9990 }
9991
9992 napi_valuetype valueType = napi_undefined;
9993 if (napi_typeof(env, context->argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
9994 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
9995 return nullptr;
9996 }
9997
9998 return thisVar;
9999 }
10000
PhotoAccessUnregisterCallback(napi_env env,napi_callback_info info)10001 napi_value MediaLibraryNapi::PhotoAccessUnregisterCallback(napi_env env, napi_callback_info info)
10002 {
10003 NAPI_INFO_LOG("ento PhotoAccessUnregisterCallback");
10004 MediaLibraryTracer tracer;
10005 tracer.Start("PhotoAccessUnregisterCallback");
10006 napi_value undefinedResult = nullptr;
10007 napi_get_undefined(env, &undefinedResult);
10008 if (g_listObj == nullptr) {
10009 return undefinedResult;
10010 }
10011 unique_ptr<MediaLibraryAsyncContext> context = make_unique<MediaLibraryAsyncContext>();
10012 if (CheckUnregisterCallbackArgs(env, info, context) == nullptr) {
10013 return undefinedResult;
10014 }
10015 char buffer[ARG_BUF_SIZE];
10016 size_t res = 0;
10017 if (napi_get_value_string_utf8(env, context->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
10018 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
10019 return undefinedResult;
10020 }
10021 string type = string(buffer);
10022 Notification::NotifyUriType uriType = Notification::NotifyUriType::INVALID;
10023 if (MediaLibraryNotifyUtils::GetRegisterNotifyType(type, uriType) != E_OK) {
10024 NapiError::ThrowError(env, JS_E_PARAM_INVALID);
10025 return undefinedResult;
10026 }
10027 napi_valuetype valueType = napi_undefined;
10028 napi_ref cbOffRef = nullptr;
10029 if (context->argc == ARGS_TWO) {
10030 if (napi_typeof(env, context->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
10031 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE);
10032 return undefinedResult;
10033 }
10034 const int32_t refCount = 1;
10035 napi_create_reference(env, context->argv[PARAM1], refCount, &cbOffRef);
10036 }
10037 int32_t ret = UnregisterObserverExecute(env, uriType, cbOffRef, *g_listObj);
10038 if (ret != E_OK) {
10039 NapiError::ThrowError(env, MediaLibraryNotifyUtils::ConvertToJsError(ret));
10040 }
10041 if (cbOffRef != nullptr) {
10042 napi_delete_reference(env, cbOffRef);
10043 }
10044 return undefinedResult;
10045 }
10046
PhotoAccessHelperOffCallback(napi_env env,napi_callback_info info)10047 napi_value MediaLibraryNapi::PhotoAccessHelperOffCallback(napi_env env, napi_callback_info info)
10048 {
10049 MediaLibraryTracer tracer;
10050 tracer.Start("PhotoAccessHelperOffCallback");
10051 napi_value undefinedResult = nullptr;
10052 napi_get_undefined(env, &undefinedResult);
10053
10054 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
10055 napi_value thisVar = UserFileMgrOffCheckArgs(env, info, asyncContext);
10056 MediaLibraryNapi *obj = nullptr;
10057 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&obj));
10058 if (status != napi_ok || obj == nullptr || g_listObj == nullptr) {
10059 return undefinedResult;
10060 }
10061 size_t res = 0;
10062 char buffer[ARG_BUF_SIZE];
10063 if (napi_get_value_string_utf8(env, asyncContext->argv[PARAM0], buffer, ARG_BUF_SIZE, &res) != napi_ok) {
10064 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10065 return undefinedResult;
10066 }
10067
10068 string uri = string(buffer);
10069 napi_valuetype valueType = napi_undefined;
10070 if (ListenerTypeMaps.find(uri) != ListenerTypeMaps.end()) {
10071 if (asyncContext->argc == ARGS_TWO) {
10072 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
10073 return undefinedResult;
10074 }
10075 const int32_t refCount = 1;
10076 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &g_listObj->cbOffRef_);
10077 }
10078 obj->UnregisterChange(env, uri, *g_listObj);
10079 return undefinedResult;
10080 }
10081 napi_ref cbOffRef = nullptr;
10082 if (asyncContext->argc == ARGS_TWO) {
10083 if (napi_typeof(env, asyncContext->argv[PARAM1], &valueType) != napi_ok || valueType != napi_function) {
10084 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10085 return undefinedResult;
10086 }
10087 const int32_t refCount = 1;
10088 napi_create_reference(env, asyncContext->argv[PARAM1], refCount, &cbOffRef);
10089 }
10090 tracer.Start("UnRegisterNotifyChange");
10091 obj->UnRegisterNotifyChange(env, uri, cbOffRef, *g_listObj);
10092 return undefinedResult;
10093 }
10094
ParseArgsPHAccessHelperTrash(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)10095 napi_value ParseArgsPHAccessHelperTrash(napi_env env, napi_callback_info info,
10096 unique_ptr<MediaLibraryAsyncContext> &context)
10097 {
10098 if (!MediaLibraryNapiUtils::IsSystemApp()) {
10099 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
10100 return nullptr;
10101 }
10102
10103 vector<string> uris;
10104 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringArrayCallback(env, info, context, uris),
10105 JS_ERR_PARAMETER_INVALID);
10106 if (uris.empty()) {
10107 NapiError::ThrowError(env, JS_E_URI, "Failed to check empty uri!");
10108 return nullptr;
10109 }
10110 for (const auto &uri : uris) {
10111 if (uri.find(PhotoColumn::PHOTO_URI_PREFIX) == string::npos) {
10112 NapiError::ThrowError(env, JS_E_URI, "Failed to check uri format, not a photo uri!");
10113 return nullptr;
10114 }
10115 }
10116 context->uris = uris;
10117
10118 napi_value result = nullptr;
10119 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
10120 return result;
10121 }
10122
PhotoAccessHelperTrashExecute(napi_env env,void * data)10123 static void PhotoAccessHelperTrashExecute(napi_env env, void *data)
10124 {
10125 MediaLibraryTracer tracer;
10126 tracer.Start("PhotoAccessHelperTrashExecute");
10127
10128 auto *context = static_cast<MediaLibraryAsyncContext *>(data);
10129 CHECK_NULL_PTR_RETURN_VOID(context, "context is null");
10130 CHECK_IF_EQUAL(!context->uris.empty(), "uris is empty");
10131
10132 TrashPhotosReqBody reqBody;
10133 reqBody.uris = context->uris;
10134 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SYS_TRASH_PHOTOS);
10135 int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
10136 if (changedRows < 0) {
10137 context->SaveError(changedRows);
10138 NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
10139 }
10140 }
10141
PhotoAccessHelperTrashAsset(napi_env env,napi_callback_info info)10142 napi_value MediaLibraryNapi::PhotoAccessHelperTrashAsset(napi_env env, napi_callback_info info)
10143 {
10144 NAPI_INFO_LOG("enter");
10145 napi_value ret = nullptr;
10146 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
10147 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
10148 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
10149 CHECK_NULLPTR_RET(ParseArgsPHAccessHelperTrash(env, info, asyncContext));
10150
10151 SetUserIdFromObjectInfo(asyncContext);
10152 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperTrashAsset",
10153 PhotoAccessHelperTrashExecute, JSTrashAssetCompleteCallback);
10154 }
10155
ParseArgsSetHidden(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)10156 napi_value ParseArgsSetHidden(napi_env env, napi_callback_info info, unique_ptr<MediaLibraryAsyncContext> &context)
10157 {
10158 if (!MediaLibraryNapiUtils::IsSystemApp()) {
10159 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
10160 return nullptr;
10161 }
10162 napi_value result = nullptr;
10163 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
10164
10165 constexpr size_t minArgs = ARGS_ONE;
10166 constexpr size_t maxArgs = ARGS_THREE;
10167 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
10168 JS_ERR_PARAMETER_INVALID);
10169
10170 /* Parse the first argument */
10171 vector<napi_value> napiValues;
10172 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM0], napiValues));
10173 if (napiValues.empty()) {
10174 return result;
10175 }
10176 napi_valuetype valueType = napi_undefined;
10177 vector<string> uris;
10178 CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_ERR_PARAMETER_INVALID);
10179 if (valueType == napi_string) {
10180 // The input should be an array of asset uri.
10181 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetStringArray(env, napiValues, uris));
10182 } else if (valueType == napi_object) {
10183 // The input should be an array of asset object.
10184 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uris));
10185 }
10186 if (uris.empty()) {
10187 return result;
10188 }
10189 bool hiddenState = false;
10190 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamBool(env, context->argv[PARAM1], hiddenState),
10191 JS_ERR_PARAMETER_INVALID);
10192 context->predicates.In(MediaColumn::MEDIA_ID, uris);
10193 context->valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, static_cast<int32_t>(hiddenState));
10194 return result;
10195 }
10196
SetHiddenExecute(napi_env env,void * data)10197 static void SetHiddenExecute(napi_env env, void *data)
10198 {
10199 MediaLibraryTracer tracer;
10200 tracer.Start("SetHiddenExecute");
10201
10202 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10203 string hideUri = PAH_HIDE_PHOTOS;
10204 MediaLibraryNapiUtils::UriAppendKeyValue(hideUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
10205 Uri uri(hideUri);
10206 int32_t changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
10207 if (changedRows < 0) {
10208 context->SaveError(changedRows);
10209 NAPI_ERR_LOG("Media asset delete failed, err: %{public}d", changedRows);
10210 }
10211 }
10212
SetHiddenCompleteCallback(napi_env env,napi_status status,void * data)10213 static void SetHiddenCompleteCallback(napi_env env, napi_status status, void *data)
10214 {
10215 MediaLibraryTracer tracer;
10216 tracer.Start("SetHiddenCompleteCallback");
10217
10218 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10219 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
10220 jsContext->status = false;
10221 if (context->error == ERR_DEFAULT) {
10222 jsContext->status = true;
10223 napi_get_undefined(env, &jsContext->error);
10224 napi_get_undefined(env, &jsContext->data);
10225 } else {
10226 napi_get_undefined(env, &jsContext->data);
10227 context->HandleError(env, jsContext->error);
10228 }
10229 if (context->work != nullptr) {
10230 tracer.Finish();
10231 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
10232 context->work, *jsContext);
10233 }
10234
10235 delete context;
10236 }
10237
SetHidden(napi_env env,napi_callback_info info)10238 napi_value MediaLibraryNapi::SetHidden(napi_env env, napi_callback_info info)
10239 {
10240 auto asyncContext = make_unique<MediaLibraryAsyncContext>();
10241 CHECK_NULLPTR_RET(ParseArgsSetHidden(env, info, asyncContext));
10242
10243 SetUserIdFromObjectInfo(asyncContext);
10244 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "SetHidden",
10245 SetHiddenExecute, SetHiddenCompleteCallback);
10246 }
10247
ParseArgsPahGetHiddenAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)10248 napi_value ParseArgsPahGetHiddenAlbums(napi_env env, napi_callback_info info,
10249 unique_ptr<MediaLibraryAsyncContext> &context)
10250 {
10251 if (!MediaLibraryNapiUtils::IsSystemApp()) {
10252 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
10253 return nullptr;
10254 }
10255 napi_value result = nullptr;
10256 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
10257 napi_status status = MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, ARGS_ONE, ARGS_THREE);
10258 CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10259
10260 int32_t fetchMode = 0;
10261 status = MediaLibraryNapiUtils::GetInt32(env, context->argv[PARAM0], fetchMode);
10262 CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10263 if (fetchMode != HiddenPhotosDisplayMode::ASSETS_MODE && fetchMode != HiddenPhotosDisplayMode::ALBUMS_MODE) {
10264 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid fetch mode: " + to_string(fetchMode));
10265 return nullptr;
10266 }
10267
10268 bool hasCallback = false;
10269 status = MediaLibraryNapiUtils::HasCallback(env, context->argc, context->argv, hasCallback);
10270 CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10271 if ((context->argc - hasCallback) == ARGS_TWO) {
10272 status = MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM1], ALBUM_FETCH_OPT, context);
10273 CHECK_ARGS(env, status, OHOS_INVALID_PARAM_CODE);
10274 }
10275
10276 CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_ERR_PARAMETER_INVALID);
10277 context->hiddenAlbumFetchMode = fetchMode;
10278 return result;
10279 }
10280
CallPahGetHiddenAlbums(MediaLibraryAsyncContext * context,int32_t & errCode)10281 static std::shared_ptr<DataShareResultSet> CallPahGetHiddenAlbums(MediaLibraryAsyncContext *context, int32_t &errCode)
10282 {
10283 if (context->businessCode != 0) {
10284 QueryAlbumsReqBody reqBody;
10285 QueryAlbumsRespBody respBody;
10286 reqBody.columns = context->fetchColumn;
10287 reqBody.predicates = context->predicates;
10288 reqBody.hiddenAlbumFetchMode = context->hiddenAlbumFetchMode;
10289 errCode = IPC::UserDefineIPCClient().SetUserId(context->userId).Call(context->businessCode, reqBody, respBody);
10290 if (errCode != 0) {
10291 NAPI_ERR_LOG("after IPC::UserDefineIPCClient().Call, errCode: %{public}d.", errCode);
10292 return nullptr;
10293 }
10294 return respBody.resultSet;
10295 }
10296
10297 Uri uri(PAH_QUERY_HIDDEN_ALBUM);
10298 AddDefaultPhotoAlbumColumns(context->fetchColumn);
10299 if (context->hiddenAlbumFetchMode == ALBUMS_MODE) {
10300 context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COUNT);
10301 context->fetchColumn.push_back(PhotoAlbumColumns::HIDDEN_COVER);
10302 context->predicates.EqualTo(PhotoAlbumColumns::CONTAINS_HIDDEN, to_string(1));
10303 } else {
10304 context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::HIDDEN);
10305 }
10306 return UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode, context->userId);
10307 }
10308
JSPahGetHiddenAlbumsExecute(napi_env env,void * data)10309 static void JSPahGetHiddenAlbumsExecute(napi_env env, void *data)
10310 {
10311 MediaLibraryTracer tracer;
10312 tracer.Start("JSPahGetHiddenAlbumsExecute");
10313
10314 int32_t errCode = 0;
10315 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10316 std::shared_ptr<DataShareResultSet> resultSet = CallPahGetHiddenAlbums(context, errCode);
10317 if (resultSet == nullptr) {
10318 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
10319 if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
10320 context->SaveError(errCode);
10321 } else {
10322 context->SaveError(E_HAS_DB_ERROR);
10323 }
10324 return;
10325 }
10326 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
10327 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
10328 context->fetchPhotoAlbumResult->SetHiddenOnly(context->hiddenAlbumFetchMode == ALBUMS_MODE);
10329 context->fetchPhotoAlbumResult->SetLocationOnly(false);
10330 context->fetchPhotoAlbumResult->SetUserId(context->userId);
10331 }
10332
PahGetHiddenAlbums(napi_env env,napi_callback_info info)10333 napi_value MediaLibraryNapi::PahGetHiddenAlbums(napi_env env, napi_callback_info info)
10334 {
10335 auto asyncContext = make_unique<MediaLibraryAsyncContext>();
10336 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
10337 CHECK_NULLPTR_RET(ParseArgsPahGetHiddenAlbums(env, info, asyncContext));
10338 asyncContext->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_QUERY_HIDDEN_ALBUMS);
10339
10340 SetUserIdFromObjectInfo(asyncContext);
10341 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PahGetHiddenAlbums",
10342 JSPahGetHiddenAlbumsExecute, JSGetPhotoAlbumsCompleteCallback);
10343 }
10344
JSApplyChanges(napi_env env,napi_callback_info info)10345 napi_value MediaLibraryNapi::JSApplyChanges(napi_env env, napi_callback_info info)
10346 {
10347 size_t argc = ARGS_TWO;
10348 napi_value argv[ARGS_TWO] = { 0 };
10349 napi_value thisVar = nullptr;
10350 napi_valuetype valueType;
10351 MediaLibraryNapi* mediaLibraryNapi;
10352 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
10353 CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&mediaLibraryNapi)), JS_INNER_FAIL);
10354 CHECK_COND_WITH_MESSAGE(env, mediaLibraryNapi != nullptr, "Failed to get object info");
10355
10356 CHECK_COND_WITH_MESSAGE(env, argc >= ARGS_ONE && argc <= ARGS_TWO, "Number of args is invalid");
10357 CHECK_ARGS(env, napi_typeof(env, argv[PARAM0], &valueType), JS_INNER_FAIL);
10358 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
10359
10360 MediaChangeRequestNapi* obj;
10361 CHECK_ARGS(env, napi_unwrap(env, argv[PARAM0], reinterpret_cast<void**>(&obj)), JS_INNER_FAIL);
10362 CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "MediaChangeRequestNapi object is null");
10363 return obj->ApplyChanges(env, info);
10364 }
10365
initRequest(OHOS::AAFwk::Want & request,shared_ptr<DeleteCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10366 static napi_value initRequest(OHOS::AAFwk::Want &request, shared_ptr<DeleteCallback> &callback,
10367 napi_env env, napi_value args[], size_t argsLen)
10368 {
10369 if (argsLen < ARGS_THREE) {
10370 return nullptr;
10371 }
10372 napi_value result = nullptr;
10373 napi_create_object(env, &result);
10374 request.SetElementName(DELETE_UI_PACKAGE_NAME, DELETE_UI_EXT_ABILITY_NAME);
10375 request.SetParam(DELETE_UI_EXTENSION_TYPE, DELETE_UI_REQUEST_TYPE);
10376
10377 size_t nameRes = 0;
10378 char nameBuffer[ARG_BUF_SIZE];
10379 if (napi_get_value_string_utf8(env, args[ARGS_ONE], nameBuffer, ARG_BUF_SIZE, &nameRes) != napi_ok) {
10380 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10381 return nullptr;
10382 }
10383 string appName = string(nameBuffer);
10384 request.SetParam(DELETE_UI_APPNAME, appName);
10385
10386 vector<string> uris;
10387 uint32_t len = 0;
10388 CHECK_ARGS(env, napi_get_array_length(env, args[ARGS_TWO], &len), JS_ERR_PARAMETER_INVALID);
10389 char uriBuffer[ARG_BUF_SIZE];
10390 for (uint32_t i = 0; i < len; i++) {
10391 napi_value uri = nullptr;
10392 CHECK_ARGS(env, napi_get_element(env, args[ARGS_TWO], i, &uri), JS_ERR_PARAMETER_INVALID);
10393 if (uri == nullptr) {
10394 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
10395 return nullptr;
10396 }
10397 size_t uriRes = 0;
10398 CHECK_ARGS(env, napi_get_value_string_utf8(env, uri, uriBuffer, ARG_BUF_SIZE, &uriRes),
10399 JS_ERR_PARAMETER_INVALID);
10400 uris.push_back(string(uriBuffer));
10401 }
10402 request.SetParam(DELETE_UI_URIS, uris);
10403 callback->SetUris(uris);
10404 callback->SetFunc(args[ARGS_THREE]);
10405 return result;
10406 }
10407
CreateDeleteRequest(napi_env env,napi_callback_info info)10408 napi_value MediaLibraryNapi::CreateDeleteRequest(napi_env env, napi_callback_info info)
10409 {
10410 #ifdef HAS_ACE_ENGINE_PART
10411 size_t argc = ARGS_FOUR;
10412 napi_value args[ARGS_FOUR] = {nullptr};
10413 napi_value thisVar = nullptr;
10414 napi_value result = nullptr;
10415 napi_create_object(env, &result);
10416 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
10417 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10418 NAPI_ASSERT(env, context != nullptr, "context == nullptr");
10419
10420 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10421 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10422 NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
10423
10424 auto uiContent = abilityContext->GetUIContent();
10425 NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
10426
10427 auto callback = std::make_shared<DeleteCallback>(env, uiContent);
10428 OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10429 ([callback](auto arg) { callback->OnRelease(arg); }),
10430 ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
10431 ([callback](auto arg) { callback->OnReceive(arg); }),
10432 ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
10433 };
10434 OHOS::Ace::ModalUIExtensionConfig config;
10435 config.isProhibitBack = true;
10436 OHOS::AAFwk::Want request;
10437 napi_value initRequestResult = initRequest(request, callback, env, args, sizeof(args));
10438 NAPI_ASSERT(env, initRequestResult != nullptr, "initRequest fail");
10439
10440 int32_t sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
10441 NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10442
10443 callback->SetSessionId(sessionId);
10444 return result;
10445 #else
10446 NapiError::ThrowError(env, JS_INNER_FAIL, "ace_engine is not support");
10447 return nullptr;
10448 #endif
10449 }
10450
10451 #ifdef HAS_ACE_ENGINE_PART
ParseString(const napi_env & env,const napi_value & value,std::string & result)10452 static bool ParseString(const napi_env &env, const napi_value &value, std::string &result)
10453 {
10454 size_t size = 0;
10455
10456 CHECK_COND_RET(napi_get_value_string_utf8(env, value, nullptr, 0, &size) == napi_ok, false,
10457 "Failed to get string length.");
10458
10459 result.reserve(size + 1);
10460 result.resize(size);
10461
10462 CHECK_COND_RET(napi_get_value_string_utf8(env, value, result.data(), size + 1, &size) == napi_ok, false,
10463 "Failed to get string value.");
10464
10465 return true;
10466 }
10467
ParseAndSetFileUriArray(const napi_env & env,OHOS::AAFwk::Want & want,const napi_value & value)10468 static bool ParseAndSetFileUriArray(const napi_env &env, OHOS::AAFwk::Want &want, const napi_value &value)
10469 {
10470 uint32_t len = 0;
10471 CHECK_COND_RET(napi_get_array_length(env, value, &len) == napi_ok, false, "Failed to get array length.");
10472 if (len > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
10473 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Array size over 100.");
10474 return false;
10475 }
10476
10477 vector<string> srcFileUris;
10478 for (uint32_t i = 0; i < len; ++i) {
10479 napi_value element = nullptr;
10480 CHECK_COND_RET(napi_get_element(env, value, i, &element) == napi_ok, false, "Failed to get array element.");
10481 if (element == nullptr) {
10482 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get array element.");
10483 return false;
10484 }
10485
10486 string srcFileUri;
10487 if (!ParseString(env, element, srcFileUri)) {
10488 return false;
10489 }
10490 NAPI_INFO_LOG("srcFileUri is %{public}s.", srcFileUri.c_str());
10491 AppFileService::ModuleFileUri::FileUri fileUri(srcFileUri);
10492 std::string realUriPath = fileUri.ToString();
10493 NAPI_INFO_LOG("realUriPath is %{public}s.", realUriPath.c_str());
10494
10495 srcFileUris.emplace_back(realUriPath);
10496 }
10497
10498 want.SetParam(CONFIRM_BOX_SRC_FILE_URIS, srcFileUris);
10499
10500 return true;
10501 }
10502
IsNeedParseProperty(const napi_env & env,const napi_value & value,const string & key,napi_value & property,napi_valuetype & needType)10503 static bool IsNeedParseProperty(const napi_env &env, const napi_value &value, const string &key, napi_value &property,
10504 napi_valuetype &needType)
10505 {
10506 bool hasProp = false;
10507 napi_valuetype valueType = napi_undefined;
10508
10509 CHECK_COND_RET(napi_has_named_property(env, value, key.c_str(), &hasProp) == napi_ok, false,
10510 "Failed to check named property.");
10511 if (hasProp) {
10512 CHECK_COND_RET(napi_get_named_property(env, value, key.c_str(), &property) == napi_ok, false,
10513 "Failed to get named property.");
10514 CHECK_COND_RET(napi_typeof(env, property, &valueType) == napi_ok, false, "Failed to get value type.");
10515
10516 return ((valueType != napi_undefined) && (valueType != napi_null) && (valueType == needType));
10517 }
10518
10519 return hasProp;
10520 }
10521
ParseConfigObject(const napi_env & env,const napi_value & value,PhotoCreationConfig & config)10522 static bool ParseConfigObject(const napi_env &env, const napi_value &value, PhotoCreationConfig &config)
10523 {
10524 napi_value property = nullptr;
10525 napi_valuetype type = napi_undefined;
10526
10527 // title: optional
10528 type = napi_string;
10529 if (IsNeedParseProperty(env, value, TITLE, property, type)) {
10530 NAPI_INFO_LOG("With title.");
10531 if (!ParseString(env, property, config.title)) {
10532 return false;
10533 }
10534 }
10535
10536 // fileNameExtension: mandatory
10537 CHECK_COND_RET(IsNeedParseProperty(env, value, EXTENSION, property, type), false, "Lack param fileNameExtension.");
10538 if (!ParseString(env, property, config.fileNameExtension)) {
10539 return false;
10540 }
10541
10542 // photoType: mandatory
10543 type = napi_number;
10544 CHECK_COND_RET(IsNeedParseProperty(env, value, PHOTO_TYPE, property, type), false, "Lack param photoType.");
10545 CHECK_COND_RET(napi_get_value_int32(env, property, &(config.photoType)) == napi_ok, false,
10546 "Failed to get number type.");
10547 CHECK_COND_RET(((config.photoType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) || (
10548 (config.photoType) == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO))), false,
10549 "Param photoType is not valid.");
10550
10551 // subtype: optional
10552 if (IsNeedParseProperty(env, value, PHOTO_SUB_TYPE, property, type)) {
10553 NAPI_INFO_LOG("With subtype.");
10554 CHECK_COND_RET(napi_get_value_int32(env, property, &(config.subtype)) == napi_ok, false,
10555 "Failed to get number type.");
10556 CHECK_COND_RET(((config.subtype == static_cast<int32_t>(PhotoSubType::DEFAULT)) || (
10557 (config.subtype) == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO))), false,
10558 "Param subtype is not valid.");
10559 }
10560
10561 return true;
10562 }
10563
ParseAndSetConfigArray(const napi_env & env,OHOS::AAFwk::Want & want,const napi_value & value)10564 static bool ParseAndSetConfigArray(const napi_env &env, OHOS::AAFwk::Want &want, const napi_value &value)
10565 {
10566 uint32_t len = 0;
10567 CHECK_COND_RET(napi_get_array_length(env, value, &len) == napi_ok, false, "Failed to get array length.");
10568 if (len > CONFIRM_BOX_ARRAY_MAX_LENGTH) {
10569 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Array size over 100.");
10570 return false;
10571 }
10572
10573 vector<string> titleList;
10574 vector<string> extensionList;
10575 vector<int32_t> photoTypeList;
10576 vector<int32_t> photoSubTypeList;
10577
10578 for (uint32_t i = 0; i < len; ++i) {
10579 napi_value element = nullptr;
10580 CHECK_COND_RET(napi_get_element(env, value, i, &element) == napi_ok, false, "Failed to get array element.");
10581 if (element == nullptr) {
10582 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get array element.");
10583 return false;
10584 }
10585
10586 PhotoCreationConfig config;
10587 if (!ParseConfigObject(env, element, config)) {
10588 return false;
10589 }
10590
10591 titleList.emplace_back(config.title);
10592 extensionList.emplace_back(config.fileNameExtension);
10593 photoTypeList.emplace_back(config.photoType);
10594 photoSubTypeList.emplace_back(config.subtype);
10595 }
10596
10597 // separate Array<PhotoCreationConfig> into Array<string> + Array<string> + Array<number> + Array<number>
10598 want.SetParam(CONFIRM_BOX_TITLE_ARRAY, titleList);
10599 want.SetParam(CONFIRM_BOX_EXTENSION_ARRAY, extensionList);
10600 want.SetParam(CONFIRM_BOX_PHOTO_TYPE_ARRAY, photoTypeList);
10601 want.SetParam(CONFIRM_BOX_PHOTO_SUB_TYPE_ARRAY, photoSubTypeList);
10602
10603 return true;
10604 }
10605
InitConfirmRequest(OHOS::AAFwk::Want & want,shared_ptr<ConfirmCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10606 static bool InitConfirmRequest(OHOS::AAFwk::Want &want, shared_ptr<ConfirmCallback> &callback,
10607 napi_env env, napi_value args[], size_t argsLen)
10608 {
10609 if (argsLen < ARGS_SEVEN) {
10610 return false;
10611 }
10612
10613 want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
10614 want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
10615 want.AddFlags(Want::FLAG_AUTH_READ_URI_PERMISSION);
10616
10617 // second param: Array<string>
10618 if (!ParseAndSetFileUriArray(env, want, args[PARAM1])) {
10619 return false;
10620 }
10621
10622 // third param: Array<PhotoCreationConfig>
10623 if (!ParseAndSetConfigArray(env, want, args[PARAM2])) {
10624 return false;
10625 }
10626
10627 // fourth param: string
10628 string bundleName;
10629 if (!ParseString(env, args[PARAM3], bundleName)) {
10630 return false;
10631 }
10632 want.SetParam(CONFIRM_BOX_BUNDLE_NAME, bundleName);
10633
10634 // fifth param: string
10635 string appName;
10636 if (!ParseString(env, args[PARAM4], appName)) {
10637 return false;
10638 }
10639 want.SetParam(CONFIRM_BOX_APP_NAME, appName);
10640
10641 // sixth param: string
10642 string appId;
10643 if (!ParseString(env, args[PARAM5], appId)) {
10644 return false;
10645 }
10646 want.SetParam(CONFIRM_BOX_APP_ID, appId);
10647
10648 // seventh param: function
10649 callback->SetFunc(args[PARAM6]);
10650
10651 return true;
10652 }
10653 #endif
10654
ShowAssetsCreationDialog(napi_env env,napi_callback_info info)10655 napi_value MediaLibraryNapi::ShowAssetsCreationDialog(napi_env env, napi_callback_info info)
10656 {
10657 #ifdef HAS_ACE_ENGINE_PART
10658 size_t argc = ARGS_SEVEN;
10659 napi_value args[ARGS_SEVEN] = {nullptr};
10660 napi_value thisVar = nullptr;
10661 napi_value result = nullptr;
10662 napi_create_object(env, &result);
10663 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), OHOS_INVALID_PARAM_CODE);
10664
10665 // first param: context, check whether context is abilityContext from stage mode
10666 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10667 NAPI_ASSERT(env, context != nullptr, "Context is null.");
10668
10669 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10670 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10671 NAPI_ASSERT(env, abilityContext != nullptr, "AbilityContext is null.");
10672
10673 // get uiContent from abilityContext, this api should be called after loadContent, otherwise uiContent is nullptr
10674 auto uiContent = abilityContext->GetUIContent();
10675 NAPI_ASSERT(env, uiContent != nullptr, "UiContent is null.");
10676
10677 // set want
10678 OHOS::AAFwk::Want want;
10679 auto callback = std::make_shared<ConfirmCallback>(env, uiContent);
10680 NAPI_ASSERT(env, InitConfirmRequest(want, callback, env, args, sizeof(args)), "Parse input fail.");
10681
10682 // regist callback and config
10683 OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10684 [callback](int32_t releaseCode) {
10685 callback->OnRelease(releaseCode);
10686 },
10687 [callback](int32_t resultCode, const AAFwk::Want &result) {
10688 callback->OnResult(resultCode, result);
10689 },
10690 [callback](const AAFwk::WantParams &receive) {
10691 callback->OnReceive(receive);
10692 },
10693 [callback](int32_t code, const std::string &name, const std::string &message) {
10694 callback->OnError(code, name, name);
10695 },
10696 };
10697 OHOS::Ace::ModalUIExtensionConfig config;
10698 config.isProhibitBack = true;
10699
10700 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
10701 NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10702
10703 NAPI_INFO_LOG("SessionId is %{public}d.", sessionId);
10704
10705 callback->SetSessionId(sessionId);
10706 return result;
10707 #else
10708 NapiError::ThrowError(env, JS_INNER_FAIL, "ace_engine is not support");
10709 return nullptr;
10710 #endif
10711 }
10712
CheckShortTermPermission(napi_env env,napi_callback_info info)10713 napi_value MediaLibraryNapi::CheckShortTermPermission(napi_env env, napi_callback_info info)
10714 {
10715 AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
10716 int res = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_SHORT_TERM_WRITE_IMAGEVIDEO);
10717 napi_value result = nullptr;
10718 CHECK_ARGS(env, napi_get_boolean(env, res == PermissionState::PERMISSION_GRANTED, &result), JS_INNER_FAIL);
10719 return result;
10720 }
10721
InitShortTermRequest(OHOS::AAFwk::Want & want,shared_ptr<ShortTermCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10722 static bool InitShortTermRequest(OHOS::AAFwk::Want &want, shared_ptr<ShortTermCallback> &callback,
10723 napi_env env, napi_value args[], size_t argsLen)
10724 {
10725 if (argsLen < ARGS_SIX) {
10726 return false;
10727 }
10728
10729 want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_ABILITY_NAME);
10730 want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
10731
10732 if (args[PARAM1] == nullptr) {
10733 return false;
10734 }
10735
10736 PhotoCreationConfig config;
10737 napi_value element = args[PARAM1];
10738 if (!ParseConfigObject(env, element, config)) {
10739 return false;
10740 }
10741 want.SetParam(SHORT_TERM_TAG, true);
10742 want.SetParam(SHORT_TERM_TITLE, config.title);
10743 want.SetParam(SHORT_TERM_EXTENSION, config.fileNameExtension);
10744 want.SetParam(SHORT_TERM_PHOTO_TYPE, config.photoType);
10745 want.SetParam(SHORT_TERM_PHOTO_SUB_TYPE, config.subtype);
10746
10747 string bundleName;
10748 if (!ParseString(env, args[PARAM2], bundleName)) {
10749 return false;
10750 }
10751 want.SetParam(CONFIRM_BOX_BUNDLE_NAME, bundleName);
10752
10753 string appName;
10754 if (!ParseString(env, args[PARAM3], appName)) {
10755 return false;
10756 }
10757 want.SetParam(CONFIRM_BOX_APP_NAME, appName);
10758
10759 string appId;
10760 if (!ParseString(env, args[PARAM4], appId)) {
10761 return false;
10762 }
10763 want.SetParam(CONFIRM_BOX_APP_ID, appId);
10764
10765 callback->SetFunc(args[PARAM5]);
10766 return true;
10767 }
10768
CreateAssetWithShortTermPermission(napi_env env,napi_callback_info info)10769 napi_value MediaLibraryNapi::CreateAssetWithShortTermPermission(napi_env env, napi_callback_info info)
10770 {
10771 NAPI_INFO_LOG("CreateAssetWithShortTermPermission enter");
10772 size_t argc = ARGS_SIX;
10773 napi_value args[ARGS_SIX] = {nullptr};
10774 napi_value thisVar = nullptr;
10775 napi_value result = nullptr;
10776 napi_create_object(env, &result);
10777 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
10778 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10779 NAPI_ASSERT(env, context != nullptr, "context == nullptr");
10780
10781 shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10782 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10783 NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
10784
10785 auto uiContent = abilityContext->GetUIContent();
10786 NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
10787
10788 OHOS::AAFwk::Want want;
10789 shared_ptr<ShortTermCallback> callback = make_shared<ShortTermCallback>(env, uiContent);
10790 NAPI_ASSERT(env, InitShortTermRequest(want, callback, env, args, sizeof(args)), "parse short term param fail");
10791
10792 OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10793 ([callback](auto arg) { callback->OnRelease(arg); }),
10794 ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
10795 ([callback](auto arg) { callback->OnReceive(arg); }),
10796 ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
10797 };
10798 OHOS::Ace::ModalUIExtensionConfig config;
10799 config.isProhibitBack = true;
10800 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
10801 NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10802 callback->SetSessionId(sessionId);
10803 return result;
10804 }
10805
InitRequestPhotoUrisReadPermissionRequest(OHOS::AAFwk::Want & want,shared_ptr<RequestPhotoUrisReadPermissionCallback> & callback,napi_env env,napi_value args[],size_t argsLen)10806 static bool InitRequestPhotoUrisReadPermissionRequest(OHOS::AAFwk::Want &want,
10807 shared_ptr<RequestPhotoUrisReadPermissionCallback> &callback, napi_env env, napi_value args[], size_t argsLen)
10808 {
10809 NAPI_INFO_LOG("InitRequestPhotoUrisReadPermission enter.");
10810 if (argsLen < ARGS_FOUR) {
10811 return false;
10812 }
10813
10814 std::string targetType = "photoPicker";
10815 want.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
10816 std::string requestPhotoUrisTag = "requestPhotoUrisPage";
10817 want.SetParam(TARGET_PAGE, requestPhotoUrisTag);
10818
10819 // second param: Array<string>
10820 if (!ParseAndSetFileUriArray(env, want, args[PARAM1])) {
10821 NAPI_ERR_LOG("FileUriArray check failed.");
10822 return false;
10823 }
10824
10825 string appName;
10826 if (!ParseString(env, args[PARAM2], appName)) {
10827 NAPI_ERR_LOG("appName check failed.");
10828 return false;
10829 }
10830 want.SetParam(CONFIRM_BOX_APP_NAME, appName);
10831
10832 callback->SetFunc(args[PARAM3]);
10833 return true;
10834 }
10835
RequestPhotoUrisReadPermission(napi_env env,napi_callback_info info)10836 napi_value MediaLibraryNapi::RequestPhotoUrisReadPermission(napi_env env, napi_callback_info info)
10837 {
10838 NAPI_INFO_LOG("RequestPhotoUrisReadPermission enter");
10839 size_t argc = ARGS_FOUR;
10840 napi_value args[ARGS_FOUR] = {nullptr};
10841 napi_value thisVar = nullptr;
10842 napi_value result = nullptr;
10843 napi_create_object(env, &result);
10844 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
10845
10846 // first param: context, check whether context is abilityContext from stage mode
10847 Ace::UIContent *uiContent = nullptr;
10848 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
10849 NAPI_ASSERT(env, context != nullptr, "Context is null.");
10850
10851 shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
10852 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
10853 if (abilityContext == nullptr) {
10854 auto uiExtensionContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
10855 if (uiExtensionContext == nullptr) {
10856 NAPI_ERR_LOG("Fail to convert to abilityContext or uiExtensionContext");
10857 return nullptr;
10858 }
10859 uiContent = uiExtensionContext->GetUIContent();
10860 } else {
10861 // get uiContent from abilityContext
10862 uiContent = abilityContext->GetUIContent();
10863 }
10864 NAPI_ASSERT(env, uiContent != nullptr, "UiContent is null.");
10865
10866 // set want
10867 OHOS::AAFwk::Want want;
10868 shared_ptr<RequestPhotoUrisReadPermissionCallback> callback =
10869 make_shared<RequestPhotoUrisReadPermissionCallback>(env, uiContent);
10870 NAPI_ASSERT(env, InitRequestPhotoUrisReadPermissionRequest(want, callback, env, args, sizeof(args)),
10871 "Parse RequestPhotoUrisReadPermission input fail.");
10872
10873 // regist callback and config
10874 OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
10875 ([callback](auto arg) { callback->OnRelease(arg); }),
10876 ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
10877 ([callback](auto arg) { callback->OnReceive(arg); }),
10878 ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
10879 };
10880 OHOS::Ace::ModalUIExtensionConfig config;
10881 config.isProhibitBack = true;
10882 NAPI_INFO_LOG("RequestPhotoUrisReadPermission regist callback and config success.");
10883
10884 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
10885 NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
10886 callback->SetSessionId(sessionId);
10887 return result;
10888 }
10889
10890
StartPhotoPickerExecute(napi_env env,void * data)10891 static void StartPhotoPickerExecute(napi_env env, void *data)
10892 {
10893 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10894 while (!context->pickerCallBack->ready) {
10895 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
10896 }
10897 }
10898
StartPhotoPickerAsyncCallbackComplete(napi_env env,napi_status status,void * data)10899 static void StartPhotoPickerAsyncCallbackComplete(napi_env env, napi_status status, void *data)
10900 {
10901 NAPI_INFO_LOG("StartPhotoPickerAsyncCallbackComplete start");
10902 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
10903 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
10904
10905 auto jsContext = make_unique<JSAsyncContextOutput>();
10906 jsContext->status = false;
10907 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
10908 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_ERR_PARAMETER_INVALID);
10909 napi_value result = nullptr;
10910 napi_create_object(env, &result);
10911 napi_value resultCode = nullptr;
10912 napi_create_int32(env, context->pickerCallBack->resultCode, &resultCode);
10913 status = napi_set_named_property(env, result, "resultCode", resultCode);
10914 if (status != napi_ok) {
10915 NAPI_ERR_LOG("napi_set_named_property resultCode failed");
10916 }
10917 const vector<string> &uris = context->pickerCallBack->uris;
10918 napi_value jsUris = nullptr;
10919 napi_create_array_with_length(env, uris.size(), &jsUris);
10920 napi_value jsUri = nullptr;
10921 for (size_t i = 0; i < uris.size(); i++) {
10922 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, uris[i].c_str(),
10923 NAPI_AUTO_LENGTH, &jsUri), JS_INNER_FAIL);
10924 if ((jsUri == nullptr) || (napi_set_element(env, jsUris, i, jsUri) != napi_ok)) {
10925 NAPI_ERR_LOG("failed to set uri array");
10926 break;
10927 }
10928 }
10929 if (napi_set_named_property(env, result, "uris", jsUris) != napi_ok) {
10930 NAPI_ERR_LOG("napi_set_named_property uris failed");
10931 }
10932 napi_value isOrigin = nullptr;
10933 napi_get_boolean(env, context->pickerCallBack->isOrigin, &isOrigin);
10934 status = napi_set_named_property(env, result, "isOrigin", isOrigin);
10935 if (status != napi_ok) {
10936 NAPI_ERR_LOG("napi_set_named_property isOrigin failed");
10937 }
10938 if (result != nullptr) {
10939 jsContext->data = result;
10940 jsContext->status = true;
10941 } else {
10942 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
10943 "failed to create js object");
10944 }
10945 if (context->work != nullptr) {
10946 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
10947 context->work, *jsContext);
10948 }
10949 delete context;
10950 }
10951
GetSubWindowUIContent(napi_env env,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)10952 Ace::UIContent *GetSubWindowUIContent(napi_env env, unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
10953 {
10954 bool present = false;
10955 napi_status status = napi_has_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &present);
10956 if (status != napi_ok || !present) {
10957 return nullptr;
10958 }
10959 napi_value paramValue;
10960 status = napi_get_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", ¶mValue);
10961 CHECK_COND_RET(status == napi_ok, nullptr, "failed to get named property of parameters");
10962 present = false;
10963 status = napi_has_named_property(env, paramValue, "subWindowName", &present);
10964 if (status != napi_ok || !present) {
10965 return nullptr;
10966 }
10967 napi_value subWindowName;
10968 status = napi_get_named_property(env, paramValue, "subWindowName", &subWindowName);
10969 CHECK_COND_RET(status == napi_ok, nullptr, "failed to get named property of subWindowName");
10970 char buffer[ARG_BUF_SIZE];
10971 size_t res = 0;
10972 status = napi_get_value_string_utf8(env, subWindowName, buffer, ARG_BUF_SIZE, &res);
10973 if (status != napi_ok) {
10974 NAPI_ERR_LOG("failed to get the value of subWindow name");
10975 return nullptr;
10976 }
10977 auto currentWindow = Rosen::Window::Find(string(buffer));
10978 if (currentWindow == nullptr) {
10979 NAPI_ERR_LOG("GetSubWindowUIContent failed to find context by subWindow name");
10980 return nullptr;
10981 }
10982 return currentWindow->GetUIContent();
10983 }
10984
IsPcPicker(napi_env env,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)10985 static bool IsPcPicker(napi_env env, unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
10986 {
10987 bool present = false;
10988 napi_status status = napi_has_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", &present);
10989 if (status != napi_ok || !present) {
10990 return false;
10991 }
10992 napi_value paramValue;
10993 status = napi_get_named_property(env, AsyncContext->argv[ARGS_ONE], "parameters", ¶mValue);
10994 CHECK_COND_RET(status == napi_ok, false, "failed to get named property of parameters");
10995 present = false;
10996 status = napi_has_named_property(env, paramValue, "isPc", &present);
10997 if (status != napi_ok || !present) {
10998 return false;
10999 }
11000 napi_value isPc;
11001 status = napi_get_named_property(env, paramValue, "isPc", &isPc);
11002 CHECK_COND_RET(status == napi_ok, false, "failed to get named property of isPc");
11003 bool isPcPicker;
11004 napi_get_value_bool(env, isPc, &isPcPicker);
11005 return isPcPicker;
11006 }
11007
GetUIContent(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)11008 Ace::UIContent *GetUIContent(napi_env env, napi_callback_info info,
11009 unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
11010 {
11011 NAPI_INFO_LOG("GetUIContent start");
11012 if (!IsPcPicker(env, AsyncContext)) {
11013 NAPI_INFO_LOG("GetUIContent is not from PcPicker");
11014 Ace::UIContent *uiContent = GetSubWindowUIContent(env, AsyncContext);
11015 if (uiContent != nullptr) {
11016 NAPI_INFO_LOG("GetSubWindowUIContent success");
11017 return uiContent;
11018 }
11019 }
11020
11021 bool isStageMode = false;
11022 napi_status status = AbilityRuntime::IsStageContext(env, AsyncContext->argv[ARGS_ZERO], isStageMode);
11023 if (status != napi_ok || !isStageMode) {
11024 NAPI_ERR_LOG("is not StageMode context, status: %{public}d, isStageMode: %{public}d",
11025 status, static_cast<int32_t>(isStageMode));
11026 return nullptr;
11027 }
11028 auto context = AbilityRuntime::GetStageModeContext(env, AsyncContext->argv[ARGS_ZERO]);
11029 if (context == nullptr) {
11030 NAPI_ERR_LOG("Failed to get native stage context instance");
11031 return nullptr;
11032 }
11033 auto abilityContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::AbilityContext>(context);
11034 if (abilityContext == nullptr) {
11035 auto uiExtensionContext = AbilityRuntime::Context::ConvertTo<AbilityRuntime::UIExtensionContext>(context);
11036 if (uiExtensionContext == nullptr) {
11037 NAPI_ERR_LOG("Fail to convert to abilityContext or uiExtensionContext");
11038 return nullptr;
11039 }
11040 return uiExtensionContext->GetUIContent();
11041 }
11042 return abilityContext->GetUIContent();
11043 }
11044
StartPickerExtension(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & AsyncContext)11045 static napi_value StartPickerExtension(napi_env env, napi_callback_info info,
11046 unique_ptr<MediaLibraryAsyncContext> &AsyncContext)
11047 {
11048 NAPI_INFO_LOG("StartPickerExtension start");
11049 Ace::UIContent *uiContent = GetUIContent(env, info, AsyncContext);
11050 if (uiContent == nullptr) {
11051 NAPI_ERR_LOG("get uiContent failed");
11052 return nullptr;
11053 }
11054 AAFwk::Want request;
11055 AppExecFwk::UnwrapWant(env, AsyncContext->argv[ARGS_ONE], request);
11056 std::string targetType = "photoPicker";
11057 request.SetParam(ABILITY_WANT_PARAMS_UIEXTENSIONTARGETTYPE, targetType);
11058 AsyncContext->pickerCallBack = make_shared<PickerCallBack>();
11059 auto callback = std::make_shared<ModalUICallback>(uiContent, AsyncContext->pickerCallBack.get());
11060 Ace::ModalUIExtensionCallbacks extensionCallback = {
11061 ([callback](auto arg) { callback->OnRelease(arg); }),
11062 ([callback](auto arg1, auto arg2) { callback->OnResultForModal(arg1, arg2); }),
11063 ([callback](auto arg) { callback->OnReceive(arg); }),
11064 ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
11065 std::bind(&ModalUICallback::OnDestroy, callback),
11066 };
11067 Ace::ModalUIExtensionConfig config;
11068 config.isWindowModeFollowHost = true;
11069 config.isProhibitBack = true;
11070 int sessionId = uiContent->CreateModalUIExtension(request, extensionCallback, config);
11071 if (sessionId == 0) {
11072 NAPI_ERR_LOG("create modalUIExtension failed");
11073 return nullptr;
11074 }
11075 callback->SetSessionId(sessionId);
11076 napi_value result = nullptr;
11077 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
11078 return result;
11079 }
11080
11081 template <class AsyncContext>
AsyncContextSetStaticObjectInfo(napi_env env,napi_callback_info info,AsyncContext & asyncContext,const size_t minArgs,const size_t maxArgs)11082 static napi_status AsyncContextSetStaticObjectInfo(napi_env env, napi_callback_info info,
11083 AsyncContext &asyncContext, const size_t minArgs, const size_t maxArgs)
11084 {
11085 NAPI_INFO_LOG("AsyncContextSetStaticObjectInfo start");
11086 napi_value thisVar = nullptr;
11087 asyncContext->argc = maxArgs;
11088 CHECK_STATUS_RET(napi_get_cb_info(env, info, &asyncContext->argc, &(asyncContext->argv[ARGS_ZERO]), &thisVar,
11089 nullptr), "Failed to get cb info");
11090 CHECK_COND_RET(((asyncContext->argc >= minArgs) && (asyncContext->argc <= maxArgs)), napi_invalid_arg,
11091 "Number of args is invalid");
11092 if (minArgs > 0) {
11093 CHECK_COND_RET(asyncContext->argv[ARGS_ZERO] != nullptr, napi_invalid_arg, "Argument list is empty");
11094 }
11095 CHECK_STATUS_RET(MediaLibraryNapiUtils::GetParamCallback(env, asyncContext), "Failed to get callback param!");
11096 return napi_ok;
11097 }
11098
ParseArgsStartPhotoPicker(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11099 static napi_value ParseArgsStartPhotoPicker(napi_env env, napi_callback_info info,
11100 unique_ptr<MediaLibraryAsyncContext> &context)
11101 {
11102 NAPI_INFO_LOG("ParseArgsStartPhotoPicker start");
11103 constexpr size_t minArgs = ARGS_TWO;
11104 constexpr size_t maxArgs = ARGS_THREE;
11105 CHECK_ARGS(env, AsyncContextSetStaticObjectInfo(env, info, context, minArgs, maxArgs),
11106 JS_ERR_PARAMETER_INVALID);
11107 NAPI_CALL(env, MediaLibraryNapiUtils::GetParamCallback(env, context));
11108 CHECK_NULLPTR_RET(StartPickerExtension(env, info, context));
11109 napi_value result = nullptr;
11110 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
11111 return result;
11112 }
11113
PhotoAccessGetSupportedPhotoFormatsExec(MediaLibraryAsyncContext * context)11114 static void PhotoAccessGetSupportedPhotoFormatsExec(MediaLibraryAsyncContext *context)
11115 {
11116 CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
11117 if (context->photoType == MEDIA_TYPE_IMAGE || context->photoType == MEDIA_TYPE_VIDEO) {
11118 context->mediaTypeNames = MediaFileUtils::GetAllTypes(context->photoType);
11119 } else {
11120 context->SaveError(E_FAIL);
11121 }
11122 }
11123
GetSupportedPhotoFormatsAsyncCallbadkComplete(napi_env env,napi_status status,void * data)11124 static void GetSupportedPhotoFormatsAsyncCallbadkComplete(napi_env env, napi_status status, void *data)
11125 {
11126 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11127 CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
11128 auto jsContext = make_unique<JSAsyncContextOutput>();
11129 CHECK_IF_EQUAL(jsContext != nullptr, "jsContext is nullptr");
11130 napi_value mediaValue;
11131 napi_value resultTypes;
11132 napi_create_array(env, &resultTypes);
11133 int count = 0;
11134 jsContext->status = false;
11135 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_ERR_PARAMETER_INVALID);
11136 if (context->error != ERR_DEFAULT) {
11137 context->HandleError(env, jsContext->error);
11138 } else {
11139 for (const auto &type_out : context->mediaTypeNames) {
11140 CHECK_ARGS_RET_VOID(
11141 env, napi_create_string_utf8(env, type_out.c_str(), NAPI_AUTO_LENGTH, &mediaValue),
11142 JS_INNER_FAIL);
11143 CHECK_ARGS_RET_VOID(
11144 env, napi_set_element(env, resultTypes, count++, mediaValue), JS_INNER_FAIL);
11145 }
11146 jsContext->status = true;
11147 jsContext->data = resultTypes;
11148 }
11149 if (context->work != nullptr) {
11150 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11151 context->work, *jsContext);
11152 }
11153 delete context;
11154 }
11155
PhotoAccessGetSupportedPhotoFormats(napi_env env,napi_callback_info info)11156 napi_value MediaLibraryNapi::PhotoAccessGetSupportedPhotoFormats(napi_env env, napi_callback_info info)
11157 {
11158 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11159 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->photoType),
11160 JS_ERR_PARAMETER_INVALID);
11161
11162 SetUserIdFromObjectInfo(asyncContext);
11163 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSupportedPhotoFormats",
11164 [](napi_env env, void *data) {
11165 auto context = static_cast<MediaLibraryAsyncContext*>(data);
11166 PhotoAccessGetSupportedPhotoFormatsExec(context);
11167 },
11168 reinterpret_cast<CompleteCallback>(GetSupportedPhotoFormatsAsyncCallbadkComplete));
11169 }
11170
StartPhotoPicker(napi_env env,napi_callback_info info)11171 napi_value MediaLibraryNapi::StartPhotoPicker(napi_env env, napi_callback_info info)
11172 {
11173 NAPI_INFO_LOG("StartPhotoPicker start");
11174 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11175 auto pickerCallBack = make_shared<PickerCallBack>();
11176 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
11177 ParseArgsStartPhotoPicker(env, info, asyncContext);
11178
11179 SetUserIdFromObjectInfo(asyncContext);
11180 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "StrartPhotoPicker",
11181 StartPhotoPickerExecute, StartPhotoPickerAsyncCallbackComplete);
11182 }
11183
PhotoAccessHelperSetForceHideSensitiveType(napi_env env,napi_callback_info info)11184 napi_value MediaLibraryNapi::PhotoAccessHelperSetForceHideSensitiveType(napi_env env, napi_callback_info info)
11185 {
11186 MediaLibraryTracer tracer;
11187 tracer.Start("PhotoAccessHelperSetForceHideSensitiveType");
11188
11189 NAPI_INFO_LOG("enter");
11190
11191 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11192 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
11193 asyncContext->assetType = TYPE_PHOTO;
11194 NAPI_ASSERT(env, ParseArgsGrantPhotoUrisForForceSensitive(env, info, asyncContext), "Failed to parse js args");
11195
11196 SetUserIdFromObjectInfo(asyncContext);
11197 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessGrantPhotoUrisPermission",
11198 PhotoAccessGrantPhotoUrisPermissionExecute, JSPhotoUriPermissionCallback);
11199 }
11200
PhotoAccessGetSharedPhotoAssets(napi_env env,napi_callback_info info)11201 napi_value MediaLibraryNapi::PhotoAccessGetSharedPhotoAssets(napi_env env, napi_callback_info info)
11202 {
11203 MediaLibraryTracer tracer;
11204 tracer.Start("PhotoAccessGetSharedPhotoAssets");
11205 unique_ptr<MediaLibraryAsyncContext> asyncContext =
11206 make_unique<MediaLibraryAsyncContext>();
11207 asyncContext->assetType = TYPE_PHOTO;
11208 CHECK_NULLPTR_RET(ParseArgsGetAssets(env, info, asyncContext));
11209
11210 MediaLibraryAsyncContext* context =
11211 static_cast<MediaLibraryAsyncContext*>((asyncContext.get()));
11212 string queryUri = PAH_QUERY_PHOTO;
11213 MediaLibraryNapiUtils::UriAppendKeyValue(queryUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
11214
11215 Uri uri(queryUri);
11216 shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
11217 context->predicates, context->fetchColumn);
11218 CHECK_NULLPTR_RET(resultSet);
11219
11220 napi_value jsFileArray = 0;
11221 napi_create_array(env, &jsFileArray);
11222
11223 int count = 0;
11224 int err = resultSet->GoToFirstRow();
11225 if (err != napi_ok) {
11226 NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
11227 return jsFileArray;
11228 }
11229 do {
11230 napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet, true);
11231 napi_set_element(env, jsFileArray, count++, item);
11232 } while (!resultSet->GoToNextRow());
11233 resultSet->Close();
11234 return jsFileArray;
11235 }
11236
InitDefaultAlbumNameRequest(OHOS::AAFwk::Want & want,shared_ptr<DefaultAlbumNameCallback> & callback,napi_env env,napi_value args[],size_t argsLen)11237 static bool InitDefaultAlbumNameRequest(OHOS::AAFwk::Want &want, shared_ptr<DefaultAlbumNameCallback> &callback,
11238 napi_env env, napi_value args[], size_t argsLen)
11239 {
11240 if (argsLen < ARGS_TWO) {
11241 return false;
11242 }
11243
11244 want.SetElementName(CONFIRM_BOX_PACKAGE_NAME, CONFIRM_BOX_EXT_DEFAULT_ALBUM_NAME_ABILITY_NAME);
11245 want.SetParam(CONFIRM_BOX_EXTENSION_TYPE, CONFIRM_BOX_REQUEST_TYPE);
11246
11247 callback->SetFunc(args[PARAM1]);
11248 return true;
11249 }
11250
GetPhotoPickerComponentDefaultAlbumName(napi_env env,napi_callback_info info)11251 napi_value MediaLibraryNapi::GetPhotoPickerComponentDefaultAlbumName(napi_env env, napi_callback_info info)
11252 {
11253 NAPI_INFO_LOG("GetPhotoPickerComponentDefaultAlbumName enter");
11254 size_t argc = ARGS_TWO;
11255 napi_value args[ARGS_TWO] = {nullptr};
11256 napi_value thisVar = nullptr;
11257 napi_value result = nullptr;
11258 napi_create_object(env, &result);
11259 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr), JS_ERR_PARAMETER_INVALID);
11260 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, args[ARGS_ZERO]);
11261 NAPI_ASSERT(env, context != nullptr, "context == nullptr");
11262
11263 shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext =
11264 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
11265 NAPI_ASSERT(env, abilityContext != nullptr, "abilityContext == nullptr");
11266
11267 auto uiContent = abilityContext->GetUIContent();
11268 NAPI_ASSERT(env, uiContent != nullptr, "uiContent == nullptr");
11269
11270 OHOS::AAFwk::Want want;
11271 shared_ptr<DefaultAlbumNameCallback> callback = make_shared<DefaultAlbumNameCallback>(env, uiContent);
11272 NAPI_ASSERT(env, InitDefaultAlbumNameRequest(want, callback, env, args, sizeof(args)),
11273 "parse default album name param fail");
11274
11275 OHOS::Ace::ModalUIExtensionCallbacks extensionCallback = {
11276 ([callback](auto arg) { callback->OnRelease(arg); }),
11277 ([callback](auto arg1, auto arg2) { callback->OnResult(arg1, arg2); }),
11278 ([callback](auto arg) { callback->OnReceive(arg); }),
11279 ([callback](auto arg1, auto arg2, auto arg3) { callback->OnError(arg1, arg2, arg3); }),
11280 };
11281 OHOS::Ace::ModalUIExtensionConfig config;
11282 config.isProhibitBack = true;
11283 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallback, config);
11284 NAPI_ASSERT(env, sessionId != DEFAULT_SESSION_ID, "CreateModalUIExtension fail");
11285 callback->SetSessionId(sessionId);
11286 return result;
11287 }
11288
CheckOrderStyle(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,OrderStyleType & orderStyle)11289 static napi_value CheckOrderStyle(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context,
11290 OrderStyleType &orderStyle)
11291 {
11292 CHECK_COND_RET(context->argc >= ARGS_ONE, nullptr, "No arguments to check order style");
11293
11294 int32_t albumOrderStyle;
11295 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], albumOrderStyle));
11296 double doubleArg;
11297 CHECK_COND_RET(MediaLibraryNapiUtils::GetDouble(env, context->argv[PARAM0], doubleArg) == napi_ok, nullptr,
11298 "Failed to get orderStyle");
11299 CHECK_ARGS_WITH_MEG(env, doubleArg == static_cast<double>(albumOrderStyle), JS_E_PARAM_INVALID,
11300 "orderStyle is not an integer");
11301
11302 if (!PhotoAlbum::CheckOrderStyleType(static_cast<OrderStyleType>(albumOrderStyle))) {
11303 NapiError::ThrowError(env, JS_E_PARAM_INVALID, "orderStyle is an invalid parameter");
11304 return nullptr;
11305 }
11306
11307 napi_value result = nullptr;
11308 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11309 orderStyle = static_cast<OrderStyleType>(albumOrderStyle);
11310 return result;
11311 }
11312
ParseArgsGetPhotoAlbumsWithoutSubtype(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11313 static napi_value ParseArgsGetPhotoAlbumsWithoutSubtype(napi_env env, napi_callback_info info,
11314 unique_ptr<MediaLibraryAsyncContext> &context)
11315 {
11316 if (!MediaLibraryNapiUtils::IsSystemApp()) {
11317 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system app");
11318 return nullptr;
11319 }
11320
11321 constexpr size_t minArgs = ARGS_ZERO;
11322 constexpr size_t maxArgs = ARGS_ONE;
11323 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
11324 JS_E_PARAM_INVALID);
11325
11326 if (context->argc == maxArgs) {
11327 napi_valuetype valueType = napi_undefined;
11328 if (napi_typeof(env, context->argv[PARAM1], &valueType) == napi_ok &&
11329 (valueType == napi_undefined || valueType == napi_null)) {
11330 context->argc -= 1;
11331 }
11332 }
11333
11334 if (context->argc == maxArgs) {
11335 auto status =
11336 MediaLibraryNapiUtils::GetFetchOption(env, context->argv[maxArgs - 1], ALBUM_FETCH_OPT, context);
11337 CHECK_ARGS(env, status, JS_E_INNER_FAIL);
11338 }
11339 RestrictAlbumSubtypeOptions(context->predicates);
11340
11341 CHECK_COND(env, CheckAlbumFetchColumns(context->fetchColumn), JS_E_INNER_FAIL);
11342 AddNoSmartFetchColumns(context->fetchColumn);
11343
11344 napi_value result = nullptr;
11345 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11346 return result;
11347 }
11348
JSGetPhotoAlbumsWithoutSubtypeExecute(napi_env env,void * data)11349 static void JSGetPhotoAlbumsWithoutSubtypeExecute(napi_env env, void *data)
11350 {
11351 MediaLibraryTracer tracer;
11352 tracer.Start("JSGetPhotoAlbumsWithoutSubtypeExecute");
11353
11354 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11355 GetPhotoAlbumObjectReqBody reqBody;
11356 GetPhotoAlbumObjectRespBody respBody;
11357 shared_ptr<DataShareResultSet> resultSet;
11358 reqBody.predicates = context->predicates;
11359 reqBody.columns = context->fetchColumn;
11360 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GET_PHOTO_ALBUMS);
11361
11362 int32_t errCode = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
11363 resultSet = respBody.resultSet;
11364 if (resultSet == nullptr) {
11365 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
11366 if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
11367 context->SaveError(errCode);
11368 } else {
11369 context->SaveError(E_INNER_FAIL);
11370 }
11371 return;
11372 }
11373
11374 context->fetchPhotoAlbumResult = make_unique<FetchResult<PhotoAlbum>>(move(resultSet));
11375 context->fetchPhotoAlbumResult->SetResultNapiType(context->resultNapiType);
11376 context->fetchPhotoAlbumResult->SetUserId(context->userId);
11377 }
11378
GetNapiPhotoAlbumResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)11379 static void GetNapiPhotoAlbumResult(napi_env env, MediaLibraryAsyncContext *context,
11380 unique_ptr<JSAsyncContextOutput> &jsContext)
11381 {
11382 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchPhotoAlbumResult));
11383 if (fileResult == nullptr) {
11384 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_E_INNER_FAIL);
11385 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
11386 "Failed to create js object for Fetch Photo Album Result");
11387 return;
11388 }
11389 jsContext->data = fileResult;
11390 jsContext->status = true;
11391 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_E_INNER_FAIL);
11392 }
11393
GetPhotoAlbumsWithoutSubtypeCompleteCallback(napi_env env,napi_status status,void * data)11394 static void GetPhotoAlbumsWithoutSubtypeCompleteCallback(napi_env env, napi_status status, void *data)
11395 {
11396 MediaLibraryTracer tracer;
11397 tracer.Start("GetPhotoAlbumsWithoutSubtypeCompleteCallback");
11398
11399 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11400 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
11401 jsContext->status = false;
11402 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_E_INNER_FAIL);
11403 if (context->error != ERR_DEFAULT || context->fetchPhotoAlbumResult == nullptr) {
11404 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_E_INNER_FAIL);
11405 context->HandleError(env, jsContext->error);
11406 } else {
11407 GetNapiPhotoAlbumResult(env, context, jsContext);
11408 }
11409
11410 tracer.Finish();
11411 if (context->work != nullptr) {
11412 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11413 context->work, *jsContext);
11414 }
11415 delete context;
11416 }
11417
PhotoAccessGetPhotoAlbumsWithoutSubtype(napi_env env,napi_callback_info info)11418 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumsWithoutSubtype(napi_env env, napi_callback_info info)
11419 {
11420 MediaLibraryTracer tracer;
11421 tracer.Start("PhotoAccessGetPhotoAlbumsWithoutSubtype");
11422
11423 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11424 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
11425 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbumsWithoutSubtype(env, info, asyncContext));
11426
11427 SetUserIdFromObjectInfo(asyncContext);
11428 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbumsWithoutSubtype",
11429 JSGetPhotoAlbumsWithoutSubtypeExecute, GetPhotoAlbumsWithoutSubtypeCompleteCallback);
11430 }
11431
AddDefaultAlbumOrderColumns(napi_env env,unique_ptr<MediaLibraryAsyncContext> & context,vector<string> & fetchColumns,const OrderStyleType & orderStyle)11432 static napi_value AddDefaultAlbumOrderColumns(napi_env env, unique_ptr<MediaLibraryAsyncContext> &context,
11433 vector<string> &fetchColumns, const OrderStyleType &orderStyle)
11434 {
11435 auto validFetchColumns = (orderStyle == OrderStyleType::MIX) ?
11436 PhotoAlbumColumns::DEFAULT_FETCH_ORDER_COLUMNS_STYLE1 : PhotoAlbumColumns::DEFAULT_FETCH_ORDER_COLUMNS_STYLE2;
11437 for (const auto &column : fetchColumns) {
11438 if (!AlbumOrder::IsAlbumOrderColumn(orderStyle, column)) {
11439 NAPI_ERR_LOG("AlbumOrder does not contain this column: %{public}s, orderStyle: %{public}d",
11440 column.c_str(), static_cast<int32_t>(orderStyle));
11441 return nullptr;
11442 }
11443 }
11444 fetchColumns.assign(validFetchColumns.begin(), validFetchColumns.end());
11445
11446 napi_value result = nullptr;
11447 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11448 return result;
11449 }
11450
ParseArgsGetPhotoAlbumOrder(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11451 static napi_value ParseArgsGetPhotoAlbumOrder(napi_env env, napi_callback_info info,
11452 unique_ptr<MediaLibraryAsyncContext> &context)
11453 {
11454 if (!MediaLibraryNapiUtils::IsSystemApp()) {
11455 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system app");
11456 return nullptr;
11457 }
11458
11459 constexpr size_t minArgs = ARGS_ONE;
11460 constexpr size_t maxArgs = ARGS_TWO;
11461 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
11462 JS_E_PARAM_INVALID);
11463
11464 if (context->argc == maxArgs) {
11465 napi_valuetype valueType = napi_undefined;
11466 if (napi_typeof(env, context->argv[PARAM1], &valueType) == napi_ok &&
11467 (valueType == napi_undefined || valueType == napi_null)) {
11468 context->argc -= 1;
11469 }
11470 }
11471
11472 OrderStyleType orderStyle;
11473 CHECK_ARGS_WITH_MEG(env, CheckOrderStyle(env, context, orderStyle), JS_E_PARAM_INVALID,
11474 "Failed to check orderStyle");
11475
11476 if (context->argc == maxArgs) {
11477 auto status =
11478 MediaLibraryNapiUtils::GetFetchOption(env, context->argv[maxArgs - 1], ALBUM_FETCH_OPT, context);
11479 CHECK_ARGS(env, status, JS_E_INNER_FAIL);
11480 }
11481 RestrictAlbumSubtypeOptions(context->predicates);
11482
11483 CHECK_ARGS_WITH_MEG(env, AddDefaultAlbumOrderColumns(env, context, context->fetchColumn, orderStyle),
11484 JS_E_PARAM_INVALID, "Failed to add default columns");
11485
11486 napi_value result = nullptr;
11487 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11488 return result;
11489 }
11490
11491
JSGetPhotoAlbumOrderExecute(napi_env env,void * data)11492 static void JSGetPhotoAlbumOrderExecute(napi_env env, void *data)
11493 {
11494 MediaLibraryTracer tracer;
11495 tracer.Start("JSGetPhotoAlbumOrderExecute");
11496
11497 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11498 GetPhotoAlbumObjectReqBody reqBody;
11499 GetPhotoAlbumObjectRespBody respBody;
11500 shared_ptr<DataShareResultSet> resultSet;
11501 reqBody.predicates = context->predicates;
11502 reqBody.columns = context->fetchColumn;
11503 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_GET_PHOTO_ALBUM_ORDER);
11504
11505 int32_t errCode = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
11506 resultSet = respBody.resultSet;
11507 if (resultSet == nullptr) {
11508 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
11509 if (errCode == E_PERMISSION_DENIED || errCode == -E_CHECK_SYSTEMAPP_FAIL) {
11510 context->SaveError(errCode);
11511 } else {
11512 context->SaveError(E_INNER_FAIL);
11513 }
11514 return;
11515 }
11516
11517 context->fetchAlbumOrderResult = make_unique<FetchResult<AlbumOrder>>(move(resultSet));
11518 }
11519
GetNapiAlbumOrderResult(napi_env env,MediaLibraryAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)11520 static void GetNapiAlbumOrderResult(napi_env env, MediaLibraryAsyncContext *context,
11521 unique_ptr<JSAsyncContextOutput> &jsContext)
11522 {
11523 if (context->fetchAlbumOrderResult == nullptr) {
11524 NAPI_ERR_LOG("No fetch album order result found!");
11525 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
11526 "Failed to obtain Fetch AlbumOrder Result");
11527 return;
11528 }
11529 napi_value fileResult = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchAlbumOrderResult));
11530 if (fileResult == nullptr) {
11531 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
11532 "Failed to create js object for Fetch File Result");
11533 } else {
11534 jsContext->data = fileResult;
11535 jsContext->status = true;
11536 napi_get_undefined(env, &jsContext->error);
11537 }
11538 }
11539
GetAlbumOrderCallbackComplete(napi_env env,napi_status status,void * data)11540 static void GetAlbumOrderCallbackComplete(napi_env env, napi_status status, void *data)
11541 {
11542 MediaLibraryTracer tracer;
11543 tracer.Start("GetAlbumOrderCallbackComplete");
11544
11545 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11546 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
11547
11548 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
11549 jsContext->status = false;
11550 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_E_INNER_FAIL);
11551
11552 if (context->error != ERR_DEFAULT) {
11553 context->HandleError(env, jsContext->error);
11554 } else {
11555 GetNapiAlbumOrderResult(env, context, jsContext);
11556 }
11557
11558 tracer.Finish();
11559 if (context->work != nullptr) {
11560 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11561 context->work, *jsContext);
11562 }
11563 delete context;
11564 }
11565
PhotoAccessGetPhotoAlbumOrder(napi_env env,napi_callback_info info)11566 napi_value MediaLibraryNapi::PhotoAccessGetPhotoAlbumOrder(napi_env env, napi_callback_info info)
11567 {
11568 MediaLibraryTracer tracer;
11569 tracer.Start("PhotoAccessGetPhotoAlbumOrder");
11570
11571 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11572 CHECK_NULLPTR_RET(ParseArgsGetPhotoAlbumOrder(env, info, asyncContext));
11573
11574 SetUserIdFromObjectInfo(asyncContext);
11575 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "GetPhotoAlbumOrder",
11576 JSGetPhotoAlbumOrderExecute, GetAlbumOrderCallbackComplete);
11577 }
11578
HandleAlbumOrderParam(AlbumOrderNapi * obj,DataShareValuesBucket & valuesBucket,OrderStyleType orderStyle,AlbumOrderParam param)11579 static napi_status HandleAlbumOrderParam(AlbumOrderNapi *obj, DataShareValuesBucket &valuesBucket,
11580 OrderStyleType orderStyle, AlbumOrderParam param)
11581 {
11582 int32_t index = static_cast<int32_t>(orderStyle);
11583 auto iter = PhotoAlbumColumns::ORDER_COLUMN_STYLE_MAP.find(param);
11584 if (iter != PhotoAlbumColumns::ORDER_COLUMN_STYLE_MAP.end()) {
11585 size_t len = iter->second.size();
11586 CHECK_COND_RET(index >= 0 && static_cast<size_t>(index) < len, napi_invalid_arg,
11587 "The orderStyle has exceeded the length of the column array, unable to find the real column name");
11588
11589 string columnName = iter->second[index];
11590 switch (param) {
11591 case AlbumOrderParam::ALBUM_ORDER:
11592 valuesBucket.Put(columnName, obj->GetAlbumOrder());
11593 break;
11594 case AlbumOrderParam::ORDER_SECTION:
11595 valuesBucket.Put(columnName, obj->GetOrderSection());
11596 break;
11597 case AlbumOrderParam::ORDER_TYPE:
11598 valuesBucket.Put(columnName, obj->GetOrderType());
11599 break;
11600 case AlbumOrderParam::ORDER_STATUS:
11601 valuesBucket.Put(columnName, obj->GetOrderStatus());
11602 break;
11603 default:
11604 break;
11605 }
11606 }
11607 return napi_ok;
11608 }
11609
TransAlbumOrderToBuckets(AlbumOrderNapi * obj,DataShare::DataShareValuesBucket & values,OrderStyleType orderStyle)11610 static napi_status TransAlbumOrderToBuckets(AlbumOrderNapi *obj, DataShare::DataShareValuesBucket &values,
11611 OrderStyleType orderStyle)
11612 {
11613 for (int i = static_cast<int32_t>(AlbumOrderParam::ALBUM_ORDER);
11614 i <= static_cast<int32_t>(AlbumOrderParam::ORDER_STATUS); i++) {
11615 AlbumOrderParam param = static_cast<AlbumOrderParam>(i);
11616 CHECK_COND_RET(HandleAlbumOrderParam(obj, values, orderStyle, param) == napi_ok, napi_invalid_arg,
11617 "orderStyle cannot be mapped to the actual rdb columnName");
11618 }
11619 return napi_ok;
11620 }
11621
ParseAlbumOrderArray(napi_env env,napi_value arg,OrderStyleType orderStyle,vector<DataShare::DataShareValuesBucket> & dataShareValuesBuckets)11622 static napi_value ParseAlbumOrderArray(napi_env env, napi_value arg, OrderStyleType orderStyle,
11623 vector<DataShare::DataShareValuesBucket> &dataShareValuesBuckets)
11624 {
11625 bool isArray = false;
11626 CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_E_INNER_FAIL);
11627 CHECK_ARGS_WITH_MEG(env, isArray == true, JS_E_PARAM_INVALID, "Failed to check array type");
11628
11629 uint32_t len = 0;
11630 CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_E_INNER_FAIL);
11631 CHECK_ARGS_WITH_MEG(env, len > 0, JS_E_PARAM_INVALID, "Failed to check array length");
11632
11633 for (uint32_t i = 0; i < len; i++) {
11634 napi_value orderData = nullptr;
11635 CHECK_ARGS(env, napi_get_element(env, arg, i, &orderData), JS_E_INNER_FAIL);
11636 CHECK_ARGS_WITH_MEG(env, orderData != nullptr, JS_E_PARAM_INVALID, "Failed to get album order element");
11637
11638 AlbumOrderNapi *obj = nullptr;
11639 DataShareValuesBucket valuesBucket;
11640 CHECK_ARGS(env, napi_unwrap(env, orderData, reinterpret_cast<void **>(&obj)), JS_E_INNER_FAIL);
11641 CHECK_ARGS_WITH_MEG(env, obj != nullptr, JS_E_PARAM_INVALID, "Failed to get albumOrder napi object");
11642
11643 if (obj->GetAlbumId() <= 0) {
11644 NAPI_ERR_LOG("Skip invalid album order, albumId: %{public}d", obj->GetAlbumId());
11645 continue;
11646 }
11647 valuesBucket.Put(PhotoAlbumColumns::ALBUM_ID, obj->GetAlbumId());
11648 CHECK_ARGS_WITH_MEG(env, TransAlbumOrderToBuckets(obj, valuesBucket, orderStyle) == napi_ok,
11649 JS_E_PARAM_INVALID, "Transform albumOrder to datasharvaluebucket failed");
11650
11651 dataShareValuesBuckets.emplace_back(valuesBucket);
11652 }
11653
11654 napi_value result = nullptr;
11655 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11656 return result;
11657 }
11658
ParseArgsSetPhotoAlbumOrder(napi_env env,napi_callback_info info,unique_ptr<MediaLibraryAsyncContext> & context)11659 static napi_value ParseArgsSetPhotoAlbumOrder(napi_env env, napi_callback_info info,
11660 unique_ptr<MediaLibraryAsyncContext> &context)
11661 {
11662 if (!MediaLibraryNapiUtils::IsSystemApp()) {
11663 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system app");
11664 return nullptr;
11665 }
11666
11667 napi_value result = nullptr;
11668 constexpr size_t minArgs = ARGS_TWO;
11669 constexpr size_t maxArgs = ARGS_TWO;
11670 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
11671 JS_E_PARAM_INVALID);
11672
11673 OrderStyleType orderStyle;
11674 CHECK_ARGS_WITH_MEG(env, CheckOrderStyle(env, context, orderStyle), JS_E_PARAM_INVALID,
11675 "Failed to check orderStyle");
11676 context->orderStyle = static_cast<int32_t>(orderStyle);
11677
11678 CHECK_NULLPTR_RET(ParseAlbumOrderArray(env, context->argv[PARAM1], orderStyle, context->valuesBucketArray));
11679
11680 CHECK_ARGS_WITH_MEG(env, !context->valuesBucketArray.empty(), JS_E_PARAM_INVALID,
11681 "Albumorder array is empty");
11682 CHECK_ARGS_WITH_MEG(env, context->valuesBucketArray.size() <= MAX_SET_ORDER_ARRAY_SIZE, JS_E_PARAM_INVALID,
11683 "Exceeded the maximum batch input quantity, can not update album order");
11684
11685 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_E_INNER_FAIL);
11686 return result;
11687 }
11688
TransValueBucketToReqBody(const std::vector<OHOS::DataShare::DataShareValuesBucket> & valuesBucketArray,const int32_t & orderStyle,SetPhotoAlbumOrderReqBody & reqBody)11689 static void TransValueBucketToReqBody(const std::vector<OHOS::DataShare::DataShareValuesBucket> &valuesBucketArray,
11690 const int32_t &orderStyle, SetPhotoAlbumOrderReqBody &reqBody)
11691 {
11692 reqBody.albumOrderColumn = PhotoAlbumColumns::ALBUM_ORDER_COLUMNS[orderStyle];
11693 reqBody.orderSectionColumn = PhotoAlbumColumns::ALBUM_ORDER_SECTION_COLUMNS[orderStyle];
11694 reqBody.orderTypeColumn = PhotoAlbumColumns::ALBUM_ORDER_TYPE_COLUMNS[orderStyle];
11695 reqBody.orderStatusColumn = PhotoAlbumColumns::ALBUM_ORDER_STATUS_COLUMNS[orderStyle];
11696
11697 bool isValid = false;
11698 for (const auto& valueBucket : valuesBucketArray) {
11699 reqBody.albumIds.emplace_back(valueBucket.Get(PhotoAlbumColumns::ALBUM_ID, isValid));
11700 reqBody.albumOrders.emplace_back(valueBucket.Get(reqBody.albumOrderColumn, isValid));
11701 reqBody.orderSection.emplace_back(valueBucket.Get(reqBody.orderSectionColumn, isValid));
11702 reqBody.orderType.emplace_back(valueBucket.Get(reqBody.orderTypeColumn, isValid));
11703 reqBody.orderStatus.emplace_back(valueBucket.Get(reqBody.orderStatusColumn, isValid));
11704 }
11705 }
11706
JSSetPhotoAlbumOrderExecute(napi_env env,void * data)11707 static void JSSetPhotoAlbumOrderExecute(napi_env env, void *data)
11708 {
11709 MediaLibraryTracer tracer;
11710 tracer.Start("JSSetPhotoAlbumOrderExecute");
11711
11712 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11713 SetPhotoAlbumOrderReqBody reqBody;
11714 TransValueBucketToReqBody(context->valuesBucketArray, context->orderStyle, reqBody);
11715
11716 uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SET_PHOTO_ALBUM_ORDER);
11717 int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
11718 if (ret < 0) {
11719 context->SaveError(ret);
11720 NAPI_ERR_LOG("set photo album order failed, err: %{public}d", ret);
11721 }
11722 }
11723
JSSetAlbumOrderCompleteCallback(napi_env env,napi_status status,void * data)11724 static void JSSetAlbumOrderCompleteCallback(napi_env env, napi_status status, void *data)
11725 {
11726 MediaLibraryTracer tracer;
11727 tracer.Start("JSSetAlbumOrderCompleteCallback");
11728
11729 auto *context = static_cast<MediaLibraryAsyncContext*>(data);
11730 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
11731 jsContext->status = false;
11732 if (context->error == ERR_DEFAULT) {
11733 jsContext->status = true;
11734 napi_get_undefined(env, &jsContext->error);
11735 napi_get_undefined(env, &jsContext->data);
11736 } else {
11737 napi_get_undefined(env, &jsContext->data);
11738 context->HandleError(env, jsContext->error);
11739 }
11740 if (context->work != nullptr) {
11741 tracer.Finish();
11742 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
11743 context->work, *jsContext);
11744 }
11745 delete context;
11746 }
11747
PhotoAccessSetPhotoAlbumOrder(napi_env env,napi_callback_info info)11748 napi_value MediaLibraryNapi::PhotoAccessSetPhotoAlbumOrder(napi_env env, napi_callback_info info)
11749 {
11750 MediaLibraryTracer tracer;
11751 tracer.Start("PhotoAccessSetPhotoAlbumOrder");
11752
11753 unique_ptr<MediaLibraryAsyncContext> asyncContext = make_unique<MediaLibraryAsyncContext>();
11754 CHECK_NULLPTR_RET(ParseArgsSetPhotoAlbumOrder(env, info, asyncContext));
11755
11756 SetUserIdFromObjectInfo(asyncContext);
11757 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "SetPhotoAlbumOrder",
11758 JSSetPhotoAlbumOrderExecute, JSSetAlbumOrderCompleteCallback);
11759 }
11760
GetUserId()11761 int32_t MediaLibraryNapi::GetUserId()
11762 {
11763 return userId_;
11764 }
11765
SetUserId(const int32_t & userId)11766 void MediaLibraryNapi::SetUserId(const int32_t &userId)
11767 {
11768 userId_ = userId;
11769 }
11770 } // namespace Media
11771 } // namespace OHOS
11772