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