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 NAPI_INFO_LOG("enter");
537 if (!MediaLibraryNapiUtils::IsSystemApp()) {
538 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
539 return nullptr;
540 }
541
542 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
543 CHECK_COND_WITH_MESSAGE(env,
544 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
545 "Failed to get object info");
546
547 auto changeRequest = asyncContext->objectInfo;
548 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
549 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
550 CHECK_COND_WITH_MESSAGE(env,
551 PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
552 "Only trash album can delete assets permanently");
553
554 vector<string> assetUriArray;
555 CHECK_COND_WITH_MESSAGE(env, ParseAssetArray(env, asyncContext->argv[PARAM0], assetUriArray),
556 "Failed to parse assets");
557 if (!CheckDuplicatedAssetArray(assetUriArray, changeRequest->assetsToDelete_)) {
558 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT,
559 "The previous deleteAssets operation has contained the same asset");
560 return nullptr;
561 }
562 changeRequest->assetsToDelete_.insert(
563 changeRequest->assetsToDelete_.end(), assetUriArray.begin(), assetUriArray.end());
564 changeRequest->albumChangeOperations_.push_back(AlbumChangeOperation::DELETE_ASSETS);
565 RETURN_NAPI_UNDEFINED(env);
566 }
567
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)568 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
569 {
570 bool isArray = false;
571 CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
572 if (!isArray) {
573 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array type");
574 return nullptr;
575 }
576
577 uint32_t len = 0;
578 CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
579 if (len <= 0) {
580 NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
581 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to check array length");
582 return nullptr;
583 }
584
585 for (uint32_t i = 0; i < len; i++) {
586 napi_value asset = nullptr;
587 CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
588 if (asset == nullptr) {
589 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset element");
590 return nullptr;
591 }
592
593 FileAssetNapi *obj = nullptr;
594 CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
595 if (obj == nullptr) {
596 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Failed to get asset napi object");
597 return nullptr;
598 }
599 if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
600 NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
601 continue;
602 }
603 assetsArray.push_back(obj->GetFileUri());
604 }
605
606 napi_value result = nullptr;
607 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
608 return result;
609 }
610
JSSetIsMe(napi_env env,napi_callback_info info)611 napi_value MediaAlbumChangeRequestNapi::JSSetIsMe(napi_env env, napi_callback_info info)
612 {
613 if (!MediaLibraryNapiUtils::IsSystemApp()) {
614 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
615 return nullptr;
616 }
617 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
618 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
619 env, info, asyncContext, ARGS_ZERO, ARGS_ZERO) == napi_ok, "Failed to get object info");
620
621 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
622 CHECK_COND_WITH_MESSAGE(env,
623 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
624 "Only portrait album can set is me");
625 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_IS_ME);
626 napi_value result = nullptr;
627 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
628 return result;
629 }
630
CheckDismissAssetVaild(std::vector<std::string> & dismissAssets,std::vector<std::string> & newAssetArray)631 bool MediaAlbumChangeRequestNapi::CheckDismissAssetVaild(std::vector<std::string> &dismissAssets,
632 std::vector<std::string> &newAssetArray)
633 {
634 if (newAssetArray.empty()) {
635 return false;
636 }
637 unordered_set<string> assetSet(dismissAssets.begin(), dismissAssets.end());
638 unordered_set<string> tempSet;
639 for (const auto& newAsset : newAssetArray) {
640 if (assetSet.find(newAsset) != assetSet.end()) {
641 return false;
642 }
643 tempSet.insert(newAsset);
644 }
645 for (const auto& tmp : tempSet) {
646 dismissAssets.push_back(tmp);
647 }
648 return true;
649 }
650
JSDismissAssets(napi_env env,napi_callback_info info)651 napi_value MediaAlbumChangeRequestNapi::JSDismissAssets(napi_env env, napi_callback_info info)
652 {
653 if (!MediaLibraryNapiUtils::IsSystemApp()) {
654 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
655 return nullptr;
656 }
657 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
658 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
659 env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok, "Failed to get object info");
660
661 vector<std::string> newAssetArray;
662 CHECK_NULLPTR_RET(GetAssetsIdArray(env, asyncContext->argv[PARAM0], newAssetArray));
663 if (!CheckDismissAssetVaild(asyncContext->objectInfo->dismissAssets_, newAssetArray)) {
664 NapiError::ThrowError(env, JS_E_OPERATION_NOT_SUPPORT, "This dismissAssets is not support");
665 return nullptr;
666 }
667 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
668 auto type = photoAlbum->GetPhotoAlbumType();
669 auto subtype = photoAlbum->GetPhotoAlbumSubType();
670 CHECK_COND_WITH_MESSAGE(env, PhotoAlbum::IsSmartPortraitPhotoAlbum(type, subtype) ||
671 PhotoAlbum::IsSmartGroupPhotoAlbum(type, subtype) || PhotoAlbum::IsSmartClassifyAlbum(type, subtype),
672 "Only portrait, group photo and classify album can dismiss asset");
673
674 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::DISMISS_ASSET);
675 napi_value result = nullptr;
676 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
677 return result;
678 }
679
JSMergeAlbum(napi_env env,napi_callback_info info)680 napi_value MediaAlbumChangeRequestNapi::JSMergeAlbum(napi_env env, napi_callback_info info)
681 {
682 if (!MediaLibraryNapiUtils::IsSystemApp()) {
683 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
684 return nullptr;
685 }
686 napi_valuetype valueType;
687 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
688
689 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
690 env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok, "Failed to get object info");
691 CHECK_ARGS(env, napi_typeof(env, asyncContext->argv[PARAM0], &valueType), JS_INNER_FAIL);
692 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object, "Invalid argument type");
693 if (valueType == napi_object) {
694 PhotoAlbumNapi* photoAlbumNapi;
695 CHECK_ARGS(env, napi_unwrap(env, asyncContext->argv[PARAM0],
696 reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
697 CHECK_COND_WITH_MESSAGE(env, photoAlbumNapi != nullptr, "Failed to get PhotoAlbumNapi object");
698 asyncContext->objectInfo->targetAlbum_ = photoAlbumNapi->GetPhotoAlbumInstance();
699 }
700 auto photoAlbum = asyncContext->objectInfo->photoAlbum_;
701 auto targetAlbum = asyncContext->objectInfo->targetAlbum_;
702 CHECK_COND_WITH_MESSAGE(env,
703 (photoAlbum != nullptr) && (targetAlbum != nullptr), "PhotoAlbum Or TargetAlbum is nullptr");
704 CHECK_COND_WITH_MESSAGE(env,
705 (PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) &&
706 (PhotoAlbum::IsSmartPortraitPhotoAlbum(targetAlbum->GetPhotoAlbumType(), targetAlbum->GetPhotoAlbumSubType())),
707 "Only portrait album can merge");
708 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::MERGE_ALBUM);
709 napi_value result = nullptr;
710 CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
711 return result;
712 }
713
JSSetDisplayLevel(napi_env env,napi_callback_info info)714 napi_value MediaAlbumChangeRequestNapi::JSSetDisplayLevel(napi_env env, napi_callback_info info)
715 {
716 if (!MediaLibraryNapiUtils::IsSystemApp()) {
717 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
718 return nullptr;
719 }
720 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
721 int32_t displayLevel;
722 CHECK_COND_WITH_MESSAGE(env,
723 MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, displayLevel) == napi_ok,
724 "Failed to parse args");
725 CHECK_COND_WITH_MESSAGE(env, asyncContext->argc == ARGS_ONE, "Number of args is invalid");
726 CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckDisplayLevel(displayLevel), "Invalid display level");
727
728 auto photoAlbum = asyncContext->objectInfo->photoAlbum_;
729 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "PhotoAlbum is nullptr");
730 CHECK_COND_WITH_MESSAGE(env,
731 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
732 "Only portrait album can set album display level");
733 photoAlbum->SetDisplayLevel(displayLevel);
734 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_DISPLAY_LEVEL);
735
736 napi_value result = nullptr;
737 CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
738 return result;
739 }
740
JSDismiss(napi_env env,napi_callback_info info)741 napi_value MediaAlbumChangeRequestNapi::JSDismiss(napi_env env, napi_callback_info info)
742 {
743 if (!MediaLibraryNapiUtils::IsSystemApp()) {
744 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
745 return nullptr;
746 }
747 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
748 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
749 env, info, asyncContext, ARGS_ZERO, ARGS_ZERO) == napi_ok, "Failed to get object info");
750
751 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
752 CHECK_COND_WITH_MESSAGE(env,
753 PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
754 "Only group photo can be dismissed");
755 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::DISMISS);
756 napi_value result = nullptr;
757 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
758 return result;
759 }
760
JSSetAlbumName(napi_env env,napi_callback_info info)761 napi_value MediaAlbumChangeRequestNapi::JSSetAlbumName(napi_env env, napi_callback_info info)
762 {
763 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
764 string albumName;
765 CHECK_COND_WITH_MESSAGE(env,
766 MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, albumName) == napi_ok,
767 "Failed to parse args");
768 CHECK_COND_WITH_MESSAGE(env, asyncContext->argc == ARGS_ONE, "Number of args is invalid");
769 CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckAlbumName(albumName) == E_OK, "Invalid album name");
770
771 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
772 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
773 CHECK_COND_WITH_MESSAGE(env,
774 PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
775 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
776 PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
777 "Only user album, smart portrait album and group photo can set album name");
778 photoAlbum->SetAlbumName(albumName);
779 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_ALBUM_NAME);
780 RETURN_NAPI_UNDEFINED(env);
781 }
782
JSSetCoverUri(napi_env env,napi_callback_info info)783 napi_value MediaAlbumChangeRequestNapi::JSSetCoverUri(napi_env env, napi_callback_info info)
784 {
785 if (!MediaLibraryNapiUtils::IsSystemApp()) {
786 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
787 return nullptr;
788 }
789
790 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
791 string coverUri;
792 CHECK_COND_WITH_MESSAGE(env,
793 MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, coverUri) == napi_ok,
794 "Failed to parse args");
795 CHECK_COND_WITH_MESSAGE(env, asyncContext->argc == ARGS_ONE, "Number of args is invalid");
796
797 auto photoAlbum = asyncContext->objectInfo->GetPhotoAlbumInstance();
798 CHECK_COND_WITH_MESSAGE(env, photoAlbum != nullptr, "photoAlbum is null");
799 CHECK_COND_WITH_MESSAGE(env,
800 PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
801 PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()) ||
802 PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType()),
803 "Only user album, smart portrait album and group photo can set album name");
804 photoAlbum->SetCoverUri(coverUri);
805 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::SET_COVER_URI);
806 RETURN_NAPI_UNDEFINED(env);
807 }
808
JSPlaceBefore(napi_env env,napi_callback_info info)809 napi_value MediaAlbumChangeRequestNapi::JSPlaceBefore(napi_env env, napi_callback_info info)
810 {
811 if (!MediaLibraryNapiUtils::IsSystemApp()) {
812 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
813 return nullptr;
814 }
815 napi_valuetype valueType;
816 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
817
818 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(
819 env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok, "Failed to get object info");
820 CHECK_ARGS(env, napi_typeof(env, asyncContext->argv[PARAM0], &valueType), JS_INNER_FAIL);
821 CHECK_COND_WITH_MESSAGE(env, valueType == napi_object || valueType == napi_null, "Invalid argument type");
822 if (valueType == napi_object) {
823 PhotoAlbumNapi* photoAlbumNapi;
824 CHECK_ARGS(env, napi_unwrap(env, asyncContext->argv[PARAM0],
825 reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
826 CHECK_COND_WITH_MESSAGE(env, photoAlbumNapi != nullptr, "Failed to get PhotoAlbumNapi object");
827 asyncContext->objectInfo->referencePhotoAlbum_ = photoAlbumNapi->GetPhotoAlbumInstance();
828 }
829 asyncContext->objectInfo->albumChangeOperations_.push_back(AlbumChangeOperation::ORDER_ALBUM);
830 RETURN_NAPI_UNDEFINED(env);
831 }
832
CreateAlbumExecute(MediaAlbumChangeRequestAsyncContext & context)833 static bool CreateAlbumExecute(MediaAlbumChangeRequestAsyncContext& context)
834 {
835 MediaLibraryTracer tracer;
836 tracer.Start("CreateAlbumExecute");
837
838 auto changeRequest = context.objectInfo;
839 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
840
841 Uri createAlbumUri(PAH_CREATE_PHOTO_ALBUM);
842 DataShare::DataShareValuesBucket valuesBucket;
843 valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, photoAlbum->GetAlbumName());
844 int32_t ret = UserFileClient::Insert(createAlbumUri, valuesBucket);
845 if (ret == -1) {
846 context.SaveError(-EEXIST);
847 NAPI_ERR_LOG("Album exists");
848 return false;
849 }
850 if (ret < 0) {
851 context.SaveError(ret);
852 NAPI_ERR_LOG("Failed to create album, ret: %{public}d", ret);
853 return false;
854 }
855
856 photoAlbum->SetAlbumId(ret);
857 photoAlbum->SetAlbumUri(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(ret));
858 return true;
859 }
860
FetchNewCount(MediaAlbumChangeRequestAsyncContext & context,shared_ptr<PhotoAlbum> & album)861 static bool FetchNewCount(MediaAlbumChangeRequestAsyncContext& context, shared_ptr<PhotoAlbum>& album)
862 {
863 if (album == nullptr) {
864 NAPI_ERR_LOG("Album is null");
865 context.SaveError(E_FAIL);
866 return false;
867 }
868
869 Uri queryUri(PAH_QUERY_PHOTO_ALBUM);
870 DataShare::DataSharePredicates predicates;
871 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, album->GetAlbumId());
872 vector<string> fetchColumns = { PhotoAlbumColumns::ALBUM_ID, PhotoAlbumColumns::ALBUM_COUNT,
873 PhotoAlbumColumns::ALBUM_IMAGE_COUNT, PhotoAlbumColumns::ALBUM_VIDEO_COUNT };
874 int errCode = 0;
875 auto resultSet = UserFileClient::Query(queryUri, predicates, fetchColumns, errCode);
876 if (resultSet == nullptr) {
877 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
878 context.SaveError(E_HAS_DB_ERROR);
879 return false;
880 }
881 if (resultSet->GoToFirstRow() != 0) {
882 NAPI_ERR_LOG("go to first row failed when fetch new count");
883 context.SaveError(E_HAS_DB_ERROR);
884 return false;
885 }
886
887 bool hiddenOnly = album->GetHiddenOnly();
888 int imageCount = hiddenOnly ? -1 :
889 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT, resultSet, TYPE_INT32));
890 int videoCount = hiddenOnly ? -1 :
891 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT, resultSet, TYPE_INT32));
892 album->SetCount(
893 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_COUNT, resultSet, TYPE_INT32)));
894 album->SetImageCount(imageCount);
895 album->SetVideoCount(videoCount);
896 return true;
897 }
898
AddAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)899 static bool AddAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
900 {
901 MediaLibraryTracer tracer;
902 tracer.Start("AddAssetsExecute");
903
904 auto changeRequest = context.objectInfo;
905 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
906 int32_t albumId = photoAlbum->GetAlbumId();
907 vector<DataShare::DataShareValuesBucket> valuesBuckets;
908 for (const auto& asset : changeRequest->GetAddAssetArray()) {
909 DataShare::DataShareValuesBucket pair;
910 pair.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
911 pair.Put(PhotoColumn::MEDIA_ID, asset);
912 valuesBuckets.push_back(pair);
913 }
914
915 Uri addAssetsUri(PAH_PHOTO_ALBUM_ADD_ASSET);
916 int ret = UserFileClient::BatchInsert(addAssetsUri, valuesBuckets);
917 changeRequest->ClearAddAssetArray();
918 if (ret < 0) {
919 context.SaveError(ret);
920 NAPI_ERR_LOG("Failed to add assets into album %{public}d, err: %{public}d", albumId, ret);
921 return false;
922 }
923
924 NAPI_INFO_LOG("Add %{public}d asset(s) into album %{public}d", ret, albumId);
925 FetchNewCount(context, photoAlbum);
926 return true;
927 }
928
RemoveAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)929 static bool RemoveAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
930 {
931 MediaLibraryTracer tracer;
932 tracer.Start("RemoveAssetsExecute");
933
934 auto changeRequest = context.objectInfo;
935 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
936 int32_t albumId = photoAlbum->GetAlbumId();
937 DataShare::DataSharePredicates predicates;
938 predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(albumId));
939 predicates.And()->In(PhotoColumn::MEDIA_ID, changeRequest->GetRemoveAssetArray());
940
941 Uri removeAssetsUri(PAH_PHOTO_ALBUM_REMOVE_ASSET);
942 int ret = UserFileClient::Delete(removeAssetsUri, predicates);
943 changeRequest->ClearRemoveAssetArray();
944 if (ret < 0) {
945 context.SaveError(ret);
946 NAPI_ERR_LOG("Failed to remove assets from album %{public}d, err: %{public}d", albumId, ret);
947 return false;
948 }
949
950 NAPI_INFO_LOG("Remove %{public}d asset(s) from album %{public}d", ret, albumId);
951 FetchNewCount(context, photoAlbum);
952 return true;
953 }
954
MoveAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)955 static bool MoveAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
956 {
957 MediaLibraryTracer tracer;
958 tracer.Start("MoveAssetsExecute");
959
960 auto changeRequest = context.objectInfo;
961 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
962 int32_t albumId = photoAlbum->GetAlbumId();
963 auto moveMap = changeRequest->GetMoveMap();
964 changeRequest->ClearMoveMap();
965
966 for (auto iter = moveMap.begin(); iter != moveMap.end(); iter++) {
967 auto targetPhotoAlbum = iter->first;
968 int32_t targetAlbumId = targetPhotoAlbum->GetAlbumId();
969 vector<string> moveAssetArray = iter->second;
970 // Move into target album.
971 DataShare::DataSharePredicates predicates;
972 predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(albumId));
973 predicates.And()->In(PhotoColumn::MEDIA_ID, moveAssetArray);
974
975 DataShare::DataShareValuesBucket valuesBuckets;
976 valuesBuckets.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, targetAlbumId);
977 string uri = PAH_BATCH_UPDATE_OWNER_ALBUM_ID;
978 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
979 Uri moveAssetsUri(uri);
980 int ret = UserFileClient::Update(moveAssetsUri, predicates, valuesBuckets);
981 if (ret < 0) {
982 context.SaveError(ret);
983 NAPI_ERR_LOG("Failed to move assets into album %{public}d, err: %{public}d", targetAlbumId, ret);
984 return false;
985 }
986 NAPI_INFO_LOG("Move %{public}d asset(s) into album %{public}d", ret, targetAlbumId);
987 FetchNewCount(context, targetPhotoAlbum);
988 }
989 FetchNewCount(context, photoAlbum);
990 return true;
991 }
992
RecoverAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)993 static bool RecoverAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
994 {
995 MediaLibraryTracer tracer;
996 tracer.Start("RecoverAssetsExecute");
997
998 DataShare::DataSharePredicates predicates;
999 DataShare::DataShareValuesBucket valuesBucket;
1000 predicates.In(PhotoColumn::MEDIA_ID, context.objectInfo->GetRecoverAssetArray());
1001 valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, 0);
1002
1003 Uri recoverAssetsUri(PAH_RECOVER_PHOTOS);
1004 int ret = UserFileClient::Update(recoverAssetsUri, predicates, valuesBucket);
1005 context.objectInfo->ClearRecoverAssetArray();
1006 if (ret < 0) {
1007 context.SaveError(ret);
1008 NAPI_ERR_LOG("Failed to recover assets, err: %{public}d", ret);
1009 return false;
1010 }
1011
1012 NAPI_INFO_LOG("Recover %{public}d assets from trash album", ret);
1013 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1014 int32_t currentCount = photoAlbum->GetCount() - ret;
1015 photoAlbum->SetCount(currentCount > 0 ? currentCount : 0);
1016 return true;
1017 }
1018
DeleteAssetsExecute(MediaAlbumChangeRequestAsyncContext & context)1019 static bool DeleteAssetsExecute(MediaAlbumChangeRequestAsyncContext& context)
1020 {
1021 MediaLibraryTracer tracer;
1022 tracer.Start("DeleteAssetsExecute");
1023
1024 DataShare::DataSharePredicates predicates;
1025 predicates.In(PhotoColumn::MEDIA_ID, context.objectInfo->GetDeleteAssetArray());
1026 DataShare::DataShareValuesBucket valuesBucket;
1027 valuesBucket.Put(PhotoColumn::MEDIA_DATE_TRASHED, 0);
1028
1029 Uri deleteAssetsUri(PAH_DELETE_PHOTOS);
1030 int ret = UserFileClient::Update(deleteAssetsUri, predicates, valuesBucket);
1031 context.objectInfo->ClearDeleteAssetArray();
1032 if (ret < 0) {
1033 context.SaveError(ret);
1034 NAPI_ERR_LOG("Failed to delete assets from trash album permanently, err: %{public}d", ret);
1035 return false;
1036 }
1037
1038 NAPI_INFO_LOG("Delete %{public}d assets permanently from trash album", ret);
1039 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1040 int32_t currentCount = photoAlbum->GetCount() - ret;
1041 photoAlbum->SetCount(currentCount > 0 ? currentCount : 0);
1042 return true;
1043 }
1044
OrderAlbumExecute(MediaAlbumChangeRequestAsyncContext & context)1045 static bool OrderAlbumExecute(MediaAlbumChangeRequestAsyncContext& context)
1046 {
1047 MediaLibraryTracer tracer;
1048 tracer.Start("OrderAlbumExecute");
1049
1050 DataShare::DataSharePredicates predicates;
1051 DataShare::DataShareValuesBucket valuesBucket;
1052 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1053 auto referenceAlum = context.objectInfo->GetReferencePhotoAlbumInstance();
1054 Uri updateAlbumUri(PAH_ORDER_ALBUM);
1055 valuesBucket.Put(PhotoAlbumColumns::ALBUM_ID, photoAlbum->GetAlbumId());
1056 int32_t referenceAlbumId = -1;
1057 if (referenceAlum != nullptr) {
1058 referenceAlbumId = referenceAlum->GetAlbumId();
1059 }
1060 valuesBucket.Put(PhotoAlbumColumns::REFERENCE_ALBUM_ID, referenceAlbumId);
1061 valuesBucket.Put(PhotoAlbumColumns::ALBUM_TYPE, photoAlbum->GetPhotoAlbumType());
1062 valuesBucket.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbum->GetPhotoAlbumSubType());
1063 int32_t result = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
1064 if (result < 0) {
1065 context.SaveError(result);
1066 NAPI_ERR_LOG("Failed to order albums err: %{public}d", result);
1067 return false;
1068 }
1069 return true;
1070 }
1071
UpdateTabAnalysisImageFace(std::shared_ptr<PhotoAlbum> & photoAlbum,MediaAlbumChangeRequestAsyncContext & context)1072 static void UpdateTabAnalysisImageFace(std::shared_ptr<PhotoAlbum>& photoAlbum,
1073 MediaAlbumChangeRequestAsyncContext& context)
1074 {
1075 if (photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::PORTRAIT) {
1076 return;
1077 }
1078
1079 std::string updateUri = PAH_UPDATE_ANA_FACE;
1080 MediaLibraryNapiUtils::UriAppendKeyValue(updateUri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
1081 MediaLibraryNapiUtils::UriAppendKeyValue(updateUri, MEDIA_OPERN_KEYWORD, UPDATE_DISMISS_ASSET);
1082 Uri updateFaceUri(updateUri);
1083
1084 DataShare::DataShareValuesBucket updateValues;
1085 updateValues.Put(MediaAlbumChangeRequestNapi::TAG_ID,
1086 std::to_string(MediaAlbumChangeRequestNapi::PORTRAIT_REMOVED));
1087
1088 DataShare::DataSharePredicates updatePredicates;
1089 std::vector<std::string> dismissAssetArray = context.objectInfo->GetDismissAssetArray();
1090 std::string selection = std::to_string(photoAlbum->GetAlbumId());
1091 for (size_t i = 0; i < dismissAssetArray.size(); ++i) {
1092 selection += "," + dismissAssetArray[i];
1093 }
1094 updatePredicates.SetWhereClause(selection);
1095 int updatedRows = UserFileClient::Update(updateFaceUri, updatePredicates, updateValues);
1096 if (updatedRows <= 0) {
1097 NAPI_WARN_LOG("Failed to update tab_analysis_image_face, err: %{public}d", updatedRows);
1098 }
1099 }
1100
DismissAssetExecute(MediaAlbumChangeRequestAsyncContext & context)1101 static bool DismissAssetExecute(MediaAlbumChangeRequestAsyncContext& context)
1102 {
1103 MediaLibraryTracer tracer;
1104 tracer.Start("DismissAssetExecute");
1105
1106 string disMissAssetAssetsUri = PAH_DISMISS_ASSET;
1107 Uri uri(disMissAssetAssetsUri);
1108
1109 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1110 DataShare::DataSharePredicates predicates;
1111 predicates.EqualTo(MAP_ALBUM, to_string(photoAlbum->GetAlbumId()));
1112 predicates.And()->In(MAP_ASSET, context.objectInfo->GetDismissAssetArray());
1113 predicates.And()->EqualTo(ALBUM_SUBTYPE, to_string(photoAlbum->GetPhotoAlbumSubType()));
1114
1115 auto deletedRows = UserFileClient::Delete(uri, predicates);
1116 if (deletedRows < 0) {
1117 context.SaveError(deletedRows);
1118 NAPI_ERR_LOG("Failed to dismiss asset err: %{public}d", deletedRows);
1119 return false;
1120 }
1121
1122 /* 只针对人像相册更新 tab_analysis_image_face 表 */
1123 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
1124 UpdateTabAnalysisImageFace(photoAlbum, context);
1125 }
1126
1127 context.objectInfo->ClearDismissAssetArray();
1128 return true;
1129 }
1130
MergeAlbumExecute(MediaAlbumChangeRequestAsyncContext & context)1131 static bool MergeAlbumExecute(MediaAlbumChangeRequestAsyncContext& context)
1132 {
1133 MediaLibraryTracer tracer;
1134 tracer.Start("MergeAlbumExecute");
1135
1136 DataShare::DataSharePredicates predicates;
1137 DataShare::DataShareValuesBucket valuesBucket;
1138 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1139 auto targetAlum = context.objectInfo->GetTargetPhotoAlbumInstance();
1140 Uri updateAlbumUri(PAH_PORTRAIT_MERGE_ALBUM);
1141 valuesBucket.Put(ALBUM_ID, photoAlbum->GetAlbumId());
1142 int32_t targetAlbumId = -1;
1143 if (targetAlum != nullptr) {
1144 targetAlbumId = targetAlum->GetAlbumId();
1145 }
1146 valuesBucket.Put(TARGET_ALBUM_ID, targetAlbumId);
1147 int32_t result = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
1148 if (result < 0) {
1149 context.SaveError(result);
1150 NAPI_ERR_LOG("Failed to merge albums err: %{public}d", result);
1151 return false;
1152 }
1153 return true;
1154 }
1155
GetAlbumUpdateValue(shared_ptr<PhotoAlbum> & photoAlbum,const AlbumChangeOperation changeOperation,string & uri,DataShare::DataShareValuesBucket & valuesBucket,string & property)1156 static bool GetAlbumUpdateValue(shared_ptr<PhotoAlbum>& photoAlbum, const AlbumChangeOperation changeOperation,
1157 string& uri, DataShare::DataShareValuesBucket& valuesBucket, string& property)
1158 {
1159 if (photoAlbum == nullptr) {
1160 NAPI_ERR_LOG("photoAlbum is null");
1161 return false;
1162 }
1163
1164 switch (changeOperation) {
1165 case AlbumChangeOperation::SET_ALBUM_NAME:
1166 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
1167 uri = PAH_PORTRAIT_ANAALBUM_ALBUM_NAME;
1168 } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
1169 uri = PAH_GROUP_ANAALBUM_ALBUM_NAME;
1170 } else {
1171 uri = PAH_SET_PHOTO_ALBUM_NAME;
1172 }
1173 property = PhotoAlbumColumns::ALBUM_NAME;
1174 valuesBucket.Put(property, photoAlbum->GetAlbumName());
1175 break;
1176 case AlbumChangeOperation::SET_COVER_URI:
1177 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
1178 uri = PAH_PORTRAIT_ANAALBUM_COVER_URI;
1179 } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
1180 uri = PAH_GROUP_ANAALBUM_COVER_URI;
1181 } else {
1182 uri = PAH_UPDATE_PHOTO_ALBUM;
1183 }
1184 property = PhotoAlbumColumns::ALBUM_COVER_URI;
1185 valuesBucket.Put(property, photoAlbum->GetCoverUri());
1186 break;
1187 case AlbumChangeOperation::SET_DISPLAY_LEVEL:
1188 uri = PAH_PORTRAIT_DISPLAY_LEVLE;
1189 property = USER_DISPLAY_LEVEL;
1190 valuesBucket.Put(property, photoAlbum->GetDisplayLevel());
1191 break;
1192 case AlbumChangeOperation::SET_IS_ME:
1193 uri = PAH_PORTRAIT_IS_ME;
1194 property = IS_ME;
1195 valuesBucket.Put(property, 1);
1196 break;
1197 case AlbumChangeOperation::DISMISS:
1198 uri = PAH_GROUP_ANAALBUM_DISMISS;
1199 property = IS_REMOVED;
1200 valuesBucket.Put(property, 1);
1201 break;
1202 default:
1203 return false;
1204 }
1205 return true;
1206 }
1207
SetAlbumPropertyExecute(MediaAlbumChangeRequestAsyncContext & context,const AlbumChangeOperation changeOperation)1208 static bool SetAlbumPropertyExecute(
1209 MediaAlbumChangeRequestAsyncContext& context, const AlbumChangeOperation changeOperation)
1210 {
1211 MediaLibraryTracer tracer;
1212 tracer.Start("SetAlbumPropertyExecute");
1213
1214 // In the scenario of creation, the new name will be applied when the album is created.
1215 if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME &&
1216 context.albumChangeOperations.front() == AlbumChangeOperation::CREATE_ALBUM) {
1217 return true;
1218 }
1219
1220 DataShare::DataSharePredicates predicates;
1221 DataShare::DataShareValuesBucket valuesBucket;
1222 auto photoAlbum = context.objectInfo->GetPhotoAlbumInstance();
1223 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
1224 string uri;
1225 string property;
1226 if (!GetAlbumUpdateValue(photoAlbum, changeOperation, uri, valuesBucket, property)) {
1227 context.SaveError(E_FAIL);
1228 NAPI_ERR_LOG("Failed to parse album change operation: %{public}d", changeOperation);
1229 return false;
1230 }
1231 valuesBucket.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbum->GetPhotoAlbumSubType());
1232 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1233 Uri updateAlbumUri(uri);
1234 int32_t changedRows = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
1235 if (changedRows < 0) {
1236 context.SaveError(changedRows);
1237 NAPI_ERR_LOG("Failed to set %{public}s, err: %{public}d", property.c_str(), changedRows);
1238 return false;
1239 }
1240 return true;
1241 }
1242
1243 static const unordered_map<AlbumChangeOperation, bool (*)(MediaAlbumChangeRequestAsyncContext&)> EXECUTE_MAP = {
1244 { AlbumChangeOperation::CREATE_ALBUM, CreateAlbumExecute },
1245 { AlbumChangeOperation::ADD_ASSETS, AddAssetsExecute },
1246 { AlbumChangeOperation::REMOVE_ASSETS, RemoveAssetsExecute },
1247 { AlbumChangeOperation::MOVE_ASSETS, MoveAssetsExecute },
1248 { AlbumChangeOperation::RECOVER_ASSETS, RecoverAssetsExecute },
1249 { AlbumChangeOperation::DELETE_ASSETS, DeleteAssetsExecute },
1250 { AlbumChangeOperation::ORDER_ALBUM, OrderAlbumExecute },
1251 { AlbumChangeOperation::MERGE_ALBUM, MergeAlbumExecute },
1252 { AlbumChangeOperation::DISMISS_ASSET, DismissAssetExecute },
1253 };
1254
ApplyAlbumChangeRequestExecute(napi_env env,void * data)1255 static void ApplyAlbumChangeRequestExecute(napi_env env, void* data)
1256 {
1257 MediaLibraryTracer tracer;
1258 tracer.Start("ApplyAlbumChangeRequestExecute");
1259
1260 auto* context = static_cast<MediaAlbumChangeRequestAsyncContext*>(data);
1261 unordered_set<AlbumChangeOperation> appliedOperations;
1262 for (const auto& changeOperation : context->albumChangeOperations) {
1263 // Keep the final result(s) of each operation, and commit only once.
1264 if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
1265 continue;
1266 }
1267
1268 bool valid = false;
1269 auto iter = EXECUTE_MAP.find(changeOperation);
1270 if (iter != EXECUTE_MAP.end()) {
1271 valid = iter->second(*context);
1272 } else if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME ||
1273 changeOperation == AlbumChangeOperation::SET_COVER_URI ||
1274 changeOperation == AlbumChangeOperation::SET_IS_ME ||
1275 changeOperation == AlbumChangeOperation::SET_DISPLAY_LEVEL ||
1276 changeOperation == AlbumChangeOperation::DISMISS) {
1277 valid = SetAlbumPropertyExecute(*context, changeOperation);
1278 } else {
1279 NAPI_ERR_LOG("Invalid album change operation: %{public}d", changeOperation);
1280 context->error = OHOS_INVALID_PARAM_CODE;
1281 return;
1282 }
1283
1284 if (!valid) {
1285 NAPI_ERR_LOG("Failed to apply album change request, operation: %{public}d", changeOperation);
1286 return;
1287 }
1288 appliedOperations.insert(changeOperation);
1289 }
1290 }
1291
ApplyAlbumChangeRequestCompleteCallback(napi_env env,napi_status status,void * data)1292 static void ApplyAlbumChangeRequestCompleteCallback(napi_env env, napi_status status, void* data)
1293 {
1294 MediaLibraryTracer tracer;
1295 tracer.Start("ApplyAlbumChangeRequestCompleteCallback");
1296
1297 auto* context = static_cast<MediaAlbumChangeRequestAsyncContext*>(data);
1298 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1299 auto jsContext = make_unique<JSAsyncContextOutput>();
1300 jsContext->status = false;
1301 napi_get_undefined(env, &jsContext->data);
1302 napi_get_undefined(env, &jsContext->error);
1303 if (context->error == ERR_DEFAULT) {
1304 jsContext->status = true;
1305 } else {
1306 context->HandleError(env, jsContext->error);
1307 }
1308
1309 if (context->work != nullptr) {
1310 MediaLibraryNapiUtils::InvokeJSAsyncMethod(
1311 env, context->deferred, context->callbackRef, context->work, *jsContext);
1312 }
1313 delete context;
1314 }
1315
CheckPortraitMergeAlbum()1316 bool MediaAlbumChangeRequestNapi::CheckPortraitMergeAlbum()
1317 {
1318 bool hasMergeAlbum = false;
1319 bool hasAlbumName = false;
1320 for (auto operation : albumChangeOperations_) {
1321 if (operation == AlbumChangeOperation::MERGE_ALBUM) {
1322 hasMergeAlbum = true;
1323 }
1324 if (operation == AlbumChangeOperation::SET_ALBUM_NAME) {
1325 hasAlbumName = true;
1326 }
1327 }
1328 return (hasAlbumName && hasMergeAlbum) || (hasMergeAlbum == false);
1329 }
1330
ApplyChanges(napi_env env,napi_callback_info info)1331 napi_value MediaAlbumChangeRequestNapi::ApplyChanges(napi_env env, napi_callback_info info)
1332 {
1333 constexpr size_t minArgs = ARGS_ONE;
1334 constexpr size_t maxArgs = ARGS_TWO;
1335 auto asyncContext = make_unique<MediaAlbumChangeRequestAsyncContext>();
1336 CHECK_COND_WITH_MESSAGE(env,
1337 MediaLibraryNapiUtils::AsyncContextGetArgs(env, info, asyncContext, minArgs, maxArgs) == napi_ok,
1338 "Failed to get args");
1339 asyncContext->objectInfo = this;
1340 CHECK_COND_WITH_MESSAGE(env, CheckChangeOperations(env), "Failed to check album change request operations");
1341 asyncContext->albumChangeOperations = albumChangeOperations_;
1342 albumChangeOperations_.clear();
1343 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "ApplyMediaAlbumChangeRequest",
1344 ApplyAlbumChangeRequestExecute, ApplyAlbumChangeRequestCompleteCallback);
1345 }
1346 } // namespace OHOS::Media