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