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