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