1 /*
2 * Copyright (C) 2023 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 "MediaAlbumChangeRequestNapi"
17
18 #include "media_album_change_request_napi.h"
19
20 #include <unordered_map>
21 #include <unordered_set>
22
23 #include "file_asset_napi.h"
24 #include "media_file_utils.h"
25 #include "medialibrary_client_errno.h"
26 #include "medialibrary_napi_log.h"
27 #include "medialibrary_tracer.h"
28 #include "photo_album_napi.h"
29 #include "photo_map_column.h"
30 #include "result_set_utils.h"
31 #include "userfile_client.h"
32 #include "vision_column.h"
33 #include "vision_face_tag_column.h"
34 #include "vision_photo_map_column.h"
35
36 using namespace std;
37
38 namespace OHOS::Media {
39 static const string MEDIA_ALBUM_CHANGE_REQUEST_CLASS = "MediaAlbumChangeRequest";
40 thread_local napi_ref MediaAlbumChangeRequestNapi::constructor_ = nullptr;
41
Init(napi_env env,napi_value exports)42 napi_value MediaAlbumChangeRequestNapi::Init(napi_env env, napi_value exports)
43 {
44 NapiClassInfo info = { .name = MEDIA_ALBUM_CHANGE_REQUEST_CLASS,
45 .ref = &constructor_,
46 .constructor = Constructor,
47 .props = {
48 DECLARE_NAPI_STATIC_FUNCTION("createAlbumRequest", JSCreateAlbumRequest),
49 DECLARE_NAPI_STATIC_FUNCTION("deleteAlbums", JSDeleteAlbums),
50 DECLARE_NAPI_FUNCTION("getAlbum", JSGetAlbum),
51 DECLARE_NAPI_FUNCTION("addAssets", JSAddAssets),
52 DECLARE_NAPI_FUNCTION("removeAssets", JSRemoveAssets),
53 DECLARE_NAPI_FUNCTION("moveAssets", JSMoveAssets),
54 DECLARE_NAPI_FUNCTION("recoverAssets", JSRecoverAssets),
55 DECLARE_NAPI_FUNCTION("deleteAssets", JSDeleteAssets),
56 DECLARE_NAPI_FUNCTION("setAlbumName", JSSetAlbumName),
57 DECLARE_NAPI_FUNCTION("setCoverUri", JSSetCoverUri),
58 DECLARE_NAPI_FUNCTION("placeBefore", JSPlaceBefore),
59 DECLARE_NAPI_FUNCTION("setDisplayLevel", JSSetDisplayLevel),
60 DECLARE_NAPI_FUNCTION("mergeAlbum", JSMergeAlbum),
61 DECLARE_NAPI_FUNCTION("dismissAssets", JSDismissAssets),
62 DECLARE_NAPI_FUNCTION("setIsMe", JSSetIsMe),
63 DECLARE_NAPI_FUNCTION("dismiss", JSDismiss),
64 } };
65 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
66 return exports;
67 }
68
ParsePhotoAlbum(napi_env env,napi_value arg,shared_ptr<PhotoAlbum> & photoAlbum)69 static napi_value ParsePhotoAlbum(napi_env env, napi_value arg, shared_ptr<PhotoAlbum>& photoAlbum)
70 {
71 napi_valuetype valueType;
72 PhotoAlbumNapi* photoAlbumNapi;
73 CHECK_ARGS(env, napi_typeof(env, arg, &valueType), JS_INNER_FAIL);
74 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
75 CHECK_ARGS(env, napi_unwrap(env, arg, reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
76 CHECK_COND_WITH_MESSAGE(env, photoAlbumNapi != nullptr, "Failed to get PhotoAlbumNapi object");
77
78 auto photoAlbumPtr = photoAlbumNapi->GetPhotoAlbumInstance();
79 CHECK_COND_WITH_MESSAGE(env, photoAlbumPtr != nullptr, "photoAlbum is null");
80 CHECK_COND_WITH_MESSAGE(env,
81 photoAlbumPtr->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER &&
82 PhotoAlbum::CheckPhotoAlbumType(photoAlbumPtr->GetPhotoAlbumType()) &&
83 PhotoAlbum::CheckPhotoAlbumSubType(photoAlbumPtr->GetPhotoAlbumSubType()),
84 "Unsupported type of photoAlbum");
85 photoAlbum = photoAlbumPtr;
86 RETURN_NAPI_TRUE(env);
87 }
88
Constructor(napi_env env,napi_callback_info info)89 napi_value MediaAlbumChangeRequestNapi::Constructor(napi_env env, napi_callback_info info)
90 {
91 napi_value newTarget = nullptr;
92 CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
93 CHECK_COND_RET(newTarget != nullptr, nullptr, "Failed to check new.target");
94
95 size_t argc = ARGS_ONE;
96 napi_value argv[ARGS_ONE] = { 0 };
97 napi_value thisVar = nullptr;
98 shared_ptr<PhotoAlbum> photoAlbum = nullptr;
99 CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
100 CHECK_COND_WITH_MESSAGE(env, argc == ARGS_ONE, "Number of args is invalid");
101 CHECK_COND_WITH_MESSAGE(env, ParsePhotoAlbum(env, argv[PARAM0], photoAlbum), "Failed to parse album");
102
103 unique_ptr<MediaAlbumChangeRequestNapi> obj = make_unique<MediaAlbumChangeRequestNapi>();
104 CHECK_COND(env, obj != nullptr, JS_INNER_FAIL);
105 obj->photoAlbum_ = photoAlbum;
106 CHECK_ARGS(env,
107 napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), MediaAlbumChangeRequestNapi::Destructor, nullptr,
108 nullptr),
109 JS_INNER_FAIL);
110 obj.release();
111 return thisVar;
112 }
113
Destructor(napi_env env,void * nativeObject,void * finalizeHint)114 void MediaAlbumChangeRequestNapi::Destructor(napi_env env, void* nativeObject, void* finalizeHint)
115 {
116 auto* albumChangeRequest = reinterpret_cast<MediaAlbumChangeRequestNapi*>(nativeObject);
117 if (albumChangeRequest != nullptr) {
118 delete albumChangeRequest;
119 albumChangeRequest = nullptr;
120 }
121 }
122
GetPhotoAlbumInstance() const123 shared_ptr<PhotoAlbum> MediaAlbumChangeRequestNapi::GetPhotoAlbumInstance() const
124 {
125 return photoAlbum_;
126 }
127
GetReferencePhotoAlbumInstance() const128 shared_ptr<PhotoAlbum> MediaAlbumChangeRequestNapi::GetReferencePhotoAlbumInstance() const
129 {
130 return referencePhotoAlbum_;
131 }
132
GetTargetPhotoAlbumInstance() const133 shared_ptr<PhotoAlbum> MediaAlbumChangeRequestNapi::GetTargetPhotoAlbumInstance() const
134 {
135 return targetAlbum_;
136 }
137
GetAddAssetArray() const138 vector<string> MediaAlbumChangeRequestNapi::GetAddAssetArray() const
139 {
140 return assetsToAdd_;
141 }
142
GetRemoveAssetArray() const143 vector<string> MediaAlbumChangeRequestNapi::GetRemoveAssetArray() const
144 {
145 return assetsToRemove_;
146 }
147
GetRecoverAssetArray() const148 vector<string> MediaAlbumChangeRequestNapi::GetRecoverAssetArray() const
149 {
150 return assetsToRecover_;
151 }
152
GetDeleteAssetArray() const153 vector<string> MediaAlbumChangeRequestNapi::GetDeleteAssetArray() const
154 {
155 return assetsToDelete_;
156 }
157
GetDismissAssetArray() const158 vector<string> MediaAlbumChangeRequestNapi::GetDismissAssetArray() const
159 {
160 return dismissAssets_;
161 }
162
GetMoveMap() const163 map<shared_ptr<PhotoAlbum>, vector<string>, PhotoAlbumPtrCompare> MediaAlbumChangeRequestNapi::GetMoveMap() const
164 {
165 return moveMap_;
166 }
167
RecordMoveAssets(vector<string> & assetArray,shared_ptr<PhotoAlbum> & targetAlbum)168 void MediaAlbumChangeRequestNapi::RecordMoveAssets(vector<string>& assetArray, shared_ptr<PhotoAlbum>& targetAlbum)
169 {
170 if (targetAlbum == nullptr || assetArray.empty()) {
171 return;
172 }
173
174 auto iter = moveMap_.find(targetAlbum);
175 if (iter != moveMap_.end()) {
176 iter->second.insert(iter->second.end(), assetArray.begin(), assetArray.end());
177 } else {
178 moveMap_.insert(make_pair(targetAlbum, assetArray));
179 }
180 }
181
ClearAddAssetArray()182 void MediaAlbumChangeRequestNapi::ClearAddAssetArray()
183 {
184 assetsToAdd_.clear();
185 }
186
ClearRemoveAssetArray()187 void MediaAlbumChangeRequestNapi::ClearRemoveAssetArray()
188 {
189 assetsToRemove_.clear();
190 }
191
ClearRecoverAssetArray()192 void MediaAlbumChangeRequestNapi::ClearRecoverAssetArray()
193 {
194 assetsToRecover_.clear();
195 }
196
ClearDeleteAssetArray()197 void MediaAlbumChangeRequestNapi::ClearDeleteAssetArray()
198 {
199 assetsToDelete_.clear();
200 }
201
ClearDismissAssetArray()202 void MediaAlbumChangeRequestNapi::ClearDismissAssetArray()
203 {
204 dismissAssets_.clear();
205 }
206
ClearMoveMap()207 void MediaAlbumChangeRequestNapi::ClearMoveMap()
208 {
209 moveMap_.clear();
210 }
211
CheckChangeOperations(napi_env env)212 bool MediaAlbumChangeRequestNapi::CheckChangeOperations(napi_env env)
213 {
214 if (albumChangeOperations_.empty()) {
215 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "None request to apply");
216 return false;
217 }
218
219 auto photoAlbum = GetPhotoAlbumInstance();
220 if (photoAlbum == nullptr) {
221 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "photoAlbum is null");
222 return false;
223 }
224
225 if (albumChangeOperations_.front() != AlbumChangeOperation::CREATE_ALBUM && photoAlbum->GetAlbumId() <= 0) {
226 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid album change request");
227 return false;
228 }
229
230 return true;
231 }
232
ParseAssetArray(napi_env env,napi_value arg,vector<string> & uriArray)233 static napi_value ParseAssetArray(napi_env env, napi_value arg, vector<string>& uriArray)
234 {
235 vector<napi_value> napiValues;
236 napi_valuetype valueType = napi_undefined;
237 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, arg, napiValues));
238 CHECK_COND_WITH_MESSAGE(env, !napiValues.empty(), "array is empty");
239 CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_INNER_FAIL);
240 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
241 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uriArray));
242 RETURN_NAPI_TRUE(env);
243 }
244
CheckDuplicatedAssetArray(const vector<string> & arrayToCheck,const vector<string> & currentArray)245 static bool CheckDuplicatedAssetArray(const vector<string>& arrayToCheck, const vector<string>& currentArray)
246 {
247 if (currentArray.empty()) {
248 return true;
249 }
250
251 for (const auto& element : arrayToCheck) {
252 if (std::find(currentArray.begin(), currentArray.end(), element) != currentArray.end()) {
253 return false;
254 }
255 }
256 return true;
257 }
258
JSGetAlbum(napi_env env,napi_callback_info info)259 napi_value MediaAlbumChangeRequestNapi::JSGetAlbum(napi_env env, napi_callback_info info)
260 {
261 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
262 CHECK_ARGS_THROW_INVALID_PARAM(
263 env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_ZERO));
264
265 auto changeRequest = asyncContext->objectInfo;
266 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
267 CHECK_COND(env, photoAlbum != nullptr, JS_INNER_FAIL);
268 if (photoAlbum->GetAlbumId() > 0) {
269 return PhotoAlbumNapi::CreatePhotoAlbumNapi(env, photoAlbum);
270 }
271
272 // PhotoAlbum object has not been actually created, return null.
273 napi_value nullValue;
274 napi_get_null(env, &nullValue);
275 return nullValue;
276 }
277
ParseArgsCreateAlbum(napi_env env,napi_callback_info info,unique_ptr<MediaAlbumChangeRequestAsyncContext> & context)278 static napi_value ParseArgsCreateAlbum(
279 napi_env env, napi_callback_info info, unique_ptr<MediaAlbumChangeRequestAsyncContext>& context)
280 {
281 if (!MediaLibraryNapiUtils::IsSystemApp()) {
282 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
283 return nullptr;
284 }
285
286 CHECK_COND_WITH_MESSAGE(env,
287 MediaLibraryNapiUtils::AsyncContextGetArgs(env, info, context, ARGS_TWO, ARGS_TWO) == napi_ok,
288 "Failed to get args");
289 CHECK_COND(env, MediaAlbumChangeRequestNapi::InitUserFileClient(env, info), JS_INNER_FAIL);
290
291 string albumName;
292 CHECK_COND_WITH_MESSAGE(env,
293 MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM1], albumName) == napi_ok,
294 "Failed to get album name");
295 CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckAlbumName(albumName) == E_OK, "Invalid album name");
296 context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, albumName);
297 RETURN_NAPI_TRUE(env);
298 }
299
JSCreateAlbumRequest(napi_env env,napi_callback_info info)300 napi_value MediaAlbumChangeRequestNapi::JSCreateAlbumRequest(napi_env env, napi_callback_info info)
301 {
302 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
303 CHECK_COND_WITH_MESSAGE(env, ParseArgsCreateAlbum(env, info, asyncContext), "Failed to parse args");
304
305 bool isValid = false;
306 string albumName = asyncContext->valuesBucket.Get(PhotoAlbumColumns::ALBUM_NAME, isValid);
307 auto photoAlbum = make_unique<PhotoAlbum>();
308 photoAlbum->SetAlbumName(albumName);
309 photoAlbum->SetPhotoAlbumType(USER);
310 photoAlbum->SetPhotoAlbumSubType(USER_GENERIC);
311 photoAlbum->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
312 napi_value photoAlbumNapi = PhotoAlbumNapi::CreatePhotoAlbumNapi(env, photoAlbum);
313 CHECK_COND(env, photoAlbumNapi != nullptr, JS_INNER_FAIL);
314
315 napi_value constructor = nullptr;
316 napi_value instance = nullptr;
317 CHECK_ARGS(env, napi_get_reference_value(env, constructor_, &constructor), JS_INNER_FAIL);
318 CHECK_ARGS(env, napi_new_instance(env, constructor, 1, &photoAlbumNapi, &instance), JS_INNER_FAIL);
319 CHECK_COND(env, instance != nullptr, JS_INNER_FAIL);
320
321 MediaAlbumChangeRequestNapi* changeRequest = nullptr;
322 CHECK_ARGS(env, napi_unwrap(env, instance, reinterpret_cast<void**>(&changeRequest)), JS_INNER_FAIL);
323 CHECK_COND(env, changeRequest != nullptr, JS_INNER_FAIL);
324 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::CREATE_ALBUM);
325 return instance;
326 }
327
ParseArgsDeleteAlbums(napi_env env,napi_callback_info info,unique_ptr<MediaAlbumChangeRequestAsyncContext> & context)328 static napi_value ParseArgsDeleteAlbums(
329 napi_env env, napi_callback_info info, unique_ptr<MediaAlbumChangeRequestAsyncContext>& context)
330 {
331 if (!MediaLibraryNapiUtils::IsSystemApp()) {
332 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
333 return nullptr;
334 }
335
336 constexpr size_t minArgs = ARGS_TWO;
337 constexpr size_t maxArgs = ARGS_THREE;
338 CHECK_COND_WITH_MESSAGE(env,
339 MediaLibraryNapiUtils::AsyncContextGetArgs(env, info, context, minArgs, maxArgs) == napi_ok,
340 "Failed to get args");
341 CHECK_COND(env, MediaAlbumChangeRequestNapi::InitUserFileClient(env, info), JS_INNER_FAIL);
342
343 vector<napi_value> napiValues;
344 napi_valuetype valueType = napi_undefined;
345 CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM1], napiValues));
346 CHECK_COND_WITH_MESSAGE(env, !napiValues.empty(), "array is empty");
347 CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_INNER_FAIL);
348 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
349
350 vector<string> deleteIds;
351 for (const auto& napiValue : napiValues) {
352 PhotoAlbumNapi* obj = nullptr;
353 CHECK_ARGS(env, napi_unwrap(env, napiValue, reinterpret_cast<void**>(&obj)), JS_INNER_FAIL);
354 CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "Failed to get album napi object");
355 CHECK_COND_WITH_MESSAGE(env,
356 PhotoAlbum::IsUserPhotoAlbum(obj->GetPhotoAlbumType(), obj->GetPhotoAlbumSubType()),
357 "Only user album can be deleted");
358 deleteIds.push_back(to_string(obj->GetAlbumId()));
359 }
360 context->predicates.In(PhotoAlbumColumns::ALBUM_ID, deleteIds);
361 RETURN_NAPI_TRUE(env);
362 }
363
DeleteAlbumsExecute(napi_env env,void * data)364 static void DeleteAlbumsExecute(napi_env env, void* data)
365 {
366 MediaLibraryTracer tracer;
367 tracer.Start("DeleteAlbumsExecute");
368
369 auto* context = static_cast<MediaAlbumChangeRequestAsyncContext*>(data);
370 Uri deleteAlbumUri(PAH_DELETE_PHOTO_ALBUM);
371 int ret = UserFileClient::Delete(deleteAlbumUri, context->predicates);
372 if (ret < 0) {
373 context->SaveError(ret);
374 NAPI_ERR_LOG("Failed to delete albums, err: %{public}d", ret);
375 return;
376 }
377 NAPI_INFO_LOG("Delete %{public}d album(s)", ret);
378 }
379
DeleteAlbumsCompleteCallback(napi_env env,napi_status status,void * data)380 static void DeleteAlbumsCompleteCallback(napi_env env, napi_status status, void* data)
381 {
382 auto* context = static_cast<MediaAlbumChangeRequestAsyncContext*>(data);
383 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
384 auto jsContext = make_unique<JSAsyncContextOutput>();
385 jsContext->status = false;
386 napi_get_undefined(env, &jsContext->data);
387 napi_get_undefined(env, &jsContext->error);
388 if (context->error == ERR_DEFAULT) {
389 jsContext->status = true;
390 } else {
391 context->HandleError(env, jsContext->error);
392 }
393
394 if (context->work != nullptr) {
395 MediaLibraryNapiUtils::InvokeJSAsyncMethod(
396 env, context->deferred, context->callbackRef, context->work, *jsContext);
397 }
398 delete context;
399 }
400
JSDeleteAlbums(napi_env env,napi_callback_info info)401 napi_value MediaAlbumChangeRequestNapi::JSDeleteAlbums(napi_env env, napi_callback_info info)
402 {
403 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
404 CHECK_COND_WITH_MESSAGE(env, ParseArgsDeleteAlbums(env, info, asyncContext), "Failed to parse args");
405 return MediaLibraryNapiUtils::NapiCreateAsyncWork(
406 env, asyncContext, "ChangeRequestDeleteAlbums", DeleteAlbumsExecute, DeleteAlbumsCompleteCallback);
407 }
408
JSAddAssets(napi_env env,napi_callback_info info)409 napi_value MediaAlbumChangeRequestNapi::JSAddAssets(napi_env env, napi_callback_info info)
410 {
411 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
412 CHECK_COND_WITH_MESSAGE(env,
413 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
414 "Failed to get object info");
415
416 auto changeRequest = asyncContext->objectInfo;
417 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
418 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
419 CHECK_COND_WITH_MESSAGE(env,
420 PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
421 "Only user album can add assets");
422
423 vector<string> assetUriArray;
424 CHECK_COND_WITH_MESSAGE(env, ParseAssetArray(env, asyncContext->argv[PARAM0], assetUriArray),
425 "Failed to parse assets");
426 if (!CheckDuplicatedAssetArray(assetUriArray, changeRequest->assetsToAdd_)) {
427 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT,
428 "The previous addAssets operation has contained the same asset");
429 return nullptr;
430 }
431 changeRequest->assetsToAdd_.insert(changeRequest->assetsToAdd_.end(), assetUriArray.begin(), assetUriArray.end());
432 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::ADD_ASSETS);
433 RETURN_NAPI_UNDEFINED(env);
434 }
435
JSRemoveAssets(napi_env env,napi_callback_info info)436 napi_value MediaAlbumChangeRequestNapi::JSRemoveAssets(napi_env env, napi_callback_info info)
437 {
438 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
439 CHECK_COND_WITH_MESSAGE(env,
440 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
441 "Failed to get object info");
442
443 auto changeRequest = asyncContext->objectInfo;
444 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
445 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
446 CHECK_COND_WITH_MESSAGE(env,
447 PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
448 "Only user album can remove assets");
449
450 vector<string> assetUriArray;
451 CHECK_COND_WITH_MESSAGE(env, ParseAssetArray(env, asyncContext->argv[PARAM0], assetUriArray),
452 "Failed to parse assets");
453 if (!CheckDuplicatedAssetArray(assetUriArray, changeRequest->assetsToRemove_)) {
454 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT,
455 "The previous removeAssets operation has contained the same asset");
456 return nullptr;
457 }
458 changeRequest->assetsToRemove_.insert(
459 changeRequest->assetsToRemove_.end(), assetUriArray.begin(), assetUriArray.end());
460 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::REMOVE_ASSETS);
461 RETURN_NAPI_UNDEFINED(env);
462 }
463
JSMoveAssets(napi_env env,napi_callback_info info)464 napi_value MediaAlbumChangeRequestNapi::JSMoveAssets(napi_env env, napi_callback_info info)
465 {
466 if (!MediaLibraryNapiUtils::IsSystemApp()) {
467 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
468 return nullptr;
469 }
470
471 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
472 CHECK_COND_WITH_MESSAGE(env,
473 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_TWO, ARGS_TWO) == napi_ok,
474 "Failed to get object info");
475
476 auto changeRequest = asyncContext->objectInfo;
477 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
478 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
479
480 shared_ptr<PhotoAlbum> targetAlbum = nullptr;
481 CHECK_COND_WITH_MESSAGE(
482 env, ParsePhotoAlbum(env, asyncContext->argv[PARAM1], targetAlbum), "Failed to parse targetAlbum");
483 CHECK_COND_WITH_MESSAGE(env, targetAlbum->GetAlbumId() != photoAlbum->GetAlbumId(), "targetAlbum cannot be self");
484
485 vector<string> assetUriArray;
486 CHECK_COND_WITH_MESSAGE(env, ParseAssetArray(env, asyncContext->argv[PARAM0], assetUriArray),
487 "Failed to parse assets");
488 auto moveMap = changeRequest->GetMoveMap();
489 for (auto iter = moveMap.begin(); iter != moveMap.end(); iter++) {
490 if (!CheckDuplicatedAssetArray(assetUriArray, iter->second)) {
491 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT,
492 "The previous moveAssets operation has contained the same asset");
493 return nullptr;
494 }
495 }
496 changeRequest->RecordMoveAssets(assetUriArray, targetAlbum);
497 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::MOVE_ASSETS);
498 RETURN_NAPI_UNDEFINED(env);
499 }
500
JSRecoverAssets(napi_env env,napi_callback_info info)501 napi_value MediaAlbumChangeRequestNapi::JSRecoverAssets(napi_env env, napi_callback_info info)
502 {
503 if (!MediaLibraryNapiUtils::IsSystemApp()) {
504 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
505 return nullptr;
506 }
507
508 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
509 CHECK_COND_WITH_MESSAGE(env,
510 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
511 "Failed to get object info");
512
513 auto changeRequest = asyncContext->objectInfo;
514 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
515 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
516 CHECK_COND_WITH_MESSAGE(env,
517 PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
518 "Only trash album can recover assets");
519
520 vector<string> assetUriArray;
521 CHECK_COND_WITH_MESSAGE(env, ParseAssetArray(env, asyncContext->argv[PARAM0], assetUriArray),
522 "Failed to parse assets");
523 if (!CheckDuplicatedAssetArray(assetUriArray, changeRequest->assetsToRecover_)) {
524 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT,
525 "The previous recoverAssets operation has contained the same asset");
526 return nullptr;
527 }
528 changeRequest->assetsToRecover_.insert(
529 changeRequest->assetsToRecover_.end(), assetUriArray.begin(), assetUriArray.end());
530 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::RECOVER_ASSETS);
531 RETURN_NAPI_UNDEFINED(env);
532 }
533
JSDeleteAssets(napi_env env,napi_callback_info info)534 napi_value MediaAlbumChangeRequestNapi::JSDeleteAssets(napi_env env, napi_callback_info info)
535 {
536 if (!MediaLibraryNapiUtils::IsSystemApp()) {
537 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
538 return nullptr;
539 }
540
541 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
542 CHECK_COND_WITH_MESSAGE(env,
543 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
544 "Failed to get object info");
545
546 auto changeRequest = asyncContext->objectInfo;
547 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
548 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
549 CHECK_COND_WITH_MESSAGE(env,
550 PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
551 "Only trash album can delete assets permanently");
552
553 vector<string> assetUriArray;
554 CHECK_COND_WITH_MESSAGE(env, ParseAssetArray(env, asyncContext->argv[PARAM0], assetUriArray),
555 "Failed to parse assets");
556 if (!CheckDuplicatedAssetArray(assetUriArray, changeRequest->assetsToDelete_)) {
557 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT,
558 "The previous deleteAssets operation has contained the same asset");
559 return nullptr;
560 }
561 changeRequest->assetsToDelete_.insert(
562 changeRequest->assetsToDelete_.end(), assetUriArray.begin(), assetUriArray.end());
563 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::DELETE_ASSETS);
564 RETURN_NAPI_UNDEFINED(env);
565 }
566
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)567 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
568 {
569 bool isArray = false;
570 CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
571 if (!isArray) {
572 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array type");
573 return nullptr;
574 }
575
576 uint32_t len = 0;
577 CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
578 if (len <= 0) {
579 NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
580 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array length");
581 return nullptr;
582 }
583
584 for (uint32_t i = 0; i < len; i++) {
585 napi_value asset = nullptr;
586 CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
587 if (asset == nullptr) {
588 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset element");
589 return nullptr;
590 }
591
592 FileAssetNapi *obj = nullptr;
593 CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
594 if (obj == nullptr) {
595 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset napi object");
596 return nullptr;
597 }
598 if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
599 NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
600 continue;
601 }
602 assetsArray.push_back(obj->GetFileUri());
603 }
604
605 napi_value result = nullptr;
606 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
607 return result;
608 }
609
JSSetIsMe(napi_env env,napi_callback_info info)610 napi_value MediaAlbumChangeRequestNapi::JSSetIsMe(napi_env env, napi_callback_info info)
611 {
612 if (!MediaLibraryNapiUtils::IsSystemApp()) {
613 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
614 return nullptr;
615 }
616 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
617 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
618 env, info, asyncContext, ARGS_ZERO, ARGS_ZERO) == napi_ok, "Failed to get object info");
619
620 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
621 CHECK_COND_WITH_MESSAGE(env,
622 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
623 "Only portrait album can set is me");
624 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_IS_ME);
625 napi_value result = nullptr;
626 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
627 return result;
628 }
629
CheckDismissAssetVaild(std::vector<std::string> & dismissAssets,std::vector<std::string> & newAssetArray)630 bool MediaAlbumChangeRequestNapi::CheckDismissAssetVaild(std::vector<std::string> &dismissAssets,
631 std::vector<std::string> &newAssetArray)
632 {
633 if (newAssetArray.empty()) {
634 return false;
635 }
636 unordered_set<string> assetSet(dismissAssets.begin(), dismissAssets.end());
637 unordered_set<string> tempSet;
638 for (const auto& newAsset : newAssetArray) {
639 if (assetSet.find(newAsset) != assetSet.end()) {
640 return false;
641 }
642 tempSet.insert(newAsset);
643 }
644 for (const auto& tmp : tempSet) {
645 dismissAssets.push_back(tmp);
646 }
647 return true;
648 }
649
JSDismissAssets(napi_env env,napi_callback_info info)650 napi_value MediaAlbumChangeRequestNapi::JSDismissAssets(napi_env env, napi_callback_info info)
651 {
652 if (!MediaLibraryNapiUtils::IsSystemApp()) {
653 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
654 return nullptr;
655 }
656 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
657 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
658 env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok, "Failed to get object info");
659
660 vector<std::string> newAssetArray;
661 CHECK_NULLPTR_RET(GetAssetsIdArray(env, asyncContext->argv[PARAM0], newAssetArray));
662 if (!CheckDismissAssetVaild(asyncContext->objectInfo->dismissAssets_, newAssetArray)) {
663 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT, "This dismissAssets is not support");
664 return nullptr;
665 }
666 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
667 auto type = photoAlbum->GetPhotoAlbumType();
668 auto subtype = photoAlbum->GetPhotoAlbumSubType();
669 CHECK_COND_WITH_MESSAGE(env, PhotoAlbum::IsSmartPortraitPhotoAlbum(type, subtype) ||
670 PhotoAlbum::IsSmartGroupPhotoAlbum(type, subtype) || PhotoAlbum::IsSmartClassifyAlbum(type, subtype),
671 "Only portrait, group photo and classify album can dismiss asset");
672
673 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::DISMISS_ASSET);
674 napi_value result = nullptr;
675 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
676 return result;
677 }
678
JSMergeAlbum(napi_env env,napi_callback_info info)679 napi_value MediaAlbumChangeRequestNapi::JSMergeAlbum(napi_env env, napi_callback_info info)
680 {
681 if (!MediaLibraryNapiUtils::IsSystemApp()) {
682 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
683 return nullptr;
684 }
685 napi_valuetype valueType;
686 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
687
688 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
689 env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok, "Failed to get object info");
690 CHECK_ARGS(env, napi_typeof(env, asyncContext->argv[PARAM0], &valueType), JS_INNER_FAIL);
691 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
692 if (valueType == napi_object) {
693 PhotoAlbumNapi* photoAlbumNapi;
694 CHECK_ARGS(env, napi_unwrap(env, asyncContext->argv[PARAM0],
695 reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
696 CHECK_COND_WITH_MESSAGE(env, photoAlbumNapi != nullptr, "Failed to get PhotoAlbumNapi object");
697 asyncContext->objectInfo->targetAlbum_ = photoAlbumNapi->GetPhotoAlbumInstance();
698 }
699 auto photoAlbum = asyncContext->objectInfo->photoAlbum_;
700 auto targetAlbum = asyncContext->objectInfo->targetAlbum_;
701 CHECK_COND_WITH_MESSAGE(env,
702 (photoAlbum != nullptr) && (targetAlbum != nullptr), "PhotoAlbum Or TargetAlbum is nullptr");
703 CHECK_COND_WITH_MESSAGE(env,
704 (PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) &&
705 (PhotoAlbum::IsSmartPortraitPhotoAlbum(targetAlbum->GetPhotoAlbumType(), targetAlbum->GetPhotoAlbumSubType())),
706 "Only portrait album can merge");
707 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::MERGE_ALBUM);
708 napi_value result = nullptr;
709 CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
710 return result;
711 }
712
JSSetDisplayLevel(napi_env env,napi_callback_info info)713 napi_value MediaAlbumChangeRequestNapi::JSSetDisplayLevel(napi_env env, napi_callback_info info)
714 {
715 if (!MediaLibraryNapiUtils::IsSystemApp()) {
716 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
717 return nullptr;
718 }
719 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
720 int32_t displayLevel;
721 CHECK_COND_WITH_MESSAGE(env,
722 MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, displayLevel) == napi_ok,
723 "Failed to parse args");
724 CHECK_COND_WITH_MESSAGE(env, asyncContext->argc == ARGS_ONE, "Number of args is invalid");
725 CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckDisplayLevel(displayLevel), "Invalid display level");
726
727 auto photoAlbum = asyncContext->objectInfo->photoAlbum_;
728 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "PhotoAlbum is nullptr");
729 CHECK_COND_WITH_MESSAGE(env,
730 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
731 "Only portrait album can set album display level");
732 photoAlbum->SetDisplayLevel(displayLevel);
733 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_DISPLAY_LEVEL);
734
735 napi_value result = nullptr;
736 CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
737 return result;
738 }
739
JSDismiss(napi_env env,napi_callback_info info)740 napi_value MediaAlbumChangeRequestNapi::JSDismiss(napi_env env, napi_callback_info info)
741 {
742 if (!MediaLibraryNapiUtils::IsSystemApp()) {
743 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
744 return nullptr;
745 }
746 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
747 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
748 env, info, asyncContext, ARGS_ZERO, ARGS_ZERO) == napi_ok, "Failed to get object info");
749
750 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
751 CHECK_COND_WITH_MESSAGE(env,
752 PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
753 "Only group photo can be dismissed");
754 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::DISMISS);
755 napi_value result = nullptr;
756 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
757 return result;
758 }
759
JSSetAlbumName(napi_env env,napi_callback_info info)760 napi_value MediaAlbumChangeRequestNapi::JSSetAlbumName(napi_env env, napi_callback_info info)
761 {
762 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
763 string albumName;
764 CHECK_COND_WITH_MESSAGE(env,
765 MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, albumName) == napi_ok,
766 "Failed to parse args");
767 CHECK_COND_WITH_MESSAGE(env, asyncContext->argc == ARGS_ONE, "Number of args is invalid");
768 CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckAlbumName(albumName) == E_OK, "Invalid album name");
769
770 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
771 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
772 CHECK_COND_WITH_MESSAGE(env,
773 PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
774 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
775 PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
776 "Only user album, smart portrait album and group photo can set album name");
777 photoAlbum->SetAlbumName(albumName);
778 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_ALBUM_NAME);
779 RETURN_NAPI_UNDEFINED(env);
780 }
781
JSSetCoverUri(napi_env env,napi_callback_info info)782 napi_value MediaAlbumChangeRequestNapi::JSSetCoverUri(napi_env env, napi_callback_info info)
783 {
784 if (!MediaLibraryNapiUtils::IsSystemApp()) {
785 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
786 return nullptr;
787 }
788
789 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
790 string coverUri;
791 CHECK_COND_WITH_MESSAGE(env,
792 MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, coverUri) == napi_ok,
793 "Failed to parse args");
794 CHECK_COND_WITH_MESSAGE(env, asyncContext->argc == ARGS_ONE, "Number of args is invalid");
795
796 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
797 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
798 CHECK_COND_WITH_MESSAGE(env,
799 PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
800 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
801 PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
802 "Only user album, smart portrait album and group photo can set album name");
803 photoAlbum->SetCoverUri(coverUri);
804 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_COVER_URI);
805 RETURN_NAPI_UNDEFINED(env);
806 }
807
JSPlaceBefore(napi_env env,napi_callback_info info)808 napi_value MediaAlbumChangeRequestNapi::JSPlaceBefore(napi_env env, napi_callback_info info)
809 {
810 if (!MediaLibraryNapiUtils::IsSystemApp()) {
811 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
812 return nullptr;
813 }
814 napi_valuetype valueType;
815 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
816
817 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
818 env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok, "Failed to get object info");
819 CHECK_ARGS(env, napi_typeof(env, asyncContext->argv[PARAM0], &valueType), JS_INNER_FAIL);
820 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object || valueType == napi_null, "Invalid argument type");
821 if (valueType == napi_object) {
822 PhotoAlbumNapi* photoAlbumNapi;
823 CHECK_ARGS(env, napi_unwrap(env, asyncContext->argv[PARAM0],
824 reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
825 CHECK_COND_WITH_MESSAGE(env, photoAlbumNapi != nullptr, "Failed to get PhotoAlbumNapi object");
826 asyncContext->objectInfo->referencePhotoAlbum_ = photoAlbumNapi->GetPhotoAlbumInstance();
827 }
828 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::ORDER_ALBUM);
829 RETURN_NAPI_UNDEFINED(env);
830 }
831
CreateAlbumExecute(MediaAlbumChangeRequestAsyncContext & context)832 static bool CreateAlbumExecute(MediaAlbumChangeRequestAsyncContext& context)
833 {
834 MediaLibraryTracer tracer;
835 tracer.Start("CreateAlbumExecute");
836
837 auto changeRequest = context.objectInfo;
838 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
839
840 Uri createAlbumUri(PAH_CREATE_PHOTO_ALBUM);
841 DataShare::DataShareValuesBucket valuesBucket;
842 valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, photoAlbum->GetAlbumName());
843 int32_t ret = UserFileClient::Insert(createAlbumUri, valuesBucket);
844 if (ret == -1) {
845 context.SaveError(-EEXIST);
846 NAPI_ERR_LOG("Album exists");
847 return false;
848 }
849 if (ret < 0) {
850 context.SaveError(ret);
851 NAPI_ERR_LOG("Failed to create album, ret: %{public}d", ret);
852 return false;
853 }
854
855 photoAlbum->SetAlbumId(ret);
856 photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(ret));
857 return true;
858 }
859
FetchNewCount(MediaAlbumChangeRequestAsyncContext & context,shared_ptr<PhotoAlbum> & album)860 static bool FetchNewCount(MediaAlbumChangeRequestAsyncContext& context, shared_ptr<PhotoAlbum>& album)
861 {
862 if (album == nullptr) {
863 NAPI_ERR_LOG("Album is null");
864 context.SaveError(E_FAIL);
865 return false;
866 }
867
868 Uri queryUri(PAH_QUERY_PHOTO_ALBUM);
869 DataShare::DataSharePredicates predicates;
870 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, album->GetAlbumId());
871 vector<string> fetchColumns = { PhotoAlbumColumns::ALBUM_ID, PhotoAlbumColumns::ALBUM_COUNT,
872 PhotoAlbumColumns::ALBUM_IMAGE_COUNT, PhotoAlbumColumns::ALBUM_VIDEO_COUNT };
873 int errCode = 0;
874 auto resultSet = UserFileClient::Query(queryUri, predicates, fetchColumns, errCode);
875 if (resultSet == nullptr) {
876 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
877 context.SaveError(E_HAS_DB_ERROR);
878 return false;
879 }
880 if (resultSet->GoToFirstRow() != 0) {
881 NAPI_ERR_LOG("go to first row failed when fetch new count");
882 context.SaveError(E_HAS_DB_ERROR);
883 return false;
884 }
885
886 bool hiddenOnly = album->GetHiddenOnly();
887 int imageCount = hiddenOnly ? -1 :
888 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT, resultSet, TYPE_INT32));
889 int videoCount = hiddenOnly ? -1 :
890 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT, resultSet, TYPE_INT32));
891 album->SetCount(
892 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_COUNT, resultSet, TYPE_INT32)));
893 album->SetImageCount(imageCount);
894 album->SetVideoCount(videoCount);
895 return true;
896 }
897
AddAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)898 static bool AddAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
899 {
900 MediaLibraryTracer tracer;
901 tracer.Start("AddAssetsExecute");
902
903 auto changeRequest = context.objectInfo;
904 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
905 int32_t albumId = photoAlbum->GetAlbumId();
906 vector<DataShare::DataShareValuesBucket> valuesBuckets;
907 for (const auto& asset : changeRequest->GetAddAssetArray()) {
908 DataShare::DataShareValuesBucket pair;
909 pair.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
910 pair.Put(PhotoColumn::MEDIA_ID, asset);
911 valuesBuckets.push_back(pair);
912 }
913
914 Uri addAssetsUri(PAH_PHOTO_ALBUM_ADD_ASSET);
915 int ret = UserFileClient::BatchInsert(addAssetsUri, valuesBuckets);
916 changeRequest->ClearAddAssetArray();
917 if (ret < 0) {
918 context.SaveError(ret);
919 NAPI_ERR_LOG("Failed to add assets into album %{public}d, err: %{public}d", albumId, ret);
920 return false;
921 }
922
923 NAPI_INFO_LOG("Add %{public}d asset(s) into album %{public}d", ret, albumId);
924 FetchNewCount(context, photoAlbum);
925 return true;
926 }
927
RemoveAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)928 static bool RemoveAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
929 {
930 MediaLibraryTracer tracer;
931 tracer.Start("RemoveAssetsExecute");
932
933 auto changeRequest = context.objectInfo;
934 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
935 int32_t albumId = photoAlbum->GetAlbumId();
936 DataShare::DataSharePredicates predicates;
937 predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(albumId));
938 predicates.And()->In(PhotoColumn::MEDIA_ID, changeRequest->GetRemoveAssetArray());
939
940 Uri removeAssetsUri(PAH_PHOTO_ALBUM_REMOVE_ASSET);
941 int ret = UserFileClient::Delete(removeAssetsUri, predicates);
942 changeRequest->ClearRemoveAssetArray();
943 if (ret < 0) {
944 context.SaveError(ret);
945 NAPI_ERR_LOG("Failed to remove assets from album %{public}d, err: %{public}d", albumId, ret);
946 return false;
947 }
948
949 NAPI_INFO_LOG("Remove %{public}d asset(s) from album %{public}d", ret, albumId);
950 FetchNewCount(context, photoAlbum);
951 return true;
952 }
953
MoveAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)954 static bool MoveAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
955 {
956 MediaLibraryTracer tracer;
957 tracer.Start("MoveAssetsExecute");
958
959 auto changeRequest = context.objectInfo;
960 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
961 int32_t albumId = photoAlbum->GetAlbumId();
962 auto moveMap = changeRequest->GetMoveMap();
963 changeRequest->ClearMoveMap();
964
965 for (auto iter = moveMap.begin(); iter != moveMap.end(); iter++) {
966 auto targetPhotoAlbum = iter->first;
967 int32_t targetAlbumId = targetPhotoAlbum->GetAlbumId();
968 vector<string> moveAssetArray = iter->second;
969 // Move into target album.
970 DataShare::DataSharePredicates predicates;
971 predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(albumId));
972 predicates.And()->In(PhotoColumn::MEDIA_ID, moveAssetArray);
973
974 DataShare::DataShareValuesBucket valuesBuckets;
975 valuesBuckets.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, targetAlbumId);
976 string uri = PAH_BATCH_UPDATE_OWNER_ALBUM_ID;
977 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
978 Uri moveAssetsUri(uri);
979 int ret = UserFileClient::Update(moveAssetsUri, predicates, valuesBuckets);
980 if (ret < 0) {
981 context.SaveError(ret);
982 NAPI_ERR_LOG("Failed to move assets into album %{public}d, err: %{public}d", targetAlbumId, ret);
983 return false;
984 }
985 NAPI_INFO_LOG("Move %{public}d asset(s) into album %{public}d", ret, targetAlbumId);
986 FetchNewCount(context, targetPhotoAlbum);
987 }
988 FetchNewCount(context, photoAlbum);
989 return true;
990 }
991
RecoverAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)992 static bool RecoverAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
993 {
994 MediaLibraryTracer tracer;
995 tracer.Start("RecoverAssetsExecute");
996
997 DataShare::DataSharePredicates predicates;
998 DataShare::DataShareValuesBucket valuesBucket;
999 predicates.In(PhotoColumn::MEDIA_ID, context.objectInfo->GetRecoverAssetArray());
1000 valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, 0);
1001
1002 Uri recoverAssetsUri(PAH_RECOVER_PHOTOS);
1003 int ret = UserFileClient::Update(recoverAssetsUri, predicates, valuesBucket);
1004 context.objectInfo->ClearRecoverAssetArray();
1005 if (ret < 0) {
1006 context.SaveError(ret);
1007 NAPI_ERR_LOG("Failed to recover assets, err: %{public}d", ret);
1008 return false;
1009 }
1010
1011 NAPI_INFO_LOG("Recover %{public}d assets from trash album", ret);
1012 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1013 int32_t currentCount = photoAlbum->GetCount() - ret;
1014 photoAlbum->SetCount(currentCount > 0 ? currentCount : 0);
1015 return true;
1016 }
1017
DeleteAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)1018 static bool DeleteAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
1019 {
1020 MediaLibraryTracer tracer;
1021 tracer.Start("DeleteAssetsExecute");
1022
1023 DataShare::DataSharePredicates predicates;
1024 predicates.In(PhotoColumn::MEDIA_ID, context.objectInfo->GetDeleteAssetArray());
1025 DataShare::DataShareValuesBucket valuesBucket;
1026 valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, 0);
1027
1028 Uri deleteAssetsUri(PAH_DELETE_PHOTOS);
1029 int ret = UserFileClient::Update(deleteAssetsUri, predicates, valuesBucket);
1030 context.objectInfo->ClearDeleteAssetArray();
1031 if (ret < 0) {
1032 context.SaveError(ret);
1033 NAPI_ERR_LOG("Failed to delete assets from trash album permanently, err: %{public}d", ret);
1034 return false;
1035 }
1036
1037 NAPI_INFO_LOG("Delete %{public}d assets permanently from trash album", ret);
1038 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1039 int32_t currentCount = photoAlbum->GetCount() - ret;
1040 photoAlbum->SetCount(currentCount > 0 ? currentCount : 0);
1041 return true;
1042 }
1043
OrderAlbumExecute(MediaAlbumChangeRequestAsyncContext & context)1044 static bool OrderAlbumExecute(MediaAlbumChangeRequestAsyncContext& context)
1045 {
1046 MediaLibraryTracer tracer;
1047 tracer.Start("OrderAlbumExecute");
1048
1049 DataShare::DataSharePredicates predicates;
1050 DataShare::DataShareValuesBucket valuesBucket;
1051 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1052 auto referenceAlum = context.objectInfo->GetReferencePhotoAlbumInstance();
1053 Uri updateAlbumUri(PAH_ORDER_ALBUM);
1054 valuesBucket.Put(PhotoAlbumColumns::ALBUM_ID, photoAlbum->GetAlbumId());
1055 int32_t referenceAlbumId = -1;
1056 if (referenceAlum != nullptr) {
1057 referenceAlbumId = referenceAlum->GetAlbumId();
1058 }
1059 valuesBucket.Put(PhotoAlbumColumns::REFERENCE_ALBUM_ID, referenceAlbumId);
1060 valuesBucket.Put(PhotoAlbumColumns::ALBUM_TYPE, photoAlbum->GetPhotoAlbumType());
1061 valuesBucket.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbum->GetPhotoAlbumSubType());
1062 int32_t result = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
1063 if (result < 0) {
1064 context.SaveError(result);
1065 NAPI_ERR_LOG("Failed to order albums err: %{public}d", result);
1066 return false;
1067 }
1068 return true;
1069 }
1070
UpdateTabAnalysisImageFace(std::shared_ptr<PhotoAlbum> & photoAlbum,MediaAlbumChangeRequestAsyncContext & context)1071 static void UpdateTabAnalysisImageFace(std::shared_ptr<PhotoAlbum>& photoAlbum,
1072 MediaAlbumChangeRequestAsyncContext& context)
1073 {
1074 if (photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::PORTRAIT) {
1075 return;
1076 }
1077
1078 std::string updateUri = PAH_UPDATE_ANA_FACE;
1079 MediaLibraryNapiUtils::UriAppendKeyValue(updateUri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1080 MediaLibraryNapiUtils::UriAppendKeyValue(updateUri, MEDIA_OPERN_KEYWORD, UPDATE_DISMISS_ASSET);
1081 Uri updateFaceUri(updateUri);
1082
1083 DataShare::DataShareValuesBucket updateValues;
1084 updateValues.Put(MediaAlbumChangeRequestNapi::TAG_ID,
1085 std::to_string(MediaAlbumChangeRequestNapi::PORTRAIT_REMOVED));
1086
1087 DataShare::DataSharePredicates updatePredicates;
1088 std::vector<std::string> dismissAssetArray = context.objectInfo->GetDismissAssetArray();
1089 std::string selection = std::to_string(photoAlbum->GetAlbumId());
1090 for (size_t i = 0; i < dismissAssetArray.size(); ++i) {
1091 selection += "," + dismissAssetArray[i];
1092 }
1093 updatePredicates.SetWhereClause(selection);
1094 int updatedRows = UserFileClient::Update(updateFaceUri, updatePredicates, updateValues);
1095 if (updatedRows <= 0) {
1096 NAPI_WARN_LOG("Failed to update tab_analysis_image_face, err: %{public}d", updatedRows);
1097 }
1098 }
1099
DismissAssetExecute(MediaAlbumChangeRequestAsyncContext & context)1100 static bool DismissAssetExecute(MediaAlbumChangeRequestAsyncContext& context)
1101 {
1102 MediaLibraryTracer tracer;
1103 tracer.Start("DismissAssetExecute");
1104
1105 string disMissAssetAssetsUri = PAH_DISMISS_ASSET;
1106 Uri uri(disMissAssetAssetsUri);
1107
1108 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1109 DataShare::DataSharePredicates predicates;
1110 predicates.EqualTo(MAP_ALBUM, to_string(photoAlbum->GetAlbumId()));
1111 predicates.And()->In(MAP_ASSET, context.objectInfo->GetDismissAssetArray());
1112 predicates.And()->EqualTo(ALBUM_SUBTYPE, to_string(photoAlbum->GetPhotoAlbumSubType()));
1113
1114 auto deletedRows = UserFileClient::Delete(uri, predicates);
1115 if (deletedRows < 0) {
1116 context.SaveError(deletedRows);
1117 NAPI_ERR_LOG("Failed to dismiss asset err: %{public}d", deletedRows);
1118 return false;
1119 }
1120
1121 /* 只针对人像相册更新 tab_analysis_image_face 表 */
1122 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
1123 UpdateTabAnalysisImageFace(photoAlbum, context);
1124 }
1125
1126 context.objectInfo->ClearDismissAssetArray();
1127 return true;
1128 }
1129
MergeAlbumExecute(MediaAlbumChangeRequestAsyncContext & context)1130 static bool MergeAlbumExecute(MediaAlbumChangeRequestAsyncContext& context)
1131 {
1132 MediaLibraryTracer tracer;
1133 tracer.Start("MergeAlbumExecute");
1134
1135 DataShare::DataSharePredicates predicates;
1136 DataShare::DataShareValuesBucket valuesBucket;
1137 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1138 auto targetAlum = context.objectInfo->GetTargetPhotoAlbumInstance();
1139 Uri updateAlbumUri(PAH_PORTRAIT_MERGE_ALBUM);
1140 valuesBucket.Put(ALBUM_ID, photoAlbum->GetAlbumId());
1141 int32_t targetAlbumId = -1;
1142 if (targetAlum != nullptr) {
1143 targetAlbumId = targetAlum->GetAlbumId();
1144 }
1145 valuesBucket.Put(TARGET_ALBUM_ID, targetAlbumId);
1146 int32_t result = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
1147 if (result < 0) {
1148 context.SaveError(result);
1149 NAPI_ERR_LOG("Failed to merge albums err: %{public}d", result);
1150 return false;
1151 }
1152 return true;
1153 }
1154
GetAlbumUpdateValue(shared_ptr<PhotoAlbum> & photoAlbum,const AlbumChangeOperation changeOperation,string & uri,DataShare::DataShareValuesBucket & valuesBucket,string & property)1155 static bool GetAlbumUpdateValue(shared_ptr<PhotoAlbum>& photoAlbum, const AlbumChangeOperation changeOperation,
1156 string& uri, DataShare::DataShareValuesBucket& valuesBucket, string& property)
1157 {
1158 if (photoAlbum == nullptr) {
1159 NAPI_ERR_LOG("photoAlbum is null");
1160 return false;
1161 }
1162
1163 switch (changeOperation) {
1164 case AlbumChangeOperation::SET_ALBUM_NAME:
1165 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
1166 uri = PAH_PORTRAIT_ANAALBUM_ALBUM_NAME;
1167 } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
1168 uri = PAH_GROUP_ANAALBUM_ALBUM_NAME;
1169 } else {
1170 uri = PAH_SET_PHOTO_ALBUM_NAME;
1171 }
1172 property = PhotoAlbumColumns::ALBUM_NAME;
1173 valuesBucket.Put(property, photoAlbum->GetAlbumName());
1174 break;
1175 case AlbumChangeOperation::SET_COVER_URI:
1176 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
1177 uri = PAH_PORTRAIT_ANAALBUM_COVER_URI;
1178 } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
1179 uri = PAH_GROUP_ANAALBUM_COVER_URI;
1180 } else {
1181 uri = PAH_UPDATE_PHOTO_ALBUM;
1182 }
1183 property = PhotoAlbumColumns::ALBUM_COVER_URI;
1184 valuesBucket.Put(property, photoAlbum->GetCoverUri());
1185 break;
1186 case AlbumChangeOperation::SET_DISPLAY_LEVEL:
1187 uri = PAH_PORTRAIT_DISPLAY_LEVLE;
1188 property = USER_DISPLAY_LEVEL;
1189 valuesBucket.Put(property, photoAlbum->GetDisplayLevel());
1190 break;
1191 case AlbumChangeOperation::SET_IS_ME:
1192 uri = PAH_PORTRAIT_IS_ME;
1193 property = IS_ME;
1194 valuesBucket.Put(property, 1);
1195 break;
1196 case AlbumChangeOperation::DISMISS:
1197 uri = PAH_GROUP_ANAALBUM_DISMISS;
1198 property = IS_REMOVED;
1199 valuesBucket.Put(property, 1);
1200 break;
1201 default:
1202 return false;
1203 }
1204 return true;
1205 }
1206
SetAlbumPropertyExecute(MediaAlbumChangeRequestAsyncContext & context,const AlbumChangeOperation changeOperation)1207 static bool SetAlbumPropertyExecute(
1208 MediaAlbumChangeRequestAsyncContext& context, const AlbumChangeOperation changeOperation)
1209 {
1210 MediaLibraryTracer tracer;
1211 tracer.Start("SetAlbumPropertyExecute");
1212
1213 // In the scenario of creation, the new name will be applied when the album is created.
1214 if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME &&
1215 context.albumChangeOperations.front() == AlbumChangeOperation::CREATE_ALBUM) {
1216 return true;
1217 }
1218
1219 DataShare::DataSharePredicates predicates;
1220 DataShare::DataShareValuesBucket valuesBucket;
1221 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1222 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
1223 string uri;
1224 string property;
1225 if (!GetAlbumUpdateValue(photoAlbum, changeOperation, uri, valuesBucket, property)) {
1226 context.SaveError(E_FAIL);
1227 NAPI_ERR_LOG("Failed to parse album change operation: %{public}d", changeOperation);
1228 return false;
1229 }
1230 valuesBucket.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbum->GetPhotoAlbumSubType());
1231 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1232 Uri updateAlbumUri(uri);
1233 int32_t changedRows = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
1234 if (changedRows < 0) {
1235 context.SaveError(changedRows);
1236 NAPI_ERR_LOG("Failed to set %{public}s, err: %{public}d", property.c_str(), changedRows);
1237 return false;
1238 }
1239 return true;
1240 }
1241
1242 static const unordered_map<AlbumChangeOperation, bool (*)(MediaAlbumChangeRequestAsyncContext&)> EXECUTE_MAP = {
1243 { AlbumChangeOperation::CREATE_ALBUM, CreateAlbumExecute },
1244 { AlbumChangeOperation::ADD_ASSETS, AddAssetsExecute },
1245 { AlbumChangeOperation::REMOVE_ASSETS, RemoveAssetsExecute },
1246 { AlbumChangeOperation::MOVE_ASSETS, MoveAssetsExecute },
1247 { AlbumChangeOperation::RECOVER_ASSETS, RecoverAssetsExecute },
1248 { AlbumChangeOperation::DELETE_ASSETS, DeleteAssetsExecute },
1249 { AlbumChangeOperation::ORDER_ALBUM, OrderAlbumExecute },
1250 { AlbumChangeOperation::MERGE_ALBUM, MergeAlbumExecute },
1251 { AlbumChangeOperation::DISMISS_ASSET, DismissAssetExecute },
1252 };
1253
ApplyAlbumChangeRequestExecute(napi_env env,void * data)1254 static void ApplyAlbumChangeRequestExecute(napi_env env, void* data)
1255 {
1256 MediaLibraryTracer tracer;
1257 tracer.Start("ApplyAlbumChangeRequestExecute");
1258
1259 auto* context = static_cast<MediaAlbumChangeRequestAsyncContext*>(data);
1260 unordered_set<AlbumChangeOperation> appliedOperations;
1261 for (const auto& changeOperation : context->albumChangeOperations) {
1262 // Keep the final result(s) of each operation, and commit only once.
1263 if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
1264 continue;
1265 }
1266
1267 bool valid = false;
1268 auto iter = EXECUTE_MAP.find(changeOperation);
1269 if (iter != EXECUTE_MAP.end()) {
1270 valid = iter->second(*context);
1271 } else if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME ||
1272 changeOperation == AlbumChangeOperation::SET_COVER_URI ||
1273 changeOperation == AlbumChangeOperation::SET_IS_ME ||
1274 changeOperation == AlbumChangeOperation::SET_DISPLAY_LEVEL ||
1275 changeOperation == AlbumChangeOperation::DISMISS) {
1276 valid = SetAlbumPropertyExecute(*context, changeOperation);
1277 } else {
1278 NAPI_ERR_LOG("Invalid album change operation: %{public}d", changeOperation);
1279 context->error = OHOS_INVALID_PARAM_CODE;
1280 return;
1281 }
1282
1283 if (!valid) {
1284 NAPI_ERR_LOG("Failed to apply album change request, operation: %{public}d", changeOperation);
1285 return;
1286 }
1287 appliedOperations.insert(changeOperation);
1288 }
1289 }
1290
ApplyAlbumChangeRequestCompleteCallback(napi_env env,napi_status status,void * data)1291 static void ApplyAlbumChangeRequestCompleteCallback(napi_env env, napi_status status, void* data)
1292 {
1293 MediaLibraryTracer tracer;
1294 tracer.Start("ApplyAlbumChangeRequestCompleteCallback");
1295
1296 auto* context = static_cast<MediaAlbumChangeRequestAsyncContext*>(data);
1297 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1298 auto jsContext = make_unique<JSAsyncContextOutput>();
1299 jsContext->status = false;
1300 napi_get_undefined(env, &jsContext->data);
1301 napi_get_undefined(env, &jsContext->error);
1302 if (context->error == ERR_DEFAULT) {
1303 jsContext->status = true;
1304 } else {
1305 context->HandleError(env, jsContext->error);
1306 }
1307
1308 if (context->work != nullptr) {
1309 MediaLibraryNapiUtils::InvokeJSAsyncMethod(
1310 env, context->deferred, context->callbackRef, context->work, *jsContext);
1311 }
1312 delete context;
1313 }
1314
CheckPortraitMergeAlbum()1315 bool MediaAlbumChangeRequestNapi::CheckPortraitMergeAlbum()
1316 {
1317 bool hasMergeAlbum = false;
1318 bool hasAlbumName = false;
1319 for (auto operation : albumChangeOperations_) {
1320 if (operation == AlbumChangeOperation::MERGE_ALBUM) {
1321 hasMergeAlbum = true;
1322 }
1323 if (operation == AlbumChangeOperation::SET_ALBUM_NAME) {
1324 hasAlbumName = true;
1325 }
1326 }
1327 return (hasAlbumName && hasMergeAlbum) || (hasMergeAlbum == false);
1328 }
1329
ApplyChanges(napi_env env,napi_callback_info info)1330 napi_value MediaAlbumChangeRequestNapi::ApplyChanges(napi_env env, napi_callback_info info)
1331 {
1332 constexpr size_t minArgs = ARGS_ONE;
1333 constexpr size_t maxArgs = ARGS_TWO;
1334 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
1335 CHECK_COND_WITH_MESSAGE(env,
1336 MediaLibraryNapiUtils::AsyncContextGetArgs(env, info, asyncContext, minArgs, maxArgs) == napi_ok,
1337 "Failed to get args");
1338 asyncContext->objectInfo = this;
1339 CHECK_COND_WITH_MESSAGE(env, CheckChangeOperations(env), "Failed to check album change request operations");
1340 asyncContext->albumChangeOperations = albumChangeOperations_;
1341 albumChangeOperations_.clear();
1342 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "ApplyMediaAlbumChangeRequest",
1343 ApplyAlbumChangeRequestExecute, ApplyAlbumChangeRequestCompleteCallback);
1344 }
1345 } // namespace OHOS::Media