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