• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define MLOG_TAG "PhotoAlbumNapi"
16 
17 #include "photo_album_napi.h"
18 #include <nlohmann/json.hpp>
19 
20 #include "fetch_file_result_napi.h"
21 #include "file_asset_napi.h"
22 #include "media_file_utils.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_napi_log.h"
25 #include "medialibrary_napi_utils_ext.h"
26 #include "medialibrary_tracer.h"
27 #include "photo_map_column.h"
28 #include "result_set_utils.h"
29 #include "userfile_client.h"
30 #include "album_operation_uri.h"
31 #include "user_define_ipc_client.h"
32 #include "medialibrary_business_code.h"
33 #include "delete_photos_vo.h"
34 #include "album_commit_modify_vo.h"
35 #include "album_add_assets_vo.h"
36 #include "album_remove_assets_vo.h"
37 #include "album_recover_assets_vo.h"
38 #include "album_photo_query_vo.h"
39 #include "album_get_assets_vo.h"
40 #include "get_face_id_vo.h"
41 #include "shooting_mode_column.h"
42 
43 using namespace std;
44 using namespace OHOS::DataShare;
45 
46 namespace OHOS::Media {
47 thread_local PhotoAlbum *PhotoAlbumNapi::pAlbumData_ = nullptr;
48 thread_local napi_ref PhotoAlbumNapi::constructor_ = nullptr;
49 thread_local napi_ref PhotoAlbumNapi::photoAccessConstructor_ = nullptr;
50 static const string PHOTO_ALBUM_CLASS = "UserFileMgrPhotoAlbum";
51 static const string PHOTOACCESS_PHOTO_ALBUM_CLASS = "PhotoAccessPhotoAlbum";
52 static const string COUNT_GROUP_BY = "count(*) AS count";
53 std::mutex PhotoAlbumNapi::mutex_;
54 
55 struct TrashAlbumExecuteOpt {
56     napi_env env;
57     void *data;
58     string tracerLabel;
59     string uri;
60 };
61 
62 using CompleteCallback = napi_async_complete_callback;
63 
PhotoAlbumNapi()64 PhotoAlbumNapi::PhotoAlbumNapi() : env_(nullptr) {}
65 
66 PhotoAlbumNapi::~PhotoAlbumNapi() = default;
67 
Init(napi_env env,napi_value exports)68 napi_value PhotoAlbumNapi::Init(napi_env env, napi_value exports)
69 {
70     NapiClassInfo info = {
71         .name = PHOTO_ALBUM_CLASS,
72         .ref = &constructor_,
73         .constructor = PhotoAlbumNapiConstructor,
74         .props = {
75             DECLARE_NAPI_GETTER_SETTER("albumName", JSGetAlbumName, JSSetAlbumName),
76             DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri),
77             DECLARE_NAPI_GETTER("count", JSGetAlbumCount),
78             DECLARE_NAPI_GETTER("albumType", JSGetPhotoAlbumType),
79             DECLARE_NAPI_GETTER("albumSubType", JSGetPhotoAlbumSubType),
80             DECLARE_NAPI_GETTER_SETTER("coverUri", JSGetCoverUri, JSSetCoverUri),
81             DECLARE_NAPI_GETTER("dateModified", JSGetDateModified),
82             DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
83             DECLARE_NAPI_FUNCTION("addPhotoAssets", JSPhotoAlbumAddAssets),
84             DECLARE_NAPI_FUNCTION("removePhotoAssets", JSPhotoAlbumRemoveAssets),
85             DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
86             DECLARE_NAPI_FUNCTION("recoverPhotoAssets", JSRecoverPhotos),
87             DECLARE_NAPI_FUNCTION("deletePhotoAssets", JSDeletePhotos),
88             // PrivateAlbum.recover
89             DECLARE_NAPI_FUNCTION("recover", PrivateAlbumRecoverPhotos),
90             // PrivateAlbum.delete
91             DECLARE_NAPI_FUNCTION("delete", PrivateAlbumDeletePhotos),
92         }
93     };
94 
95     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
96     return exports;
97 }
98 
PhotoAccessInit(napi_env env,napi_value exports)99 napi_value PhotoAlbumNapi::PhotoAccessInit(napi_env env, napi_value exports)
100 {
101     NapiClassInfo info = {
102         .name = PHOTOACCESS_PHOTO_ALBUM_CLASS,
103         .ref = &photoAccessConstructor_,
104         .constructor = PhotoAlbumNapiConstructor,
105         .props = {
106             DECLARE_NAPI_GETTER_SETTER("albumName", JSPhotoAccessGetAlbumName, JSPhotoAccessSetAlbumName),
107             DECLARE_NAPI_GETTER("albumUri", JSPhotoAccessGetAlbumUri),
108             DECLARE_NAPI_GETTER("count", JSPhotoAccessGetAlbumCount),
109             DECLARE_NAPI_GETTER("imageCount", JSPhotoAccessGetAlbumImageCount),
110             DECLARE_NAPI_GETTER("videoCount", JSPhotoAccessGetAlbumVideoCount),
111             DECLARE_NAPI_GETTER("albumType", JSGetPhotoAlbumType),
112             DECLARE_NAPI_GETTER("albumSubtype", JSGetPhotoAlbumSubType),
113             DECLARE_NAPI_GETTER("coverUri", JSGetCoverUri),
114             DECLARE_NAPI_GETTER("latitude", JSGetLatitude),
115             DECLARE_NAPI_GETTER("longitude", JSGetLongitude),
116             DECLARE_NAPI_GETTER("lpath", JSGetAlbumLPath),
117             DECLARE_NAPI_GETTER("dateModified", JSGetDateModifiedSystem),
118             DECLARE_NAPI_GETTER("dateAdded", JSGetDateAdded),
119             DECLARE_NAPI_GETTER("coverUriSource", JSGetCoverUriSource),
120             DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify),
121             DECLARE_NAPI_FUNCTION("addAssets", PhotoAccessHelperAddAssets),
122             DECLARE_NAPI_FUNCTION("removeAssets", PhotoAccessHelperRemoveAssets),
123             DECLARE_NAPI_FUNCTION("getAssets", JSPhotoAccessGetPhotoAssets),
124             DECLARE_NAPI_FUNCTION("recoverAssets", PhotoAccessHelperRecoverPhotos),
125             DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperDeletePhotos),
126             DECLARE_NAPI_FUNCTION("setCoverUri", PhotoAccessHelperSetCoverUri),
127             DECLARE_NAPI_FUNCTION("getAssetsSync", JSPhotoAccessGetPhotoAssetsSync),
128             DECLARE_NAPI_FUNCTION("getSharedPhotoAssets", JSPhotoAccessGetSharedPhotoAssets),
129             DECLARE_NAPI_FUNCTION("getFaceId", PhotoAccessHelperGetFaceId),
130         }
131     };
132 
133     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
134     return exports;
135 }
136 
CreatePhotoAlbumNapi(napi_env env,unique_ptr<PhotoAlbum> & albumData)137 napi_value PhotoAlbumNapi::CreatePhotoAlbumNapi(napi_env env, unique_ptr<PhotoAlbum> &albumData)
138 {
139     if (albumData == nullptr) {
140         return nullptr;
141     }
142 
143     napi_value constructor;
144     napi_ref constructorRef;
145     if (albumData->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
146         constructorRef = photoAccessConstructor_;
147     } else {
148         constructorRef = constructor_;
149     }
150     CHECK_ARGS(env, napi_get_reference_value(env, constructorRef, &constructor), JS_INNER_FAIL);
151 
152     napi_value result = nullptr;
153     pAlbumData_ = albumData.release();
154     CHECK_ARGS(env, napi_new_instance(env, constructor, 0, nullptr, &result), JS_INNER_FAIL);
155     pAlbumData_ = nullptr;
156     return result;
157 }
158 
CreatePhotoAlbumNapi(napi_env env,shared_ptr<PhotoAlbum> & albumData)159 napi_value PhotoAlbumNapi::CreatePhotoAlbumNapi(napi_env env, shared_ptr<PhotoAlbum>& albumData)
160 {
161     if (albumData == nullptr || albumData->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
162         NAPI_ERR_LOG("Unsupported photo album data");
163         return nullptr;
164     }
165 
166     napi_value constructor = nullptr;
167     napi_value result = nullptr;
168     CHECK_ARGS(env, napi_get_reference_value(env, photoAccessConstructor_, &constructor), JS_INNER_FAIL);
169     CHECK_ARGS(env, napi_new_instance(env, constructor, 0, nullptr, &result), JS_INNER_FAIL);
170     CHECK_COND(env, result != nullptr, JS_INNER_FAIL);
171 
172     PhotoAlbumNapi* photoAlbumNapi = nullptr;
173     CHECK_ARGS(env, napi_unwrap(env, result, reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
174     CHECK_COND(env, photoAlbumNapi != nullptr, JS_INNER_FAIL);
175     photoAlbumNapi->photoAlbumPtr = albumData;
176     return result;
177 }
178 
GetAlbumId() const179 int32_t PhotoAlbumNapi::GetAlbumId() const
180 {
181     return photoAlbumPtr->GetAlbumId();
182 }
183 
GetCount() const184 int32_t PhotoAlbumNapi::GetCount() const
185 {
186     return photoAlbumPtr->GetCount();
187 }
188 
SetCount(int32_t count)189 void PhotoAlbumNapi::SetCount(int32_t count)
190 {
191     return photoAlbumPtr->SetCount(count);
192 }
193 
GetImageCount() const194 int32_t PhotoAlbumNapi::GetImageCount() const
195 {
196     return photoAlbumPtr->GetImageCount();
197 }
198 
SetImageCount(int32_t count)199 void PhotoAlbumNapi::SetImageCount(int32_t count)
200 {
201     return photoAlbumPtr->SetImageCount(count);
202 }
203 
GetVideoCount() const204 int32_t PhotoAlbumNapi::GetVideoCount() const
205 {
206     return photoAlbumPtr->GetVideoCount();
207 }
208 
SetVideoCount(int32_t count)209 void PhotoAlbumNapi::SetVideoCount(int32_t count)
210 {
211     return photoAlbumPtr->SetVideoCount(count);
212 }
213 
GetAlbumUri() const214 const string& PhotoAlbumNapi::GetAlbumUri() const
215 {
216     return photoAlbumPtr->GetAlbumUri();
217 }
218 
GetCoverUri() const219 const string& PhotoAlbumNapi::GetCoverUri() const
220 {
221     return photoAlbumPtr->GetCoverUri();
222 }
223 
GetDateModified() const224 int64_t PhotoAlbumNapi::GetDateModified() const
225 {
226     return photoAlbumPtr->GetDateModified();
227 }
228 
GetDateAdded() const229 int64_t PhotoAlbumNapi::GetDateAdded() const
230 {
231     return photoAlbumPtr->GetDateAdded();
232 }
233 
GetCoverUriSource() const234 int32_t PhotoAlbumNapi::GetCoverUriSource() const
235 {
236     return photoAlbumPtr->GetCoverUriSource();
237 }
238 
GetAlbumName() const239 const string& PhotoAlbumNapi::GetAlbumName() const
240 {
241     return photoAlbumPtr->GetAlbumName();
242 }
243 
GetPhotoAlbumType() const244 PhotoAlbumType PhotoAlbumNapi::GetPhotoAlbumType() const
245 {
246     return photoAlbumPtr->GetPhotoAlbumType();
247 }
248 
GetPhotoAlbumSubType() const249 PhotoAlbumSubType PhotoAlbumNapi::GetPhotoAlbumSubType() const
250 {
251     return photoAlbumPtr->GetPhotoAlbumSubType();
252 }
253 
GetLatitude() const254 double PhotoAlbumNapi::GetLatitude() const
255 {
256     return photoAlbumPtr->GetLatitude();
257 }
258 
GetLongitude() const259 double PhotoAlbumNapi::GetLongitude() const
260 {
261     return photoAlbumPtr->GetLongitude();
262 }
263 
GetLPath() const264 const string& PhotoAlbumNapi::GetLPath() const
265 {
266     return photoAlbumPtr->GetLPath();
267 }
268 
GetPhotoAlbumInstance() const269 shared_ptr<PhotoAlbum> PhotoAlbumNapi::GetPhotoAlbumInstance() const
270 {
271     return photoAlbumPtr;
272 }
273 
GetHiddenOnly() const274 bool PhotoAlbumNapi::GetHiddenOnly() const
275 {
276     return photoAlbumPtr->GetHiddenOnly();
277 }
278 
SetHiddenOnly(const bool hiddenOnly_)279 void PhotoAlbumNapi::SetHiddenOnly(const bool hiddenOnly_)
280 {
281     return photoAlbumPtr->SetHiddenOnly(hiddenOnly_);
282 }
283 
SetPhotoAlbumNapiProperties()284 void PhotoAlbumNapi::SetPhotoAlbumNapiProperties()
285 {
286     photoAlbumPtr = shared_ptr<PhotoAlbum>(pAlbumData_);
287 }
288 
289 // Constructor callback
PhotoAlbumNapiConstructor(napi_env env,napi_callback_info info)290 napi_value PhotoAlbumNapi::PhotoAlbumNapiConstructor(napi_env env, napi_callback_info info)
291 {
292     napi_value result = nullptr;
293     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
294 
295     napi_value thisVar = nullptr;
296     CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
297     if (thisVar == nullptr) {
298         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
299         return result;
300     }
301 
302     unique_ptr<PhotoAlbumNapi> obj = make_unique<PhotoAlbumNapi>();
303     obj->env_ = env;
304     if (pAlbumData_ != nullptr) {
305         obj->SetPhotoAlbumNapiProperties();
306     }
307     CHECK_ARGS(env, napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
308         PhotoAlbumNapi::PhotoAlbumNapiDestructor, nullptr, nullptr), JS_INNER_FAIL);
309     obj.release();
310     return thisVar;
311 }
312 
PhotoAlbumNapiDestructor(napi_env env,void * nativeObject,void * finalizeHint)313 void PhotoAlbumNapi::PhotoAlbumNapiDestructor(napi_env env, void *nativeObject, void *finalizeHint)
314 {
315     auto *album = reinterpret_cast<PhotoAlbumNapi*>(nativeObject);
316     lock_guard<mutex> lockGuard(mutex_);
317     if (album != nullptr) {
318         delete album;
319         album = nullptr;
320     }
321 }
322 
UnwrapPhotoAlbumObject(napi_env env,napi_callback_info info,PhotoAlbumNapi ** obj)323 napi_value UnwrapPhotoAlbumObject(napi_env env, napi_callback_info info, PhotoAlbumNapi** obj)
324 {
325     napi_value result = nullptr;
326     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
327 
328     napi_value thisVar = nullptr;
329     CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
330     if (thisVar == nullptr) {
331         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
332         return result;
333     }
334 
335     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), JS_INNER_FAIL);
336     if (obj == nullptr) {
337         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
338         return result;
339     }
340 
341     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
342     return result;
343 }
344 
JSGetAlbumName(napi_env env,napi_callback_info info)345 napi_value PhotoAlbumNapi::JSGetAlbumName(napi_env env, napi_callback_info info)
346 {
347     PhotoAlbumNapi *obj = nullptr;
348     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
349 
350     napi_value jsResult = nullptr;
351     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumName().c_str(), NAPI_AUTO_LENGTH, &jsResult),
352         JS_INNER_FAIL);
353     return jsResult;
354 }
355 
JSPhotoAccessGetAlbumName(napi_env env,napi_callback_info info)356 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumName(napi_env env, napi_callback_info info)
357 {
358     PhotoAlbumNapi *obj = nullptr;
359     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
360 
361     napi_value jsResult = nullptr;
362     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumName().c_str(), NAPI_AUTO_LENGTH, &jsResult),
363         JS_INNER_FAIL);
364     return jsResult;
365 }
366 
JSGetAlbumUri(napi_env env,napi_callback_info info)367 napi_value PhotoAlbumNapi::JSGetAlbumUri(napi_env env, napi_callback_info info)
368 {
369     PhotoAlbumNapi *obj = nullptr;
370     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
371 
372     napi_value jsResult = nullptr;
373     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
374         JS_INNER_FAIL);
375     return jsResult;
376 }
377 
JSPhotoAccessGetAlbumUri(napi_env env,napi_callback_info info)378 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumUri(napi_env env, napi_callback_info info)
379 {
380     PhotoAlbumNapi *obj = nullptr;
381     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
382 
383     napi_value jsResult = nullptr;
384     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
385         JS_INNER_FAIL);
386     return jsResult;
387 }
388 
JSGetAlbumCount(napi_env env,napi_callback_info info)389 napi_value PhotoAlbumNapi::JSGetAlbumCount(napi_env env, napi_callback_info info)
390 {
391     PhotoAlbumNapi *obj = nullptr;
392     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
393 
394     napi_value jsResult = nullptr;
395     CHECK_ARGS(env, napi_create_int32(env, obj->GetCount(), &jsResult), JS_INNER_FAIL);
396     return jsResult;
397 }
398 
JSPhotoAccessGetAlbumCount(napi_env env,napi_callback_info info)399 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumCount(napi_env env, napi_callback_info info)
400 {
401     PhotoAlbumNapi *obj = nullptr;
402     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
403 
404     napi_value jsResult = nullptr;
405     CHECK_ARGS(env, napi_create_int32(env, obj->GetCount(), &jsResult), JS_INNER_FAIL);
406     return jsResult;
407 }
408 
JSPhotoAccessGetAlbumImageCount(napi_env env,napi_callback_info info)409 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumImageCount(napi_env env, napi_callback_info info)
410 {
411     PhotoAlbumNapi *obj = nullptr;
412     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
413 
414     napi_value jsResult = nullptr;
415     CHECK_ARGS(env, napi_create_int32(env, obj->GetImageCount(), &jsResult), JS_INNER_FAIL);
416     return jsResult;
417 }
418 
JSPhotoAccessGetAlbumVideoCount(napi_env env,napi_callback_info info)419 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumVideoCount(napi_env env, napi_callback_info info)
420 {
421     PhotoAlbumNapi *obj = nullptr;
422     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
423 
424     napi_value jsResult = nullptr;
425     CHECK_ARGS(env, napi_create_int32(env, obj->GetVideoCount(), &jsResult), JS_INNER_FAIL);
426     return jsResult;
427 }
428 
JSGetPhotoAlbumType(napi_env env,napi_callback_info info)429 napi_value PhotoAlbumNapi::JSGetPhotoAlbumType(napi_env env, napi_callback_info info)
430 {
431     PhotoAlbumNapi *obj = nullptr;
432     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
433 
434     napi_value jsResult = nullptr;
435     CHECK_ARGS(env, napi_create_int32(env, obj->GetPhotoAlbumType(), &jsResult), JS_INNER_FAIL);
436     return jsResult;
437 }
438 
JSGetPhotoAlbumSubType(napi_env env,napi_callback_info info)439 napi_value PhotoAlbumNapi::JSGetPhotoAlbumSubType(napi_env env, napi_callback_info info)
440 {
441     PhotoAlbumNapi *obj = nullptr;
442     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
443 
444     napi_value jsResult = nullptr;
445     CHECK_ARGS(env, napi_create_int32(env, obj->GetPhotoAlbumSubType(), &jsResult), JS_INNER_FAIL);
446     return jsResult;
447 }
448 
JSGetCoverUri(napi_env env,napi_callback_info info)449 napi_value PhotoAlbumNapi::JSGetCoverUri(napi_env env, napi_callback_info info)
450 {
451     PhotoAlbumNapi *obj = nullptr;
452     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
453 
454     napi_value jsResult = nullptr;
455     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetCoverUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
456         JS_INNER_FAIL);
457     return jsResult;
458 }
459 
JSGetLatitude(napi_env env,napi_callback_info info)460 napi_value PhotoAlbumNapi::JSGetLatitude(napi_env env, napi_callback_info info)
461 {
462     PhotoAlbumNapi *obj = nullptr;
463     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
464 
465     napi_value jsResult = nullptr;
466     CHECK_ARGS(env, napi_create_double(env, obj->GetLatitude(), &jsResult), JS_INNER_FAIL);
467     return jsResult;
468 }
469 
JSGetLongitude(napi_env env,napi_callback_info info)470 napi_value PhotoAlbumNapi::JSGetLongitude(napi_env env, napi_callback_info info)
471 {
472     PhotoAlbumNapi *obj = nullptr;
473     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
474 
475     napi_value jsResult = nullptr;
476     CHECK_ARGS(env, napi_create_double(env, obj->GetLongitude(), &jsResult), JS_INNER_FAIL);
477     return jsResult;
478 }
479 
JSGetAlbumLPath(napi_env env,napi_callback_info info)480 napi_value PhotoAlbumNapi::JSGetAlbumLPath(napi_env env, napi_callback_info info)
481 {
482     CHECK_COND_LOG_THROW_RETURN_RET(env, MediaLibraryNapiUtils::IsSystemApp(), JS_ERR_PERMISSION_DENIED,
483         "Get lpath permission denied: not a system app", nullptr, "Get album lpath failed: not a system app");
484     CHECK_COND(env, MediaLibraryNapiUtils::IsSystemApp(), JS_ERR_PERMISSION_DENIED);
485     PhotoAlbumNapi *obj = nullptr;
486     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
487 
488     napi_value jsResult = nullptr;
489     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetLPath().c_str(), NAPI_AUTO_LENGTH, &jsResult), JS_INNER_FAIL);
490     return jsResult;
491 }
492 
GetStringArg(napi_env env,napi_callback_info info,PhotoAlbumNapi ** obj,string & output)493 napi_value GetStringArg(napi_env env, napi_callback_info info, PhotoAlbumNapi **obj, string &output)
494 {
495     size_t argc = ARGS_ONE;
496     napi_value argv[ARGS_ONE];
497     napi_value thisVar = nullptr;
498     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
499     CHECK_COND(env, argc == ARGS_ONE, JS_ERR_PARAMETER_INVALID);
500 
501     napi_value result = nullptr;
502     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
503     napi_valuetype valueType = napi_undefined;
504     if ((thisVar == nullptr) || (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok) || (valueType != napi_string)) {
505         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
506         return result;
507     }
508 
509     size_t res = 0;
510     char buffer[FILENAME_MAX];
511     CHECK_ARGS(env, napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res), JS_INNER_FAIL);
512     output = string(buffer);
513 
514     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), JS_INNER_FAIL);
515     if (obj == nullptr) {
516         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
517         return result;
518     }
519 
520     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
521     return result;
522 }
523 
JSSetAlbumName(napi_env env,napi_callback_info info)524 napi_value PhotoAlbumNapi::JSSetAlbumName(napi_env env, napi_callback_info info)
525 {
526     PhotoAlbumNapi *obj = nullptr;
527     string albumName;
528     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, albumName));
529     obj->photoAlbumPtr->SetAlbumName(albumName);
530 
531     napi_value result = nullptr;
532     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
533     return result;
534 }
535 
JSPhotoAccessSetAlbumName(napi_env env,napi_callback_info info)536 napi_value PhotoAlbumNapi::JSPhotoAccessSetAlbumName(napi_env env, napi_callback_info info)
537 {
538     PhotoAlbumNapi *obj = nullptr;
539     string albumName;
540     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, albumName));
541     obj->photoAlbumPtr->SetAlbumName(albumName);
542 
543     napi_value result = nullptr;
544     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
545     return result;
546 }
547 
JSSetCoverUri(napi_env env,napi_callback_info info)548 napi_value PhotoAlbumNapi::JSSetCoverUri(napi_env env, napi_callback_info info)
549 {
550     PhotoAlbumNapi *obj = nullptr;
551     string coverUri;
552     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, coverUri));
553     obj->photoAlbumPtr->SetCoverUri(coverUri);
554 
555     napi_value result = nullptr;
556     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
557     return result;
558 }
559 
JSGetDateModified(napi_env env,napi_callback_info info)560 napi_value PhotoAlbumNapi::JSGetDateModified(napi_env env, napi_callback_info info)
561 {
562     PhotoAlbumNapi *obj = nullptr;
563     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
564 
565     napi_value jsResult = nullptr;
566     CHECK_ARGS(env, napi_create_int64(env, obj->GetDateModified(), &jsResult),
567         JS_INNER_FAIL);
568     return jsResult;
569 }
570 
JSGetDateModifiedSystem(napi_env env,napi_callback_info info)571 napi_value PhotoAlbumNapi::JSGetDateModifiedSystem(napi_env env, napi_callback_info info)
572 {
573     CHECK_COND_LOG_THROW_RETURN_RET(env, MediaLibraryNapiUtils::IsSystemApp(), JS_ERR_PERMISSION_DENIED,
574         "Get dateModified permission denied: not a system app", nullptr,
575         "Get album dateModified failed: not a system app");
576     PhotoAlbumNapi *obj = nullptr;
577     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
578 
579     napi_value jsResult = nullptr;
580     CHECK_ARGS(env, napi_create_int64(env, obj->GetDateModified(), &jsResult),
581         JS_INNER_FAIL);
582     return jsResult;
583 }
584 
585 
JSGetDateAdded(napi_env env,napi_callback_info info)586 napi_value PhotoAlbumNapi::JSGetDateAdded(napi_env env, napi_callback_info info)
587 {
588     CHECK_COND_LOG_THROW_RETURN_RET(env, MediaLibraryNapiUtils::IsSystemApp(), JS_ERR_PERMISSION_DENIED,
589         "Get dateAdded permission denied: not a system app", nullptr, "Get album dateAdded failed: not a system app");
590     PhotoAlbumNapi *obj = nullptr;
591     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
592 
593     napi_value jsResult = nullptr;
594     CHECK_ARGS(env, napi_create_int64(env, obj->GetDateAdded(), &jsResult),
595         JS_INNER_FAIL);
596     return jsResult;
597 }
598 
JSGetCoverUriSource(napi_env env,napi_callback_info info)599 napi_value PhotoAlbumNapi::JSGetCoverUriSource(napi_env env, napi_callback_info info)
600 {
601     CHECK_COND_LOG_THROW_RETURN_RET(env, MediaLibraryNapiUtils::IsSystemApp(), JS_ERR_PERMISSION_DENIED,
602         "GetCoverUriSource permission denied: not a system app", nullptr, "GetCoverUriSource failed: not a system app");
603     PhotoAlbumNapi *obj = nullptr;
604     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
605 
606     napi_value jsResult = nullptr;
607     CHECK_ARGS(env, napi_create_int32(env, obj->GetCoverUriSource(), &jsResult),
608         JS_INNER_FAIL);
609     return jsResult;
610 }
611 
ParseArgsCommitModify(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)612 static napi_value ParseArgsCommitModify(napi_env env, napi_callback_info info,
613     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
614 {
615     constexpr size_t minArgs = ARGS_ZERO;
616     constexpr size_t maxArgs = ARGS_ONE;
617     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
618         JS_ERR_PARAMETER_INVALID);
619 
620     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
621     if (photoAlbum == nullptr) {
622         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
623         return nullptr;
624     }
625     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
626         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
627         return nullptr;
628     }
629 
630     if (MediaFileUtils::CheckAlbumName(photoAlbum->GetAlbumName()) < 0) {
631         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
632         return nullptr;
633     }
634     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
635     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, photoAlbum->GetAlbumName());
636     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, photoAlbum->GetCoverUri());
637     context->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_COMMIT_MODIFY);
638 
639     napi_value result = nullptr;
640     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
641     return result;
642 }
643 
JSCommitModifyIPCExecute(PhotoAlbumNapiAsyncContext * context)644 static void JSCommitModifyIPCExecute(PhotoAlbumNapiAsyncContext *context)
645 {
646     int32_t changedRows = 0;
647     auto objectInfo = context->objectInfo;
648     if (objectInfo == nullptr) {
649         NAPI_ERR_LOG("objectInfo is nullptr");
650         return;
651     }
652     auto photoAlbum = objectInfo->GetPhotoAlbumInstance();
653     AlbumCommitModifyReqBody reqBody;
654     reqBody.businessCode = context->businessCode;
655     if (reqBody.businessCode == static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_COMMIT_MODIFY)) {
656         reqBody.albumName = photoAlbum->GetAlbumName();
657         reqBody.albumType = photoAlbum->GetPhotoAlbumType();
658         reqBody.albumSubType = photoAlbum->GetPhotoAlbumSubType();
659     }
660 
661     bool isValid = false;
662     string coverUri = context->valuesBucket.Get(PhotoAlbumColumns::ALBUM_COVER_URI, isValid);
663     reqBody.coverUri = coverUri;
664     if (!isValid) {
665         NAPI_ERR_LOG("CommitModify get coveruri fail.");
666         context->SaveError(changedRows);
667         return;
668     }
669 
670     reqBody.albumId = photoAlbum->GetAlbumId();
671     changedRows = IPC::UserDefineIPCClient().Call(context->businessCode, reqBody);
672     context->SaveError(changedRows);
673     context->changedRows = changedRows;
674 }
675 
JSCommitModifyExecute(napi_env env,void * data)676 static void JSCommitModifyExecute(napi_env env, void *data)
677 {
678     MediaLibraryTracer tracer;
679     tracer.Start("JSCommitModifyExecute");
680 
681     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
682     if (context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) {
683         JSCommitModifyIPCExecute(context);
684         return;
685     }
686 
687     Uri uri(UFM_UPDATE_PHOTO_ALBUM);
688     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
689     context->SaveError(changedRows);
690     context->changedRows = changedRows;
691 }
692 
JSCommitModifyCompleteCallback(napi_env env,napi_status status,void * data)693 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data)
694 {
695     MediaLibraryTracer tracer;
696     tracer.Start("JSCommitModifyCompleteCallback");
697 
698     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
699     auto jsContext = make_unique<JSAsyncContextOutput>();
700     jsContext->status = false;
701     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
702     if (context->error == ERR_DEFAULT) {
703         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
704         jsContext->status = true;
705     } else {
706         context->HandleError(env, jsContext->error);
707     }
708 
709     tracer.Finish();
710     if (context->work != nullptr) {
711         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
712                                                    context->work, *jsContext);
713     }
714     delete context;
715 }
716 
JSCommitModify(napi_env env,napi_callback_info info)717 napi_value PhotoAlbumNapi::JSCommitModify(napi_env env, napi_callback_info info)
718 {
719     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
720     CHECK_NULLPTR_RET(ParseArgsCommitModify(env, info, asyncContext));
721     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
722 
723     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
724         JSCommitModifyCompleteCallback);
725 }
726 
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)727 napi_value PhotoAlbumNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
728 {
729     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
730     CHECK_NULLPTR_RET(ParseArgsCommitModify(env, info, asyncContext));
731     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
732 
733     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
734         JSCommitModifyCompleteCallback);
735 }
736 
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)737 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
738 {
739     bool isArray = false;
740     CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
741     if (!isArray) {
742         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array type");
743         return nullptr;
744     }
745 
746     uint32_t len = 0;
747     CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
748     if (len < 0) {
749         NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
750         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array length");
751         return nullptr;
752     }
753     if (len == 0) {
754         napi_value result = nullptr;
755         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
756         return result;
757     }
758 
759     for (uint32_t i = 0; i < len; i++) {
760         napi_value asset = nullptr;
761         CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
762         if (asset == nullptr) {
763             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset element");
764             return nullptr;
765         }
766 
767         FileAssetNapi *obj = nullptr;
768         CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
769         if (obj == nullptr) {
770             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset napi object");
771             return nullptr;
772         }
773         if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
774             NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
775             continue;
776         }
777         assetsArray.push_back(obj->GetFileUri());
778     }
779 
780     napi_value result = nullptr;
781     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
782     return result;
783 }
784 
ParseArgsAddAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)785 static napi_value ParseArgsAddAssets(napi_env env, napi_callback_info info,
786     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
787 {
788     constexpr size_t minArgs = ARGS_ONE;
789     constexpr size_t maxArgs = ARGS_TWO;
790     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
791         JS_ERR_PARAMETER_INVALID);
792 
793     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
794     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
795         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
796         return nullptr;
797     }
798 
799     /* Parse the first argument */
800     vector<string> assetsArray;
801     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
802     context->assetsArray = assetsArray;
803     if (assetsArray.empty()) {
804         napi_value result = nullptr;
805         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
806         return result;
807     }
808     int32_t albumId = photoAlbum->GetAlbumId();
809     for (const auto &assetId : assetsArray) {
810         DataShareValuesBucket valuesBucket;
811         valuesBucket.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
812         valuesBucket.Put(PhotoColumn::MEDIA_ID, assetId);
813         context->valuesBuckets.push_back(valuesBucket);
814     }
815 
816     napi_value result = nullptr;
817     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
818     return result;
819 }
820 
FetchNewCount(PhotoAlbumNapiAsyncContext * context)821 static int32_t FetchNewCount(PhotoAlbumNapiAsyncContext *context)
822 {
823     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
824         UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
825     Uri qUri(queryUri);
826     int errCode = 0;
827     DataSharePredicates predicates;
828     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, context->objectInfo->GetAlbumId());
829     vector<string> fetchColumn = {
830         PhotoAlbumColumns::ALBUM_ID,
831         PhotoAlbumColumns::ALBUM_COUNT,
832     };
833     bool isSmartAlbum = (context->objectInfo->GetPhotoAlbumType() == PhotoAlbumType::SMART);
834     if (!isSmartAlbum) {
835         fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
836         fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
837     }
838     auto resultSet = UserFileClient::Query(qUri, predicates, fetchColumn, errCode);
839     if (resultSet == nullptr) {
840         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
841         return -1;
842     }
843     if (resultSet->GoToFirstRow() != 0) {
844         NAPI_ERR_LOG("go to first row failed");
845         return -1;
846     }
847     bool hiddenOnly = context->objectInfo->GetHiddenOnly();
848     int imageCount = (hiddenOnly || isSmartAlbum) ? -1 :
849             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT, resultSet, TYPE_INT32));
850     int videoCount = (hiddenOnly || isSmartAlbum) ? -1 :
851             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT, resultSet, TYPE_INT32));
852     context->newCount =
853             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_COUNT, resultSet, TYPE_INT32));
854     context->newImageCount = imageCount;
855     context->newVideoCount = videoCount;
856     return 0;
857 }
858 
JSPhotoAlbumAddAssetsIPCExecute(PhotoAlbumNapiAsyncContext * context)859 static void JSPhotoAlbumAddAssetsIPCExecute(PhotoAlbumNapiAsyncContext *context)
860 {
861     auto objectInfo = context->objectInfo;
862     if (objectInfo == nullptr) {
863         NAPI_ERR_LOG("objectInfo is nullptr");
864         return;
865     }
866     auto photoAlbum = objectInfo->GetPhotoAlbumInstance();
867     if (photoAlbum == nullptr) {
868         NAPI_ERR_LOG("photoAlbum is nullptr");
869         return;
870     }
871     AlbumPhotoQueryRespBody respBody;
872     AlbumAddAssetsReqBody reqBody;
873     reqBody.albumId = photoAlbum->GetAlbumId();
874     reqBody.albumType = photoAlbum->GetPhotoAlbumType();
875     reqBody.albumSubType = photoAlbum->GetPhotoAlbumSubType();
876     reqBody.assetsArray = context->assetsArray;
877     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_ADD_ASSETS);
878 
879     int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
880     if (changedRows < 0) {
881         context->SaveError(changedRows);
882         return;
883     }
884 
885     bool hiddenOnly = objectInfo->GetHiddenOnly();
886     bool isSmartAlbum = photoAlbum->GetPhotoAlbumType() == PhotoAlbumType::SMART;
887 
888     context->changedRows = changedRows;
889     context->newCount = respBody.newCount;
890     context->newImageCount = (hiddenOnly || isSmartAlbum) ? -1 : respBody.newImageCount;
891     context->newVideoCount = (hiddenOnly || isSmartAlbum) ? -1 : respBody.newVideoCount;
892 }
893 
JSPhotoAlbumAddAssetsExecute(napi_env env,void * data)894 static void JSPhotoAlbumAddAssetsExecute(napi_env env, void *data)
895 {
896     MediaLibraryTracer tracer;
897     tracer.Start("JSPhotoAlbumAddAssetsExecute");
898     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
899     if (context->valuesBuckets.empty()) {
900         return;
901     }
902 
903     if (context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) {
904         JSPhotoAlbumAddAssetsIPCExecute(context);
905         return;
906     }
907 
908     Uri uri(UFM_PHOTO_ALBUM_ADD_ASSET);
909     auto changedRows = UserFileClient::BatchInsert(uri, context->valuesBuckets);
910     if (changedRows < 0) {
911         context->SaveError(changedRows);
912         return;
913     }
914     context->changedRows = changedRows;
915     int32_t ret = FetchNewCount(context);
916     if (ret < 0) {
917         NAPI_ERR_LOG("Update count failed");
918         context->SaveError(E_HAS_DB_ERROR);
919     }
920 }
921 
JSPhotoAlbumAddAssetsCompleteCallback(napi_env env,napi_status status,void * data)922 static void JSPhotoAlbumAddAssetsCompleteCallback(napi_env env, napi_status status, void *data)
923 {
924     MediaLibraryTracer tracer;
925     tracer.Start("JSPhotoAlbumAddAssetsCompleteCallback");
926 
927     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
928     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
929     jsContext->status = false;
930     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
931     if (context->error == ERR_DEFAULT) {
932         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
933         jsContext->status = true;
934         context->objectInfo->SetCount(context->newCount);
935         context->objectInfo->SetImageCount(context->newImageCount);
936         context->objectInfo->SetVideoCount(context->newVideoCount);
937     } else {
938         context->HandleError(env, jsContext->error);
939     }
940 
941     tracer.Finish();
942     if (context->work != nullptr) {
943         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
944                                                    context->work, *jsContext);
945     }
946     delete context;
947 }
948 
JSPhotoAlbumAddAssets(napi_env env,napi_callback_info info)949 napi_value PhotoAlbumNapi::JSPhotoAlbumAddAssets(napi_env env, napi_callback_info info)
950 {
951     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
952     CHECK_NULLPTR_RET(ParseArgsAddAssets(env, info, asyncContext));
953     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
954 
955     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumAddAssets",
956         JSPhotoAlbumAddAssetsExecute, JSPhotoAlbumAddAssetsCompleteCallback);
957 }
958 
PhotoAccessHelperAddAssets(napi_env env,napi_callback_info info)959 napi_value PhotoAlbumNapi::PhotoAccessHelperAddAssets(napi_env env, napi_callback_info info)
960 {
961     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
962     CHECK_NULLPTR_RET(ParseArgsAddAssets(env, info, asyncContext));
963     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
964 
965     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumAddAssets",
966         JSPhotoAlbumAddAssetsExecute, JSPhotoAlbumAddAssetsCompleteCallback);
967 }
968 
ParseArgsRemoveAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)969 static napi_value ParseArgsRemoveAssets(napi_env env, napi_callback_info info,
970     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
971 {
972     constexpr size_t minArgs = ARGS_ONE;
973     constexpr size_t maxArgs = ARGS_TWO;
974     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
975         JS_ERR_PARAMETER_INVALID);
976 
977     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
978     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
979         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
980         return nullptr;
981     }
982 
983     /* Parse the first argument */
984     vector<string> assetsArray;
985     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
986     if (assetsArray.empty()) {
987         napi_value result = nullptr;
988         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
989         return result;
990     }
991 
992     context->assetsArray = assetsArray;
993     context->predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
994     context->predicates.And()->In(PhotoColumn::MEDIA_ID, assetsArray);
995 
996     napi_value result = nullptr;
997     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
998     return result;
999 }
1000 
JSPhotoAlbumRemoveAssetsIPCExecute(PhotoAlbumNapiAsyncContext * context)1001 static void JSPhotoAlbumRemoveAssetsIPCExecute(PhotoAlbumNapiAsyncContext *context)
1002 {
1003     auto objectInfo = context->objectInfo;
1004     CHECK_IF_EQUAL(objectInfo != nullptr, "objectInfo is nullptr");
1005     auto photoAlbum = objectInfo->GetPhotoAlbumInstance();
1006     CHECK_IF_EQUAL(photoAlbum != nullptr, "photoAlbum is nullptr");
1007     AlbumPhotoQueryRespBody respBody;
1008     AlbumRemoveAssetsReqBody reqBody;
1009     reqBody.albumId = photoAlbum->GetAlbumId();
1010     reqBody.albumType = photoAlbum->GetPhotoAlbumType();
1011     reqBody.albumSubType = photoAlbum->GetPhotoAlbumSubType();
1012     reqBody.assetsArray = context->assetsArray;
1013     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_REMOVE_ASSETS);
1014 
1015     int32_t deletedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
1016     if (deletedRows < 0) {
1017         NAPI_ERR_LOG("Remove assets failed: %{public}d", deletedRows);
1018         context->SaveError(deletedRows);
1019         return;
1020     }
1021 
1022     bool hiddenOnly = objectInfo->GetHiddenOnly();
1023     bool isSmartAlbum = photoAlbum->GetPhotoAlbumType() == PhotoAlbumType::SMART;
1024 
1025     context->changedRows = deletedRows;
1026     context->newCount = respBody.newCount;
1027     context->newImageCount = (hiddenOnly || isSmartAlbum) ? -1 : respBody.newImageCount;
1028     context->newVideoCount = (hiddenOnly || isSmartAlbum) ? -1 : respBody.newVideoCount;
1029 }
1030 
JSPhotoAlbumRemoveAssetsExecute(napi_env env,void * data)1031 static void JSPhotoAlbumRemoveAssetsExecute(napi_env env, void *data)
1032 {
1033     MediaLibraryTracer tracer;
1034     tracer.Start("JSPhotoAlbumRemoveAssetsExecute");
1035 
1036     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
1037     if (context->predicates.GetOperationList().empty()) {
1038         NAPI_ERR_LOG("Invalid input: operation list is empty");
1039         return;
1040     }
1041 
1042     if (context->resultNapiType != ResultNapiType::TYPE_USERFILE_MGR) {
1043         JSPhotoAlbumRemoveAssetsIPCExecute(context);
1044         return;
1045     }
1046 
1047     Uri uri(UFM_PHOTO_ALBUM_REMOVE_ASSET);
1048     auto deletedRows = UserFileClient::Delete(uri, context->predicates);
1049     if (deletedRows < 0) {
1050         NAPI_ERR_LOG("Remove assets failed: %{public}d", deletedRows);
1051         context->SaveError(deletedRows);
1052         return;
1053     }
1054     context->changedRows = deletedRows;
1055     int32_t ret = FetchNewCount(context);
1056     if (ret < 0) {
1057         NAPI_ERR_LOG("Update count failed");
1058         context->SaveError(E_HAS_DB_ERROR);
1059     }
1060 }
1061 
JSPhotoAlbumRemoveAssetsCompleteCallback(napi_env env,napi_status status,void * data)1062 static void JSPhotoAlbumRemoveAssetsCompleteCallback(napi_env env, napi_status status, void *data)
1063 {
1064     MediaLibraryTracer tracer;
1065     tracer.Start("JSPhotoAlbumRemoveAssetsCompleteCallback");
1066 
1067     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
1068     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1069     jsContext->status = false;
1070     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1071     if (context->error == ERR_DEFAULT) {
1072         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1073         jsContext->status = true;
1074         context->objectInfo->SetCount(context->newCount);
1075         context->objectInfo->SetImageCount(context->newImageCount);
1076         context->objectInfo->SetVideoCount(context->newVideoCount);
1077     } else {
1078         context->HandleError(env, jsContext->error);
1079     }
1080 
1081     tracer.Finish();
1082     if (context->work != nullptr) {
1083         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1084                                                    context->work, *jsContext);
1085     }
1086     delete context;
1087 }
1088 
JSPhotoAlbumRemoveAssets(napi_env env,napi_callback_info info)1089 napi_value PhotoAlbumNapi::JSPhotoAlbumRemoveAssets(napi_env env, napi_callback_info info)
1090 {
1091     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1092     CHECK_NULLPTR_RET(ParseArgsRemoveAssets(env, info, asyncContext));
1093     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1094 
1095     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumRemoveAssets",
1096         JSPhotoAlbumRemoveAssetsExecute, JSPhotoAlbumRemoveAssetsCompleteCallback);
1097 }
1098 
PhotoAccessHelperRemoveAssets(napi_env env,napi_callback_info info)1099 napi_value PhotoAlbumNapi::PhotoAccessHelperRemoveAssets(napi_env env, napi_callback_info info)
1100 {
1101     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1102     CHECK_NULLPTR_RET(ParseArgsRemoveAssets(env, info, asyncContext));
1103     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1104 
1105     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumRemoveAssets",
1106         JSPhotoAlbumRemoveAssetsExecute, JSPhotoAlbumRemoveAssetsCompleteCallback);
1107 }
1108 
NapiGetAnalysisAlbumPredicates(const shared_ptr<PhotoAlbum> & photoAlbum,DataSharePredicates & predicates)1109 static int32_t NapiGetAnalysisAlbumPredicates(const shared_ptr<PhotoAlbum>& photoAlbum,
1110     DataSharePredicates& predicates)
1111 {
1112     PhotoAlbumSubType subType = photoAlbum->GetPhotoAlbumSubType();
1113     if (subType == PhotoAlbumSubType::PORTRAIT || subType == PhotoAlbumSubType::GROUP_PHOTO) {
1114         MediaLibraryNapiUtils::GetPortraitAlbumPredicates(photoAlbum->GetAlbumId(), predicates);
1115         return E_SUCCESS;
1116     }
1117     if (subType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
1118         return MediaLibraryNapiUtils::GetAllLocationPredicates(predicates);
1119     }
1120     if (subType == PhotoAlbumSubType::SHOOTING_MODE) {
1121         ShootingModeAlbumType type {};
1122         if (!ShootingModeAlbum::AlbumNameToShootingModeAlbumType(photoAlbum->GetAlbumName(), type)) {
1123             NAPI_ERR_LOG("Invalid shooting mode album name: %{public}s", photoAlbum->GetAlbumName().c_str());
1124             return E_INVALID_ARGUMENTS;
1125         }
1126         ShootingModeAlbum::GetShootingModeAlbumPredicates(type, predicates, photoAlbum->GetHiddenOnly());
1127         return E_SUCCESS;
1128     }
1129     string albumName = photoAlbum->GetAlbumName();
1130     if (MediaLibraryNapiUtils::IsFeaturedSinglePortraitAlbum(albumName, predicates)) {
1131         return MediaLibraryNapiUtils::GetFeaturedSinglePortraitAlbumPredicates(
1132             photoAlbum->GetAlbumId(), predicates);
1133     }
1134     MediaLibraryNapiUtils::GetAnalysisPhotoMapPredicates(photoAlbum->GetAlbumId(), predicates);
1135     return E_SUCCESS;
1136 }
1137 
GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> & photoAlbum,DataSharePredicates & predicates,const bool hiddenOnly)1138 static int32_t GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> &photoAlbum,
1139     DataSharePredicates &predicates, const bool hiddenOnly)
1140 {
1141     int32_t albumId = photoAlbum->GetAlbumId();
1142     PhotoAlbumSubType subType = photoAlbum->GetPhotoAlbumSubType();
1143     bool isLocationAlbum = subType == PhotoAlbumSubType::GEOGRAPHY_LOCATION;
1144     if (albumId <= 0 && !isLocationAlbum) {
1145         NAPI_ERR_LOG("Invalid album ID");
1146         return E_INVALID_ARGUMENTS;
1147     }
1148     PhotoAlbumType type = photoAlbum->GetPhotoAlbumType();
1149     if ((!PhotoAlbum::CheckPhotoAlbumType(type)) || (!PhotoAlbum::CheckPhotoAlbumSubType(subType))) {
1150         NAPI_ERR_LOG("Invalid album type or subtype: type=%{public}d, subType=%{public}d", static_cast<int>(type),
1151             static_cast<int>(subType));
1152         return E_INVALID_ARGUMENTS;
1153     }
1154 
1155     if (PhotoAlbum::IsUserPhotoAlbum(type, subType)) {
1156         return MediaLibraryNapiUtils::GetUserAlbumPredicates(photoAlbum->GetAlbumId(), predicates, hiddenOnly);
1157     }
1158 
1159     if (PhotoAlbum::IsSourceAlbum(type, subType)) {
1160         return MediaLibraryNapiUtils::GetSourceAlbumPredicates(photoAlbum->GetAlbumId(), predicates, hiddenOnly);
1161     }
1162 
1163     if (type == PhotoAlbumType::SMART) {
1164         return NapiGetAnalysisAlbumPredicates(photoAlbum, predicates);
1165     }
1166 
1167     if (type == PhotoAlbumType::SYSTEM) {
1168         return MediaLibraryNapiUtils::GetSystemAlbumPredicates(subType, predicates, hiddenOnly);
1169     }
1170 
1171     NAPI_ERR_LOG("Invalid album type and subtype: type=%{public}d, subType=%{public}d", static_cast<int>(type),
1172         static_cast<int>(subType));
1173     return E_INVALID_ARGUMENTS;
1174 }
1175 
ParseArgsGetPhotoAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1176 static napi_value ParseArgsGetPhotoAssets(napi_env env, napi_callback_info info,
1177     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1178 {
1179     constexpr size_t minArgs = ARGS_ONE;
1180     constexpr size_t maxArgs = ARGS_TWO;
1181     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1182         JS_ERR_PARAMETER_INVALID);
1183 
1184     /* Parse the first argument */
1185     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
1186         JS_INNER_FAIL);
1187 
1188     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1189     auto ret = GetPredicatesByAlbumTypes(photoAlbum, context->predicates, photoAlbum->GetHiddenOnly());
1190     if (ret != E_SUCCESS) {
1191         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
1192         return nullptr;
1193     }
1194     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
1195         PhotoColumn::IsPhotoColumn, NapiAssetType::TYPE_PHOTO));
1196     if (photoAlbum->GetHiddenOnly() || photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::HIDDEN) {
1197         if (!MediaLibraryNapiUtils::IsSystemApp()) {
1198             NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1199             return nullptr;
1200         }
1201         context->isSystemApi = true;
1202         // sort by hidden time desc if is hidden asset
1203         context->predicates.IndexedBy(PhotoColumn::PHOTO_HIDDEN_TIME_INDEX);
1204     }
1205 
1206     napi_value result = nullptr;
1207     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1208     return result;
1209 }
1210 
JSGetPhotoAssetsExecute(napi_env env,void * data)1211 static void JSGetPhotoAssetsExecute(napi_env env, void *data)
1212 {
1213     MediaLibraryTracer tracer;
1214     tracer.Start("JSGetPhotoAssetsExecute");
1215 
1216     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1217     string queryUri = UFM_QUERY_PHOTO_MAP;
1218     Uri uri(queryUri);
1219     int32_t errCode = 0;
1220     std::vector<DataShare::OperationItem> operationItems = context->predicates.GetOperationList();
1221     for (DataShare::OperationItem item : operationItems) {
1222         if (item.operation == DataShare::OperationType::GROUP_BY) {
1223             context->fetchColumn.insert(context->fetchColumn.begin(), COUNT_GROUP_BY);
1224         }
1225     }
1226     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
1227     if (resultSet == nullptr) {
1228         context->SaveError(E_HAS_DB_ERROR);
1229         return;
1230     }
1231     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1232     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1233 }
1234 
IsFeaturedSinglePortraitAlbum(const shared_ptr<PhotoAlbum> & photoAlbum)1235 static bool IsFeaturedSinglePortraitAlbum(const shared_ptr<PhotoAlbum>& photoAlbum)
1236 {
1237     constexpr int portraitAlbumId = 0;
1238     return photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::CLASSIFY &&
1239         photoAlbum->GetAlbumName().compare(to_string(portraitAlbumId)) == 0;
1240 }
1241 
ConvertColumnsForPortrait(PhotoAlbumNapiAsyncContext * context)1242 static void ConvertColumnsForPortrait(PhotoAlbumNapiAsyncContext *context)
1243 {
1244     if (context == nullptr || context->objectInfo == nullptr) {
1245         NAPI_ERR_LOG("context is null or PhotoAlbumNapi is null");
1246         return;
1247     }
1248 
1249     shared_ptr<PhotoAlbum> photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1250     if (photoAlbum == nullptr || (photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::PORTRAIT &&
1251         photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::GROUP_PHOTO &&
1252         !IsFeaturedSinglePortraitAlbum(photoAlbum))) {
1253         return;
1254     }
1255 
1256     for (size_t i = 0; i < context->fetchColumn.size(); i++) {
1257         if (context->fetchColumn[i] != "count(*)") {
1258             context->fetchColumn[i] = PhotoColumn::PHOTOS_TABLE + "." + context->fetchColumn[i];
1259         }
1260     }
1261 }
1262 
JSPhotoAccessGetPhotoAssetsExecute(napi_env env,void * data)1263 static void JSPhotoAccessGetPhotoAssetsExecute(napi_env env, void *data)
1264 {
1265     MediaLibraryTracer tracer;
1266     tracer.Start("JSPhotoAccessGetPhotoAssetsExecute");
1267 
1268     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1269     CHECK_IF_EQUAL(context != nullptr, "context is nullptr");
1270     Uri uri(PAH_QUERY_PHOTO_MAP);
1271     ConvertColumnsForPortrait(context);
1272     int32_t errCode = 0;
1273     int32_t userId = -1;
1274     if (context->objectInfo != nullptr) {
1275         shared_ptr<PhotoAlbum> photoAlbum =  context->objectInfo->GetPhotoAlbumInstance();
1276         if (photoAlbum != nullptr) {
1277             userId = photoAlbum->GetUserId();
1278         }
1279     }
1280     auto [accessSandbox, resultSet] =
1281         UserFileClient::QueryAccessibleViaSandBox(uri, context->predicates, context->fetchColumn, errCode, userId);
1282     if (accessSandbox) {
1283         if (resultSet == nullptr) {
1284             NAPI_ERR_LOG("QueryAccessibleViaSandBox failed, resultSet is nullptr");
1285         }
1286     } else {
1287         AlbumGetAssetsReqBody reqBody;
1288         reqBody.predicates = context->predicates;
1289         reqBody.columns = context->fetchColumn;
1290         AlbumGetAssetsRespBody respBody;
1291         uint32_t businessCode = context->isSystemApi
1292                                     ? static_cast<uint32_t>(MediaLibraryBusinessCode::ALBUM_SYS_GET_ASSETS)
1293                                     : static_cast<uint32_t>(MediaLibraryBusinessCode::ALBUM_GET_ASSETS);
1294         errCode = IPC::UserDefineIPCClient().SetUserId(userId).Call(businessCode, reqBody, respBody);
1295         if (errCode == E_OK) {
1296             resultSet = respBody.resultSet;
1297         } else {
1298             NAPI_ERR_LOG("UserDefineIPCClient Call failed, errCode is %{public}d", errCode);
1299         }
1300     }
1301 
1302     if (resultSet == nullptr) {
1303         context->SaveError(E_HAS_DB_ERROR);
1304         return;
1305     }
1306     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1307     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1308     context->fetchResult->SetUserId(userId);
1309 }
1310 
JSPhotoAccessGetPhotoAssetsExecuteSync(napi_env env,PhotoAlbumNapiAsyncContext & asyncContext)1311 static napi_value JSPhotoAccessGetPhotoAssetsExecuteSync(napi_env env, PhotoAlbumNapiAsyncContext& asyncContext)
1312 {
1313     auto context = &asyncContext;
1314     Uri uri(PAH_QUERY_PHOTO_MAP);
1315     ConvertColumnsForPortrait(context);
1316     int32_t errCode = 0;
1317     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
1318     CHECK_NULLPTR_RET(resultSet);
1319     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1320     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1321 
1322     std::vector<std::unique_ptr<FileAsset>> fileAssetArray;
1323     auto file = fetchResult->GetFirstObject();
1324     while (file != nullptr) {
1325         fileAssetArray.push_back(move(file));
1326         file = fetchResult->GetNextObject();
1327     }
1328     napi_value jsFileArray = nullptr;
1329     size_t len = fileAssetArray.size();
1330     napi_create_array_with_length(env, len, &jsFileArray);
1331     size_t i = 0;
1332     int32_t userId = -1;
1333     if (context->objectInfo != nullptr) {
1334         shared_ptr<PhotoAlbum> photoAlbum =  context->objectInfo->GetPhotoAlbumInstance();
1335         if (photoAlbum != nullptr) {
1336             userId = photoAlbum->GetUserId();
1337         }
1338     }
1339     for (i = 0; i < len; i++) {
1340         fileAssetArray[i]->SetUserId(userId);
1341         napi_value jsFileAsset = FileAssetNapi::CreateFileAsset(env, fileAssetArray[i]);
1342         if ((jsFileAsset == nullptr) || (napi_set_element(env, jsFileArray, i, jsFileAsset) != napi_ok)) {
1343             NAPI_ERR_LOG("Failed to get file asset napi object");
1344             break;
1345         }
1346     }
1347     return (i == len) ? jsFileArray : nullptr;
1348 }
1349 
GetPhotoMapQueryResult(napi_env env,PhotoAlbumNapiAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1350 static void GetPhotoMapQueryResult(napi_env env, PhotoAlbumNapiAsyncContext *context,
1351     unique_ptr<JSAsyncContextOutput> &jsContext)
1352 {
1353     napi_value fetchRes = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchResult));
1354     if (fetchRes == nullptr) {
1355         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1356             "Failed to create js object for FetchFileResult");
1357         return;
1358     }
1359     jsContext->data = fetchRes;
1360     jsContext->status = true;
1361 }
1362 
JSGetPhotoAssetsCallbackComplete(napi_env env,napi_status status,void * data)1363 static void JSGetPhotoAssetsCallbackComplete(napi_env env, napi_status status, void *data)
1364 {
1365     MediaLibraryTracer tracer;
1366     tracer.Start("JSGetPhotoAssetsCallbackComplete");
1367 
1368     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1369 
1370     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1371     jsContext->status = false;
1372 
1373     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1374     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1375     if (context->fetchResult != nullptr) {
1376         GetPhotoMapQueryResult(env, context, jsContext);
1377     } else {
1378         NAPI_ERR_LOG("No fetch file result found!");
1379         context->HandleError(env, jsContext->error);
1380     }
1381 
1382     tracer.Finish();
1383     if (context->work != nullptr) {
1384         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1385                                                    context->work, *jsContext);
1386     }
1387     delete context;
1388 }
1389 
JSGetPhotoAssets(napi_env env,napi_callback_info info)1390 napi_value PhotoAlbumNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
1391 {
1392     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1393     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1394 
1395     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", JSGetPhotoAssetsExecute,
1396         JSGetPhotoAssetsCallbackComplete);
1397 }
1398 
JSPhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)1399 napi_value PhotoAlbumNapi::JSPhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
1400 {
1401     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1402     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1403 
1404     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
1405         JSPhotoAccessGetPhotoAssetsExecute, JSGetPhotoAssetsCallbackComplete);
1406 }
1407 
JSPhotoAccessGetPhotoAssetsSync(napi_env env,napi_callback_info info)1408 napi_value PhotoAlbumNapi::JSPhotoAccessGetPhotoAssetsSync(napi_env env, napi_callback_info info)
1409 {
1410     MediaLibraryTracer tracer;
1411     tracer.Start("JSPhotoAccessGetPhotoAssetsSync");
1412 
1413     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1414     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1415     return JSPhotoAccessGetPhotoAssetsExecuteSync(env, *asyncContext);
1416 }
1417 
TrashAlbumParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1418 static napi_value TrashAlbumParseArgs(napi_env env, napi_callback_info info,
1419     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1420 {
1421     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1422         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1423         return nullptr;
1424     }
1425 
1426     napi_value result = nullptr;
1427     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1428     constexpr size_t minArgs = ARGS_ONE;
1429     constexpr size_t maxArgs = ARGS_TWO;
1430     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1431         JS_ERR_PARAMETER_INVALID);
1432     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1433     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
1434         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
1435         return nullptr;
1436     }
1437 
1438     /* Parse the first argument */
1439     vector<napi_value> napiValues;
1440     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM0], napiValues));
1441     if (napiValues.empty()) {
1442         return result;
1443     }
1444     napi_valuetype valueType = napi_undefined;
1445     vector<string> uris;
1446     CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_ERR_PARAMETER_INVALID);
1447     if (valueType == napi_string) {
1448         // The input should be an array of asset uri.
1449         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetStringArray(env, napiValues, uris));
1450     } else if (valueType == napi_object) {
1451         // The input should be an array of asset object.
1452         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uris));
1453     }
1454     if (uris.empty()) {
1455         return result;
1456     }
1457 
1458     context->uris = uris;
1459     context->predicates.In(MediaColumn::MEDIA_ID, uris);
1460     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
1461 
1462     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1463     return result;
1464 }
1465 
TrashAlbumExecute(const TrashAlbumExecuteOpt & opt)1466 static void TrashAlbumExecute(const TrashAlbumExecuteOpt &opt)
1467 {
1468     MediaLibraryTracer tracer;
1469     tracer.Start(opt.tracerLabel);
1470 
1471     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(opt.data);
1472     if (context->predicates.GetOperationList().empty()) {
1473         NAPI_ERR_LOG("Operation list is empty.");
1474         return;
1475     }
1476     Uri uri(opt.uri);
1477     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
1478     if (changedRows < 0) {
1479         context->SaveError(changedRows);
1480         NAPI_ERR_LOG("Trash album executed, changeRows: %{public}d.", changedRows);
1481         return;
1482     }
1483     context->changedRows = changedRows;
1484 }
1485 
TrashAlbumComplete(napi_env env,napi_status status,void * data)1486 static void TrashAlbumComplete(napi_env env, napi_status status, void *data)
1487 {
1488     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
1489     auto jsContext = make_unique<JSAsyncContextOutput>();
1490     jsContext->status = false;
1491     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1492     if (context->error == ERR_DEFAULT) {
1493         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1494         jsContext->status = true;
1495     } else {
1496         context->HandleError(env, jsContext->error);
1497     }
1498 
1499     if (context->work != nullptr) {
1500         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1501                                                    context->work, *jsContext);
1502     }
1503     delete context;
1504 }
1505 
RecoverPhotosExecute(napi_env env,void * data)1506 static void RecoverPhotosExecute(napi_env env, void *data)
1507 {
1508     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1509     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1510         TrashAlbumExecuteOpt opt = {
1511             .env = env,
1512             .data = data,
1513             .tracerLabel = "RecoverPhotosExecute",
1514             .uri = UFM_RECOVER_PHOTOS,
1515         };
1516         TrashAlbumExecute(opt);
1517         return;
1518     }
1519 
1520     AlbumRecoverAssetsReqBody reqBody;
1521     CHECK_IF_EQUAL(context->objectInfo != nullptr, "context->objectInfo is nullptr");
1522     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1523     CHECK_IF_EQUAL(photoAlbum != nullptr, "photoAlbum is nullptr");
1524     reqBody.albumType = photoAlbum->GetPhotoAlbumType();
1525     reqBody.albumSubType = photoAlbum->GetPhotoAlbumSubType();
1526     reqBody.uris = context->uris;
1527     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_RECOVER_ASSETS);
1528 
1529     int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
1530     if (changedRows < 0) {
1531         context->SaveError(changedRows);
1532         NAPI_ERR_LOG("changeRows: %{public}d.", changedRows);
1533         return;
1534     }
1535     context->changedRows = changedRows;
1536 }
1537 
RecoverPhotosComplete(napi_env env,napi_status status,void * data)1538 static void RecoverPhotosComplete(napi_env env, napi_status status, void *data)
1539 {
1540     TrashAlbumComplete(env, status, data);
1541 }
1542 
JSRecoverPhotos(napi_env env,napi_callback_info info)1543 napi_value PhotoAlbumNapi::JSRecoverPhotos(napi_env env, napi_callback_info info)
1544 {
1545     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1546     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1547     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1548 
1549     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRecoverPhotos", RecoverPhotosExecute,
1550         RecoverPhotosComplete);
1551 }
1552 
PrivateAlbumParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1553 static napi_value PrivateAlbumParseArgs(napi_env env, napi_callback_info info,
1554     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1555 {
1556     string uri;
1557     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
1558         JS_ERR_PARAMETER_INVALID);
1559     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1560     if (photoAlbum == nullptr) {
1561         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get photo album instance");
1562         return nullptr;
1563     }
1564     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
1565         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
1566         return nullptr;
1567     }
1568 
1569     context->predicates.EqualTo(MediaColumn::MEDIA_ID, MediaFileUtils::GetIdFromUri(uri));
1570     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
1571 
1572     napi_value result = nullptr;
1573     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1574     return result;
1575 }
1576 
PrivateAlbumRecoverPhotos(napi_env env,napi_callback_info info)1577 napi_value PhotoAlbumNapi::PrivateAlbumRecoverPhotos(napi_env env, napi_callback_info info)
1578 {
1579     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1580     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1581     CHECK_NULLPTR_RET(PrivateAlbumParseArgs(env, info, asyncContext));
1582 
1583     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PrivateAlbumRecoverPhotos",
1584         RecoverPhotosExecute, RecoverPhotosComplete);
1585 }
1586 
PhotoAccessHelperRecoverPhotos(napi_env env,napi_callback_info info)1587 napi_value PhotoAlbumNapi::PhotoAccessHelperRecoverPhotos(napi_env env, napi_callback_info info)
1588 {
1589     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1590     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1591     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1592 
1593     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRecoverPhotos", RecoverPhotosExecute,
1594         RecoverPhotosComplete);
1595 }
1596 
DeletePhotosExecute(napi_env env,void * data)1597 static void DeletePhotosExecute(napi_env env, void *data)
1598 {
1599     TrashAlbumExecuteOpt opt = {
1600         .env = env,
1601         .data = data,
1602         .tracerLabel = "DeletePhotosExecute",
1603         .uri = (static_cast<PhotoAlbumNapiAsyncContext *>(data)->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1604             UFM_DELETE_PHOTOS : PAH_DELETE_PHOTOS,
1605     };
1606     TrashAlbumExecute(opt);
1607 }
1608 
DeletePhotosComplete(napi_env env,napi_status status,void * data)1609 static void DeletePhotosComplete(napi_env env, napi_status status, void *data)
1610 {
1611     TrashAlbumComplete(env, status, data);
1612 }
1613 
JSDeletePhotos(napi_env env,napi_callback_info info)1614 napi_value PhotoAlbumNapi::JSDeletePhotos(napi_env env, napi_callback_info info)
1615 {
1616     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1617     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1618     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1619 
1620     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeletePhotos", DeletePhotosExecute,
1621         DeletePhotosComplete);
1622 }
1623 
PrivateAlbumDeletePhotos(napi_env env,napi_callback_info info)1624 napi_value PhotoAlbumNapi::PrivateAlbumDeletePhotos(napi_env env, napi_callback_info info)
1625 {
1626     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1627     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1628     CHECK_NULLPTR_RET(PrivateAlbumParseArgs(env, info, asyncContext));
1629 
1630     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PrivateAlbumDeletePhotos",
1631         DeletePhotosExecute, DeletePhotosComplete);
1632 }
1633 
DeletePhotosParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1634 static napi_value DeletePhotosParseArgs(
1635     napi_env env, napi_callback_info info, unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1636 {
1637     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1638         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1639         return nullptr;
1640     }
1641 
1642     napi_value result = nullptr;
1643     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1644     constexpr size_t minArgs = ARGS_ONE;
1645     constexpr size_t maxArgs = ARGS_TWO;
1646     CHECK_ARGS(env,
1647         MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1648         JS_ERR_PARAMETER_INVALID);
1649     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1650     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
1651         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
1652         return nullptr;
1653     }
1654 
1655     /* Parse the first argument */
1656     vector<napi_value> napiValues;
1657     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM0], napiValues));
1658     if (napiValues.empty()) {
1659         return result;
1660     }
1661     napi_valuetype valueType = napi_undefined;
1662     CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_ERR_PARAMETER_INVALID);
1663     vector<string> uris;
1664     if (valueType == napi_string) {
1665         // The input should be an array of asset uri.
1666         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetStringArray(env, napiValues, uris));
1667     } else if (valueType == napi_object) {
1668         // The input should be an array of asset object.
1669         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uris));
1670     }
1671     if (uris.empty()) {
1672         return result;
1673     }
1674     context->uris = uris;
1675 
1676     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1677     return result;
1678 }
1679 
PahDeletePhotosExecute(napi_env env,void * data)1680 static void PahDeletePhotosExecute(napi_env env, void *data)
1681 {
1682     MediaLibraryTracer tracer;
1683     tracer.Start("DeletePhotosExecute");
1684 
1685     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1686     CHECK_NULL_PTR_RETURN_VOID(context, "context is null");
1687     CHECK_IF_EQUAL(!context->uris.empty(), "uris is empty");
1688 
1689     DeletePhotosReqBody reqBody;
1690     reqBody.uris = context->uris;
1691     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_DELETE_PHOTOS);
1692     int32_t changedRows = IPC::UserDefineIPCClient().Call(businessCode, reqBody);
1693     if (changedRows < 0) {
1694         context->SaveError(changedRows);
1695         NAPI_ERR_LOG("pah delete photos executed, changeRows: %{public}d.", changedRows);
1696         return;
1697     }
1698     context->changedRows = changedRows;
1699 }
1700 
PhotoAccessHelperDeletePhotos(napi_env env,napi_callback_info info)1701 napi_value PhotoAlbumNapi::PhotoAccessHelperDeletePhotos(napi_env env, napi_callback_info info)
1702 {
1703     NAPI_INFO_LOG("enter");
1704     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1705     CHECK_NULLPTR_RET(DeletePhotosParseArgs(env, info, asyncContext));
1706     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1707 
1708     return MediaLibraryNapiUtils::NapiCreateAsyncWork(
1709         env, asyncContext, "JSDeletePhotos", PahDeletePhotosExecute, DeletePhotosComplete);
1710 }
1711 
ParseArgsSetCoverUri(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1712 static napi_value ParseArgsSetCoverUri(napi_env env, napi_callback_info info,
1713     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1714 {
1715     string coverUri;
1716     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, coverUri),
1717         JS_ERR_PARAMETER_INVALID);
1718     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1719     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1720         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Only system apps can update album cover");
1721         return nullptr;
1722     }
1723 
1724     context->businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::PAH_SET_COVER_URI);
1725     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
1726     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, coverUri);
1727 
1728     napi_value result = nullptr;
1729     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1730     return result;
1731 }
1732 
PhotoAccessHelperSetCoverUri(napi_env env,napi_callback_info info)1733 napi_value PhotoAlbumNapi::PhotoAccessHelperSetCoverUri(napi_env env, napi_callback_info info)
1734 {
1735     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1736     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1737     CHECK_NULLPTR_RET(ParseArgsSetCoverUri(env, info, asyncContext));
1738 
1739     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
1740         JSCommitModifyCompleteCallback);
1741 }
1742 
PhotoAccessHelperGetFaceIdExec(napi_env env,void * data)1743 static void PhotoAccessHelperGetFaceIdExec(napi_env env, void *data)
1744 {
1745     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1746     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1747 
1748     auto *objectInfo = context->objectInfo;
1749     CHECK_NULL_PTR_RETURN_VOID(objectInfo, "objectInfo is null");
1750 
1751     auto photoAlbumInstance = objectInfo->GetPhotoAlbumInstance();
1752     CHECK_NULL_PTR_RETURN_VOID(photoAlbumInstance, "photoAlbumInstance is null");
1753 
1754     PhotoAlbumSubType albumSubType = photoAlbumInstance->GetPhotoAlbumSubType();
1755     if (albumSubType != PhotoAlbumSubType::PORTRAIT && albumSubType != PhotoAlbumSubType::GROUP_PHOTO) {
1756         NAPI_WARN_LOG("albumSubType: %{public}d, not support getFaceId", albumSubType);
1757         return;
1758     }
1759 
1760     GetFaceIdReqBody reqBody;
1761     GetFaceIdRespBody respBody;
1762     reqBody.albumId = objectInfo->GetAlbumId();
1763     reqBody.albumSubType = static_cast<int32_t>(albumSubType);
1764     uint32_t businessCode = static_cast<uint32_t>(MediaLibraryBusinessCode::GET_FACE_ID);
1765     int32_t ret = IPC::UserDefineIPCClient().Call(businessCode, reqBody, respBody);
1766     if (ret < 0) {
1767         if (ret == E_PERMISSION_DENIED) {
1768             context->error = OHOS_PERMISSION_DENIED_CODE;
1769         } else {
1770             context->SaveError(E_FAIL);
1771         }
1772         NAPI_ERR_LOG("get face id failed, errCode is %{public}d", ret);
1773         return;
1774     }
1775     NAPI_INFO_LOG("respBody.groupTag: %{public}s", respBody.groupTag.c_str());
1776     context->faceTag = respBody.groupTag;
1777 }
1778 
GetFaceIdCompleteCallback(napi_env env,napi_status status,void * data)1779 static void GetFaceIdCompleteCallback(napi_env env, napi_status status, void *data)
1780 {
1781     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1782     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1783     auto jsContext = make_unique<JSAsyncContextOutput>();
1784     jsContext->status = false;
1785 
1786     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1787     if (context->error != ERR_DEFAULT) {
1788         context->HandleError(env, jsContext->error);
1789     } else {
1790         CHECK_ARGS_RET_VOID(env,
1791             napi_create_string_utf8(env, context->faceTag.c_str(), NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
1792         jsContext->status = true;
1793     }
1794 
1795     if (context->work != nullptr) {
1796         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work,
1797             *jsContext);
1798     }
1799     delete context;
1800 }
1801 
PhotoAccessHelperGetFaceId(napi_env env,napi_callback_info info)1802 napi_value PhotoAlbumNapi::PhotoAccessHelperGetFaceId(napi_env env, napi_callback_info info)
1803 {
1804     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1805         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get the Face ID of the album");
1806         return nullptr;
1807     }
1808 
1809     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1810 
1811     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, 0, 0),
1812         JS_ERR_PARAMETER_INVALID);
1813 
1814     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSAnalysisAlbumGetFaceId",
1815         PhotoAccessHelperGetFaceIdExec, GetFaceIdCompleteCallback);
1816 }
1817 
JSPhotoAccessGetSharedPhotoAssets(napi_env env,napi_callback_info info)1818 napi_value PhotoAlbumNapi::JSPhotoAccessGetSharedPhotoAssets(napi_env env, napi_callback_info info)
1819 {
1820     MediaLibraryTracer tracer;
1821     tracer.Start("JSPhotoAccessGetSharedPhotoAssets");
1822     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext =
1823         make_unique<PhotoAlbumNapiAsyncContext>();
1824     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1825 
1826     PhotoAlbumNapiAsyncContext* context =
1827         static_cast<PhotoAlbumNapiAsyncContext*>((asyncContext.get()));
1828 
1829     Uri uri(PAH_QUERY_PHOTO_MAP);
1830     ConvertColumnsForPortrait(context);
1831     shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
1832         context->predicates, context->fetchColumn);
1833     CHECK_NULLPTR_RET(resultSet);
1834 
1835     napi_value jsFileArray = 0;
1836     napi_create_array(env, &jsFileArray);
1837 
1838     int count = 0;
1839     int err = resultSet->GoToFirstRow();
1840     if (err != napi_ok) {
1841         NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
1842         return jsFileArray;
1843     }
1844     do {
1845         napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet, true);
1846         napi_set_element(env, jsFileArray, count++, item);
1847     } while (!resultSet->GoToNextRow());
1848     resultSet->Close();
1849     return jsFileArray;
1850 }
1851 } // namespace OHOS::Media
1852