• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 #include "photo_album_ani.h"
17 
18 #include "ani_class_name.h"
19 #include "fetch_result_ani.h"
20 #include "file_asset_ani.h"
21 #include "media_file_utils.h"
22 #include "media_library_enum_ani.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_ani_log.h"
25 #include "medialibrary_ani_utils.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 "shooting_mode_column.h"
32 
33 using namespace std;
34 using namespace OHOS::DataShare;
35 
36 namespace OHOS::Media {
37 
38 struct PhotoAlbumAttributes {
39     PhotoAlbumType albumType;
40     PhotoAlbumSubType albumSubtype;
41     std::string albumName;
42     std::string albumUri;
43     int32_t count;
44     std::string coverUri;
45 };
46 
47 thread_local PhotoAlbum *PhotoAlbumAni::pAlbumData_ = nullptr;
48 
PhotoAlbumAni()49 PhotoAlbumAni::PhotoAlbumAni() : env_(nullptr) {}
50 
51 PhotoAlbumAni::~PhotoAlbumAni() = default;
52 
PhotoAccessInit(ani_env * env)53 ani_status PhotoAlbumAni::PhotoAccessInit(ani_env *env)
54 {
55     ani_class cls;
56     if (ANI_OK != env->FindClass(PAH_ANI_CLASS_PHOTO_ALBUM_HANDLE.c_str(), &cls)) {
57         ANI_ERR_LOG("Failed to find class: %{public}s", PAH_ANI_CLASS_PHOTO_ALBUM_HANDLE.c_str());
58         return ANI_ERROR;
59     }
60 
61     std::array methods = {
62         ani_native_function {"getAssetsInner", nullptr, reinterpret_cast<void *>(PhotoAccessGetPhotoAssets)},
63         ani_native_function {"getAssetsSync", nullptr, reinterpret_cast<void *>(PhotoAccessGetPhotoAssetsSync)},
64         ani_native_function {"commitModifyInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperCommitModify)},
65         ani_native_function {"addAssetsInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperAddAssets)},
66         ani_native_function {"removeAssetsInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperRemoveAssets)},
67         ani_native_function {"recoverAssetsInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperRecoverPhotos)},
68         ani_native_function {"deleteAssetsInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperDeletePhotos)},
69         ani_native_function {"setCoverUriInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperSetCoverUri)},
70         ani_native_function {"getFaceIdInner", nullptr, reinterpret_cast<void *>(PhotoAccessHelperGetFaceId)},
71         ani_native_function {"getImageCount", nullptr, reinterpret_cast<void *>(GetImageCount)},
72         ani_native_function {"getVideoCount", nullptr, reinterpret_cast<void *>(GetVideoCount)},
73     };
74 
75     if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
76         ANI_ERR_LOG("Failed to bind native methods to: %{public}s", PAH_ANI_CLASS_PHOTO_ALBUM_HANDLE.c_str());
77         return ANI_ERROR;
78     }
79 
80     ANI_INFO_LOG("PhotoAccessInit ok");
81     return ANI_OK;
82 }
83 
CreatePhotoAlbumAni(ani_env * env,std::unique_ptr<PhotoAlbum> & albumData)84 ani_object PhotoAlbumAni::CreatePhotoAlbumAni(ani_env *env, std::unique_ptr<PhotoAlbum> &albumData)
85 {
86     if (albumData == nullptr) {
87         return nullptr;
88     }
89 
90     ani_class cls {};
91     if (albumData->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
92         CHECK_COND_RET(MediaLibraryAniUtils::FindClass(env, PAH_ANI_CLASS_PHOTO_ALBUM_HANDLE, &cls) == ANI_OK,
93             nullptr, "Can't find class");
94     } else {
95         CHECK_COND_RET(MediaLibraryAniUtils::FindClass(env, UFM_ANI_CLASS_PHOTO_ALBUM_HANDLE, &cls) == ANI_OK,
96             nullptr, "Can't find class");
97     }
98 
99     pAlbumData_ = albumData.release();
100     ani_object result = PhotoAlbumAniConstructor(env, cls);
101     pAlbumData_ = nullptr;
102     return result;
103 }
104 
CreatePhotoAlbumAni(ani_env * env,std::shared_ptr<PhotoAlbum> & albumData)105 ani_object PhotoAlbumAni::CreatePhotoAlbumAni(ani_env *env, std::shared_ptr<PhotoAlbum> &albumData)
106 {
107     if (albumData == nullptr || albumData->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
108         ANI_ERR_LOG("Unsupported photo album data");
109         return nullptr;
110     }
111 
112     ani_class cls {};
113     CHECK_COND_RET(MediaLibraryAniUtils::FindClass(env, PAH_ANI_CLASS_PHOTO_ALBUM_HANDLE, &cls) == ANI_OK,
114         nullptr, "Can't find class");
115 
116     ani_object result = PhotoAlbumAniConstructor(env, cls);
117     PhotoAlbumAni *photoAlbumAni = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, result);
118     CHECK_COND_RET(photoAlbumAni != nullptr, nullptr, "PhotoAlbumAni is nullptr");
119     photoAlbumAni->photoAlbumPtr = albumData;
120     return result;
121 }
122 
UnwrapPhotoAlbumObject(ani_env * env,ani_object object)123 PhotoAlbumAni* PhotoAlbumAni::UnwrapPhotoAlbumObject(ani_env *env, ani_object object)
124 {
125     ani_long photoAlbum {};
126     if (ANI_OK != env->Object_GetFieldByName_Long(object, "nativePhotoAlbum", &photoAlbum)) {
127         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
128         return nullptr;
129     }
130     return reinterpret_cast<PhotoAlbumAni*>(photoAlbum);
131 }
132 
GetPhotoAlbumInstance() const133 std::shared_ptr<PhotoAlbum> PhotoAlbumAni::GetPhotoAlbumInstance() const
134 {
135     return photoAlbumPtr;
136 }
137 
SetPhotoAlbumAniProperties()138 void PhotoAlbumAni::SetPhotoAlbumAniProperties()
139 {
140     photoAlbumPtr = shared_ptr<PhotoAlbum>(pAlbumData_);
141 }
142 
GetPhotoAlbumAttributes(ani_env * env,ani_object object,PhotoAlbumAttributes & attrs)143 static ani_status GetPhotoAlbumAttributes(ani_env *env, ani_object object, PhotoAlbumAttributes &attrs)
144 {
145     PhotoAlbumAni *photoAlbumAni = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
146     CHECK_COND_RET(photoAlbumAni != nullptr, ANI_ERROR, "PhotoAlbumAni is nullptr");
147     auto photoAlbum = photoAlbumAni->GetPhotoAlbumInstance();
148     CHECK_COND_RET(photoAlbum != nullptr, ANI_ERROR, "PhotoAlbum is nullptr");
149 
150     attrs.albumType = photoAlbum->GetPhotoAlbumType();
151     attrs.albumSubtype = photoAlbum->GetPhotoAlbumSubType();
152     attrs.albumName = photoAlbum->GetAlbumName();
153     attrs.albumUri = photoAlbum->GetAlbumUri();
154     attrs.count = photoAlbum->GetCount();
155     attrs.coverUri = photoAlbum->GetCoverUri();
156     return ANI_OK;
157 }
158 
BindAniAttributes(ani_env * env,ani_class cls,ani_object object)159 static ani_status BindAniAttributes(ani_env *env, ani_class cls, ani_object object)
160 {
161     PhotoAlbumAttributes attrs;
162     CHECK_STATUS_RET(GetPhotoAlbumAttributes(env, object, attrs), "GetPhotoAlbumAttributes fail");
163 
164     ani_method albumTypeSetter {};
165     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>albumType", nullptr, &albumTypeSetter), "No <set>albumType");
166     ani_enum_item albumType = 0;
167     CHECK_STATUS_RET(MediaLibraryEnumAni::ToAniEnum(env, attrs.albumType, albumType), "Get albumType index fail");
168     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, albumTypeSetter, albumType), "<set>albumType fail");
169 
170     ani_method albumSubtypeSetter {};
171     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>albumSubtype", nullptr, &albumSubtypeSetter), "No <set>subtype");
172     ani_enum_item albumSubtype = 0;
173     CHECK_STATUS_RET(MediaLibraryEnumAni::ToAniEnum(env, attrs.albumSubtype, albumSubtype),
174         "Get albumSubtype index fail");
175     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, albumSubtypeSetter, albumSubtype), "<set>albumType fail");
176 
177     ani_method albumNameSetter {};
178     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>albumName", nullptr, &albumNameSetter), "No <set>albumName");
179     ani_string albumName {};
180     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.albumName, albumName), "ToAniString albumName fail");
181     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, albumNameSetter, albumName), "<set>albumName fail");
182 
183     ani_method albumUriSetter {};
184     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>albumUri", nullptr, &albumUriSetter), "No <set>albumUri");
185     ani_string albumUri {};
186     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.albumUri, albumUri), "ToAniString albumUri fail");
187     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, albumUriSetter, albumUri), "<set>albumUri fail");
188 
189     ani_method countSetter {};
190     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>count", nullptr, &countSetter), "No <set>count");
191     ani_double count = static_cast<ani_double>(attrs.count);
192     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, countSetter, count), "<set>count fail");
193 
194     ani_method coverUriSetter {};
195     CHECK_STATUS_RET(env->Class_FindMethod(cls, "<set>coverUri", nullptr, &coverUriSetter), "No <set>coverUri");
196     ani_string coverUri {};
197     CHECK_STATUS_RET(MediaLibraryAniUtils::ToAniString(env, attrs.coverUri, coverUri), "ToAniString coverUri fail");
198     CHECK_STATUS_RET(env->Object_CallMethod_Void(object, coverUriSetter, coverUri), "<set>coverUri fail");
199     return ANI_OK;
200 }
201 
PhotoAlbumAniConstructor(ani_env * env,ani_class clazz)202 ani_object PhotoAlbumAni::PhotoAlbumAniConstructor(ani_env *env, ani_class clazz)
203 {
204     ani_method ctor {};
205     CHECK_COND_RET(env->Class_FindMethod(clazz, "<ctor>", nullptr, &ctor) == ANI_OK, nullptr,
206         "Failed to find method: <ctor>");
207 
208     unique_ptr<PhotoAlbumAni> obj = make_unique<PhotoAlbumAni>();
209     obj->env_ = env;
210     if (pAlbumData_ != nullptr) {
211         obj->SetPhotoAlbumAniProperties();
212     }
213     ani_object albumHandle {};
214     CHECK_COND_RET(env->Object_New(clazz, ctor, &albumHandle, reinterpret_cast<ani_long>(obj.release())) == ANI_OK,
215         nullptr, "New PhotoAlbumHandle Fail");
216     CHECK_COND_RET(BindAniAttributes(env, clazz, albumHandle) == ANI_OK, nullptr, "PhotoAlbum BindAniAttributes Fail");
217     return albumHandle;
218 }
219 
PhotoAlbumAniDestructor(ani_env * env,ani_object object)220 void PhotoAlbumAni::PhotoAlbumAniDestructor(ani_env *env, ani_object object)
221 {
222     PhotoAlbumAni *photoAlbum = UnwrapPhotoAlbumObject(env, object);
223     if (photoAlbum == nullptr) {
224         return;
225     }
226     photoAlbum->env_ = nullptr;
227     delete photoAlbum;
228 }
229 
NapiGetAnalysisAlbumPredicates(const shared_ptr<PhotoAlbum> & photoAlbum,DataSharePredicates & predicates)230 static int32_t NapiGetAnalysisAlbumPredicates(const shared_ptr<PhotoAlbum>& photoAlbum,
231     DataSharePredicates& predicates)
232 {
233     PhotoAlbumSubType subType = photoAlbum->GetPhotoAlbumSubType();
234     if (subType == PhotoAlbumSubType::PORTRAIT || subType == PhotoAlbumSubType::GROUP_PHOTO) {
235         MediaLibraryAniUtils::GetPortraitAlbumPredicates(photoAlbum->GetAlbumId(), predicates);
236         return E_SUCCESS;
237     }
238     if (subType == PhotoAlbumSubType::GEOGRAPHY_LOCATION) {
239         return MediaLibraryAniUtils::GetAllLocationPredicates(predicates);
240     }
241     if (subType == PhotoAlbumSubType::SHOOTING_MODE) {
242         ShootingModeAlbumType type {};
243         if (!ShootingModeAlbum::AlbumNameToShootingModeAlbumType(photoAlbum->GetAlbumName(), type)) {
244             ANI_ERR_LOG("Invalid shooting mode album name: %{public}s", photoAlbum->GetAlbumName().c_str());
245             return E_INVALID_ARGUMENTS;
246         }
247         ShootingModeAlbum::GetShootingModeAlbumPredicates(type, predicates, photoAlbum->GetHiddenOnly());
248         return E_SUCCESS;
249     }
250     string albumName = photoAlbum->GetAlbumName();
251     if (MediaLibraryAniUtils::IsFeaturedSinglePortraitAlbum(albumName, predicates)) {
252         return MediaLibraryAniUtils::GetFeaturedSinglePortraitAlbumPredicates(
253             photoAlbum->GetAlbumId(), predicates);
254     }
255     MediaLibraryAniUtils::GetAnalysisPhotoMapPredicates(photoAlbum->GetAlbumId(), predicates);
256     return E_SUCCESS;
257 }
258 
GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> & photoAlbum,DataSharePredicates & predicates,const bool hiddenOnly)259 static int32_t GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> &photoAlbum,
260     DataSharePredicates &predicates, const bool hiddenOnly)
261 {
262     int32_t albumId = photoAlbum->GetAlbumId();
263     PhotoAlbumSubType subType = photoAlbum->GetPhotoAlbumSubType();
264     bool isLocationAlbum = subType == PhotoAlbumSubType::GEOGRAPHY_LOCATION;
265     if (albumId <= 0 && !isLocationAlbum) {
266         ANI_ERR_LOG("Invalid album ID");
267         return E_INVALID_ARGUMENTS;
268     }
269     PhotoAlbumType type = photoAlbum->GetPhotoAlbumType();
270     if ((!PhotoAlbum::CheckPhotoAlbumType(type)) || (!PhotoAlbum::CheckPhotoAlbumSubType(subType))) {
271         ANI_ERR_LOG("Invalid album type or subtype: type=%{public}d, subType=%{public}d", static_cast<int>(type),
272             static_cast<int>(subType));
273         return E_INVALID_ARGUMENTS;
274     }
275 
276     if (PhotoAlbum::IsUserPhotoAlbum(type, subType)) {
277         return MediaLibraryAniUtils::GetUserAlbumPredicates(photoAlbum->GetAlbumId(), predicates, hiddenOnly);
278     }
279 
280     if (PhotoAlbum::IsSourceAlbum(type, subType)) {
281         return MediaLibraryAniUtils::GetSourceAlbumPredicates(photoAlbum->GetAlbumId(), predicates, hiddenOnly);
282     }
283 
284     if (type == PhotoAlbumType::SMART) {
285         return NapiGetAnalysisAlbumPredicates(photoAlbum, predicates);
286     }
287 
288     if (type == PhotoAlbumType::SYSTEM) {
289         return MediaLibraryAniUtils::GetSystemAlbumPredicates(subType, predicates, hiddenOnly);
290     }
291 
292     ANI_ERR_LOG("Invalid album type and subtype: type=%{public}d, subType=%{public}d", static_cast<int>(type),
293         static_cast<int>(subType));
294     return E_INVALID_ARGUMENTS;
295 }
296 
ParseArgsGetPhotoAssets(ani_env * env,ani_object object,ani_object fetchOptions,unique_ptr<PhotoAlbumAniContext> & context)297 static ani_status ParseArgsGetPhotoAssets(ani_env *env, ani_object object, ani_object fetchOptions,
298     unique_ptr<PhotoAlbumAniContext> &context)
299 {
300     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
301     if (context->objectInfo == nullptr) {
302         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
303         return ANI_INVALID_ARGS;
304     }
305 
306     /* Parse the first argument */
307     ani_status result = MediaLibraryAniUtils::GetFetchOption(env, fetchOptions, ASSET_FETCH_OPT, context);
308     if (result != ANI_OK) {
309         AniError::ThrowError(env, JS_INNER_FAIL);
310         return result;
311     }
312 
313     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
314     auto ret = GetPredicatesByAlbumTypes(photoAlbum, context->predicates, photoAlbum->GetHiddenOnly());
315     if (ret != E_SUCCESS) {
316         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
317         return ANI_INVALID_ARGS;
318     }
319     CHECK_STATUS_RET(MediaLibraryAniUtils::AddDefaultAssetColumns(env, context->fetchColumn,
320         PhotoColumn::IsPhotoColumn, AniAssetType::TYPE_PHOTO), "AddDefaultAssetColumns failed");
321     if (photoAlbum->GetHiddenOnly() || photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::HIDDEN) {
322         if (!MediaLibraryAniUtils::IsSystemApp()) {
323             AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
324             return ANI_ERROR;
325         }
326         // sort by hidden time desc if is hidden asset
327         context->predicates.IndexedBy(PhotoColumn::PHOTO_HIDDEN_TIME_INDEX);
328     }
329     return ANI_OK;
330 }
331 
IsFeaturedSinglePortraitAlbum(const shared_ptr<PhotoAlbum> & photoAlbum)332 static bool IsFeaturedSinglePortraitAlbum(const shared_ptr<PhotoAlbum>& photoAlbum)
333 {
334     constexpr int portraitAlbumId = 0;
335     return photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::CLASSIFY &&
336         photoAlbum->GetAlbumName().compare(to_string(portraitAlbumId)) == 0;
337 }
338 
ConvertColumnsForPortrait(unique_ptr<PhotoAlbumAniContext> & context)339 static void ConvertColumnsForPortrait(unique_ptr<PhotoAlbumAniContext> &context)
340 {
341     if (context == nullptr || context->objectInfo == nullptr) {
342         ANI_ERR_LOG("context is null or PhotoAlbumNapi is null");
343         return;
344     }
345 
346     shared_ptr<PhotoAlbum> photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
347     if (photoAlbum == nullptr || (photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::PORTRAIT &&
348         photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::GROUP_PHOTO &&
349         !IsFeaturedSinglePortraitAlbum(photoAlbum))) {
350         return;
351     }
352 
353     for (size_t i = 0; i < context->fetchColumn.size(); i++) {
354         if (context->fetchColumn[i] != "count(*)") {
355             context->fetchColumn[i] = PhotoColumn::PHOTOS_TABLE + "." + context->fetchColumn[i];
356         }
357     }
358 }
359 
PhotoAccessGetPhotoAssetsExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)360 static void PhotoAccessGetPhotoAssetsExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
361 {
362     Uri uri(PAH_QUERY_PHOTO_MAP);
363     ConvertColumnsForPortrait(context);
364     int32_t errCode = 0;
365     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
366     if (resultSet == nullptr) {
367         context->SaveError(E_HAS_DB_ERROR);
368         return;
369     }
370     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
371     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
372 }
373 
GetPhotoAssetsComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)374 static ani_object GetPhotoAssetsComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
375 {
376     ani_object fetchRes {};
377     ani_object errorObj {};
378     if (context->fetchResult != nullptr) {
379         fetchRes = FetchFileResultAni::CreateFetchFileResult(env, move(context->fetchResult));
380         if (fetchRes == nullptr) {
381             MediaLibraryAniUtils::CreateAniErrorObject(env, errorObj, ERR_MEM_ALLOCATION,
382                 "Failed to create ani object for FetchFileResult");
383         }
384     } else {
385         ANI_ERR_LOG("No fetch file result found!");
386         context->HandleError(env, errorObj);
387     }
388     context.reset();
389     return fetchRes;
390 }
391 
PhotoAccessGetPhotoAssets(ani_env * env,ani_object object,ani_object fetchOptions)392 ani_object PhotoAlbumAni::PhotoAccessGetPhotoAssets(ani_env *env, ani_object object, ani_object fetchOptions)
393 {
394     MediaLibraryTracer tracer;
395     tracer.Start("PhotoAccessGetPhotoAssets");
396 
397     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
398     if (ANI_OK != ParseArgsGetPhotoAssets(env, object, fetchOptions, context)) {
399         AniError::ThrowError(env, JS_INNER_FAIL);
400         return nullptr;
401     }
402     PhotoAccessGetPhotoAssetsExecute(env, context);
403     return GetPhotoAssetsComplete(env, context);
404 }
405 
PhotoAccessGetPhotoAssetsExecuteSync(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)406 static ani_object PhotoAccessGetPhotoAssetsExecuteSync(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
407 {
408     Uri uri(PAH_QUERY_PHOTO_MAP);
409     ConvertColumnsForPortrait(context);
410     int32_t errCode = 0;
411     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
412     CHECK_NULLPTR_RET(resultSet);
413     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
414     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
415 
416     std::vector<std::unique_ptr<FileAsset>> fileAssetArray;
417     auto file = fetchResult->GetFirstObject();
418     while (file != nullptr) {
419         fileAssetArray.push_back(move(file));
420         file = fetchResult->GetNextObject();
421     }
422     ani_object result {};
423     CHECK_COND_RET(MediaLibraryAniUtils::ToFileAssetAniArray(env, fileAssetArray, result) == ANI_OK, nullptr,
424         "ToFileAssetAniArray fail");
425     return result;
426 }
427 
PhotoAccessGetPhotoAssetsSync(ani_env * env,ani_object object,ani_object fetchOptions)428 ani_object PhotoAlbumAni::PhotoAccessGetPhotoAssetsSync(ani_env *env, ani_object object, ani_object fetchOptions)
429 {
430     MediaLibraryTracer tracer;
431     tracer.Start("PhotoAccessGetPhotoAssetsSync");
432 
433     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
434     if (ANI_OK != ParseArgsGetPhotoAssets(env, object, fetchOptions, context)) {
435         AniError::ThrowError(env, JS_INNER_FAIL);
436         return nullptr;
437     }
438     return PhotoAccessGetPhotoAssetsExecuteSync(env, context);
439 }
440 
SyncAlbumName(ani_env * env,ani_object object,std::shared_ptr<PhotoAlbum> & photoAlbum)441 void SyncAlbumName(ani_env *env, ani_object object, std::shared_ptr<PhotoAlbum> &photoAlbum)
442 {
443     std::string albumName = "";
444     CHECK_IF_EQUAL(MediaLibraryAniUtils::GetProperty(env, object, "albumName", albumName) == ANI_OK,
445         "Failed to get albumName");
446     CHECK_IF_EQUAL(!albumName.empty(), "Get empty albumName");
447     photoAlbum->SetAlbumName(albumName);
448 }
449 
ParseArgsCommitModify(ani_env * env,ani_object object,unique_ptr<PhotoAlbumAniContext> & context)450 static ani_status ParseArgsCommitModify(ani_env *env, ani_object object, unique_ptr<PhotoAlbumAniContext> &context)
451 {
452     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
453     if (context->objectInfo == nullptr) {
454         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
455         return ANI_INVALID_ARGS;
456     }
457 
458     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
459     if (photoAlbum == nullptr) {
460         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
461         return ANI_INVALID_ARGS;
462     }
463     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
464         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
465         return ANI_INVALID_ARGS;
466     }
467 
468     SyncAlbumName(env, object, photoAlbum);
469     if (MediaFileUtils::CheckAlbumName(photoAlbum->GetAlbumName()) < 0) {
470         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
471         return ANI_INVALID_ARGS;
472     }
473     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
474     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, photoAlbum->GetAlbumName());
475     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, photoAlbum->GetCoverUri());
476     return ANI_OK;
477 }
478 
CommitModifyExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)479 static void CommitModifyExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
480 {
481     string commitModifyUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
482         UFM_UPDATE_PHOTO_ALBUM : PAH_UPDATE_PHOTO_ALBUM;
483     Uri uri(commitModifyUri);
484     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
485     context->SaveError(changedRows);
486     context->changedRows = changedRows;
487 }
488 
CommitModifyComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)489 static void CommitModifyComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
490 {
491     ani_object errorObj {};
492     if (context->error != ERR_DEFAULT) {
493         context->HandleError(env, errorObj);
494     }
495     context.reset();
496 }
497 
PhotoAccessHelperCommitModify(ani_env * env,ani_object object)498 void PhotoAlbumAni::PhotoAccessHelperCommitModify(ani_env *env, ani_object object)
499 {
500     MediaLibraryTracer tracer;
501     tracer.Start("PhotoAccessHelperCommitModify");
502 
503     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
504     CHECK_IF_EQUAL(ParseArgsCommitModify(env, object, context) == ANI_OK, "ParseArgsCommitModify fail");
505     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
506     CommitModifyExecute(env, context);
507     CommitModifyComplete(env, context);
508 }
509 
GetAssetsIdArray(ani_env * env,ani_object photoAssets,std::vector<string> & assetsArray)510 static ani_status GetAssetsIdArray(ani_env *env, ani_object photoAssets, std::vector<string> &assetsArray)
511 {
512     ani_boolean isArray = MediaLibraryAniUtils::isArray(env, photoAssets);
513     if (isArray == ANI_FALSE) {
514         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array type");
515         return ANI_INVALID_ARGS;
516     }
517 
518     ani_double length = 0;
519     CHECK_STATUS_RET(env->Object_GetPropertyByName_Double(photoAssets, "length", &length),
520         "Call method <get>length failed.");
521     if (length <= 0) {
522         ANI_ERR_LOG("Failed to check array length: %{public}f", length);
523         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array length");
524         return ANI_INVALID_ARGS;
525     }
526 
527     for (ani_int i = 0; i < static_cast<ani_int>(length); i++) {
528         ani_ref asset {};
529         CHECK_STATUS_RET(env->Object_CallMethodByName_Ref(photoAssets, "$_get", "I:Lstd/core/Object;", &asset, i),
530             "Call method $_get failed.");
531 
532         FileAssetAni *obj = FileAssetAni::Unwrap(env, static_cast<ani_object>(asset));
533         if (obj == nullptr || obj->GetFileAssetInstance() == nullptr) {
534             AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset ani object");
535             return ANI_INVALID_ARGS;
536         }
537         MediaType mediaType = obj->GetFileAssetInstance()->GetMediaType();
538         if ((mediaType != MEDIA_TYPE_IMAGE && mediaType != MEDIA_TYPE_VIDEO)) {
539             ANI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", mediaType);
540             continue;
541         }
542         assetsArray.push_back(obj->GetFileAssetInstance()->GetUri());
543     }
544     return ANI_OK;
545 }
546 
ParseArgsAddAssets(ani_env * env,ani_object object,ani_object photoAssets,unique_ptr<PhotoAlbumAniContext> & context)547 static ani_status ParseArgsAddAssets(ani_env *env, ani_object object, ani_object photoAssets,
548     unique_ptr<PhotoAlbumAniContext> &context)
549 {
550     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
551     if (context->objectInfo == nullptr) {
552         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
553         return ANI_INVALID_ARGS;
554     }
555 
556     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
557     if (photoAlbum == nullptr) {
558         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
559         return ANI_INVALID_ARGS;
560     }
561     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
562         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
563         return ANI_INVALID_ARGS;
564     }
565 
566     std::vector<string> assetsArray;
567     CHECK_STATUS_RET(GetAssetsIdArray(env, photoAssets, assetsArray), "Parse photoAssets uri fail");
568     if (assetsArray.empty()) {
569         AniError::ThrowError(env, JS_INNER_FAIL);
570         return ANI_INVALID_ARGS;
571     }
572     int32_t albumId = photoAlbum->GetAlbumId();
573     for (const auto &assetId : assetsArray) {
574         DataShareValuesBucket valuesBucket;
575         valuesBucket.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
576         valuesBucket.Put(PhotoColumn::MEDIA_ID, assetId);
577         context->valuesBuckets.push_back(valuesBucket);
578     }
579     return ANI_OK;
580 }
581 
FetchNewCount(unique_ptr<PhotoAlbumAniContext> & context)582 static bool FetchNewCount(unique_ptr<PhotoAlbumAniContext> &context)
583 {
584     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
585     if (photoAlbum == nullptr) {
586         ANI_ERR_LOG("photoAlbum is nullptr");
587         return false;
588     }
589     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
590         UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
591     Uri qUri(queryUri);
592     int errCode = 0;
593     DataSharePredicates predicates;
594     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, photoAlbum->GetAlbumId());
595     vector<string> fetchColumn = {
596         PhotoAlbumColumns::ALBUM_ID,
597         PhotoAlbumColumns::ALBUM_COUNT,
598     };
599     bool isSmartAlbum = (photoAlbum->GetPhotoAlbumType() == PhotoAlbumType::SMART);
600     if (!isSmartAlbum) {
601         fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
602         fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
603     }
604     auto resultSet = UserFileClient::Query(qUri, predicates, fetchColumn, errCode);
605     if (resultSet == nullptr) {
606         ANI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
607         return false;
608     }
609     if (resultSet->GoToFirstRow() != 0) {
610         ANI_ERR_LOG("go to first row failed");
611         return false;
612     }
613     bool hiddenOnly = photoAlbum->GetHiddenOnly();
614     int imageCount = (hiddenOnly || isSmartAlbum) ? -1 :
615             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT, resultSet, TYPE_INT32));
616     int videoCount = (hiddenOnly || isSmartAlbum) ? -1 :
617             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT, resultSet, TYPE_INT32));
618     context->newCount =
619             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_COUNT, resultSet, TYPE_INT32));
620     context->newImageCount = imageCount;
621     context->newVideoCount = videoCount;
622     return true;
623 }
624 
PhotoAlbumAddAssetsExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)625 static void PhotoAlbumAddAssetsExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
626 {
627     if (context->valuesBuckets.empty()) {
628         return;
629     }
630     string addAssetsUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
631         UFM_PHOTO_ALBUM_ADD_ASSET : PAH_PHOTO_ALBUM_ADD_ASSET;
632     Uri uri(addAssetsUri);
633 
634     auto changedRows = UserFileClient::BatchInsert(uri, context->valuesBuckets);
635     if (changedRows < 0) {
636         context->SaveError(changedRows);
637         return;
638     }
639     context->changedRows = changedRows;
640     if (!FetchNewCount(context)) {
641         ANI_ERR_LOG("Update count failed");
642         context->SaveError(E_HAS_DB_ERROR);
643     }
644 }
645 
PhotoAlbumAddAssetsComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)646 static void PhotoAlbumAddAssetsComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
647 {
648     ani_object errorObj {};
649     if (context->error == ERR_DEFAULT) {
650         auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
651         photoAlbum->SetCount(context->newCount);
652         photoAlbum->SetImageCount(context->newImageCount);
653         photoAlbum->SetVideoCount(context->newVideoCount);
654     } else {
655         context->HandleError(env, errorObj);
656     }
657     context.reset();
658 }
659 
PhotoAccessHelperAddAssets(ani_env * env,ani_object object,ani_object photoAssets)660 void PhotoAlbumAni::PhotoAccessHelperAddAssets(ani_env *env, ani_object object, ani_object photoAssets)
661 {
662     MediaLibraryTracer tracer;
663     tracer.Start("PhotoAccessHelperAddAssets");
664 
665     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
666     CHECK_IF_EQUAL(ParseArgsAddAssets(env, object, photoAssets, context) == ANI_OK, "ParseArgsAddAssets fail");
667     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
668     PhotoAlbumAddAssetsExecute(env, context);
669     PhotoAlbumAddAssetsComplete(env, context);
670 }
671 
ParseArgsRemoveAssets(ani_env * env,ani_object object,ani_object photoAssets,unique_ptr<PhotoAlbumAniContext> & context)672 static ani_status ParseArgsRemoveAssets(ani_env *env, ani_object object, ani_object photoAssets,
673     unique_ptr<PhotoAlbumAniContext> &context)
674 {
675     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
676     if (context->objectInfo == nullptr) {
677         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
678         return ANI_INVALID_ARGS;
679     }
680 
681     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
682     if (photoAlbum == nullptr) {
683         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
684         return ANI_INVALID_ARGS;
685     }
686     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
687         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
688         return ANI_INVALID_ARGS;
689     }
690 
691     std::vector<string> assetsArray;
692     CHECK_STATUS_RET(GetAssetsIdArray(env, photoAssets, assetsArray), "Parse photoAssets uri fail");
693     if (assetsArray.empty()) {
694         AniError::ThrowError(env, JS_INNER_FAIL);
695         return ANI_INVALID_ARGS;
696     }
697     context->predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
698     context->predicates.And()->In(PhotoColumn::MEDIA_ID, assetsArray);
699     return ANI_OK;
700 }
701 
PhotoAlbumRemoveAssetsExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)702 static void PhotoAlbumRemoveAssetsExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
703 {
704     if (context->predicates.GetOperationList().empty()) {
705         return;
706     }
707 
708     string removeAssetsUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
709         UFM_PHOTO_ALBUM_REMOVE_ASSET : PAH_PHOTO_ALBUM_REMOVE_ASSET;
710     Uri uri(removeAssetsUri);
711     auto deletedRows = UserFileClient::Delete(uri, context->predicates);
712     if (deletedRows < 0) {
713         context->SaveError(deletedRows);
714         return;
715     }
716     context->changedRows = deletedRows;
717     if (!FetchNewCount(context)) {
718         ANI_ERR_LOG("Update count failed");
719         context->SaveError(E_HAS_DB_ERROR);
720     }
721 }
722 
PhotoAlbumRemoveAssetsComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)723 static void PhotoAlbumRemoveAssetsComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
724 {
725     ani_object errorObj {};
726     if (context->error == ERR_DEFAULT) {
727         auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
728         photoAlbum->SetCount(context->newCount);
729         photoAlbum->SetImageCount(context->newImageCount);
730         photoAlbum->SetVideoCount(context->newVideoCount);
731     } else {
732         context->HandleError(env, errorObj);
733     }
734     context.reset();
735 }
736 
PhotoAccessHelperRemoveAssets(ani_env * env,ani_object object,ani_object photoAssets)737 void PhotoAlbumAni::PhotoAccessHelperRemoveAssets(ani_env *env, ani_object object, ani_object photoAssets)
738 {
739     MediaLibraryTracer tracer;
740     tracer.Start("PhotoAccessHelperRemoveAssets");
741 
742     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
743     CHECK_IF_EQUAL(ParseArgsRemoveAssets(env, object, photoAssets, context) == ANI_OK, "ParseArgsRemoveAssets fail");
744     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
745     PhotoAlbumRemoveAssetsExecute(env, context);
746     PhotoAlbumRemoveAssetsComplete(env, context);
747 }
748 
TrashAlbumParseArgs(ani_env * env,ani_object object,ani_object photoAssets,unique_ptr<PhotoAlbumAniContext> & context)749 static ani_status TrashAlbumParseArgs(ani_env *env, ani_object object, ani_object photoAssets,
750     unique_ptr<PhotoAlbumAniContext> &context)
751 {
752     if (!MediaLibraryAniUtils::IsSystemApp()) {
753         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
754         return ANI_ERROR;
755     }
756 
757     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
758     if (context->objectInfo == nullptr) {
759         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
760         return ANI_INVALID_ARGS;
761     }
762 
763     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
764     if (photoAlbum == nullptr) {
765         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
766         return ANI_INVALID_ARGS;
767     }
768     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
769         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
770         return ANI_INVALID_ARGS;
771     }
772 
773     std::vector<string> uris;
774     CHECK_STATUS_RET(MediaLibraryAniUtils::GetUriArrayFromAssets(env, photoAssets, uris), "Parse uris fail");
775     if (uris.empty()) {
776         AniError::ThrowError(env, JS_INNER_FAIL);
777         return ANI_INVALID_ARGS;
778     }
779     context->predicates.In(MediaColumn::MEDIA_ID, uris);
780     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
781     return ANI_OK;
782 }
783 
TrashAlbumExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context,const std::string & optUri)784 static void TrashAlbumExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context, const std::string &optUri)
785 {
786     if (context->predicates.GetOperationList().empty()) {
787         ANI_ERR_LOG("Operation list is empty.");
788         return;
789     }
790     Uri uri(optUri);
791     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
792     if (changedRows < 0) {
793         context->SaveError(changedRows);
794         ANI_ERR_LOG("Trash album executed, changeRows: %{public}d.", changedRows);
795         return;
796     }
797     context->changedRows = changedRows;
798 }
799 
TrashAlbumComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)800 static void TrashAlbumComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
801 {
802     ani_object errorObj {};
803     if (context->error != ERR_DEFAULT) {
804         context->HandleError(env, errorObj);
805     }
806     context.reset();
807 }
808 
RecoverPhotosExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)809 static void RecoverPhotosExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
810 {
811     std::string uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
812         UFM_RECOVER_PHOTOS : PAH_RECOVER_PHOTOS;
813     TrashAlbumExecute(env, context, uri);
814 }
815 
RecoverPhotosComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)816 static void RecoverPhotosComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
817 {
818     TrashAlbumComplete(env, context);
819 }
820 
PhotoAccessHelperRecoverPhotos(ani_env * env,ani_object object,ani_object photoAssets)821 void PhotoAlbumAni::PhotoAccessHelperRecoverPhotos(ani_env *env, ani_object object, ani_object photoAssets)
822 {
823     MediaLibraryTracer tracer;
824     tracer.Start("PhotoAccessHelperRecoverPhotos");
825 
826     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
827     CHECK_IF_EQUAL(TrashAlbumParseArgs(env, object, photoAssets, context) == ANI_OK, "TrashAlbumParseArgs fail");
828     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
829     RecoverPhotosExecute(env, context);
830     RecoverPhotosComplete(env, context);
831 }
832 
DeletePhotosExecute(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)833 static void DeletePhotosExecute(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
834 {
835     std::string uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
836         UFM_DELETE_PHOTOS : PAH_DELETE_PHOTOS;
837     TrashAlbumExecute(env, context, uri);
838 }
839 
DeletePhotosComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)840 static void DeletePhotosComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
841 {
842     TrashAlbumComplete(env, context);
843 }
844 
PhotoAccessHelperDeletePhotos(ani_env * env,ani_object object,ani_object photoAssets)845 void PhotoAlbumAni::PhotoAccessHelperDeletePhotos(ani_env *env, ani_object object, ani_object photoAssets)
846 {
847     MediaLibraryTracer tracer;
848     tracer.Start("PhotoAccessHelperDeletePhotos");
849 
850     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
851     CHECK_IF_EQUAL(TrashAlbumParseArgs(env, object, photoAssets, context) == ANI_OK, "TrashAlbumParseArgs fail");
852     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
853     DeletePhotosExecute(env, context);
854     DeletePhotosComplete(env, context);
855 }
856 
ParseArgsSetCoverUri(ani_env * env,ani_object object,ani_string uri,unique_ptr<PhotoAlbumAniContext> & context)857 static ani_status ParseArgsSetCoverUri(ani_env *env, ani_object object, ani_string uri,
858     unique_ptr<PhotoAlbumAniContext> &context)
859 {
860     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
861     if (context->objectInfo == nullptr) {
862         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
863         return ANI_INVALID_ARGS;
864     }
865 
866     std::string coverUri;
867     CHECK_STATUS_RET(MediaLibraryAniUtils::GetParamStringPathMax(env, uri, coverUri), "Parse coverUri failed.");
868 
869     if (!MediaLibraryAniUtils::IsSystemApp()) {
870         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can update album cover");
871         return ANI_ERROR;
872     }
873 
874     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
875     if (photoAlbum == nullptr) {
876         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
877         return ANI_INVALID_ARGS;
878     }
879     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
880     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, coverUri);
881     return ANI_OK;
882 }
883 
PhotoAccessHelperSetCoverUri(ani_env * env,ani_object object,ani_string uri)884 void PhotoAlbumAni::PhotoAccessHelperSetCoverUri(ani_env *env, ani_object object, ani_string uri)
885 {
886     MediaLibraryTracer tracer;
887     tracer.Start("PhotoAccessHelperSetCoverUri");
888 
889     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
890     CHECK_IF_EQUAL(ParseArgsSetCoverUri(env, object, uri, context) == ANI_OK, "ParseArgsSetCoverUri fail");
891     context->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
892     CommitModifyExecute(env, context);
893     CommitModifyComplete(env, context);
894 }
895 
PhotoAccessHelperGetFaceIdExec(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)896 static void PhotoAccessHelperGetFaceIdExec(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
897 {
898     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
899     PhotoAlbumSubType albumSubType = photoAlbum->GetPhotoAlbumSubType();
900     if (albumSubType != PhotoAlbumSubType::PORTRAIT && albumSubType != PhotoAlbumSubType::GROUP_PHOTO) {
901         ANI_WARN_LOG("albumSubType: %{public}d, not support getFaceId", albumSubType);
902         return;
903     }
904 
905     Uri uri(PAH_QUERY_ANA_PHOTO_ALBUM);
906     DataShare::DataSharePredicates predicates;
907     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, photoAlbum->GetAlbumId());
908     vector<string> fetchColumn = { GROUP_TAG };
909     int errCode = 0;
910 
911     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
912     if (resultSet == nullptr || resultSet->GoToFirstRow() != 0) {
913         if (errCode == E_PERMISSION_DENIED) {
914             context->error = OHOS_PERMISSION_DENIED_CODE;
915         } else {
916             context->SaveError(E_FAIL);
917         }
918         ANI_ERR_LOG("get face id failed, errCode is %{public}d", errCode);
919         return;
920     }
921 
922     context->faceTag = GetStringVal(GROUP_TAG, resultSet);
923 }
924 
GetFaceIdComplete(ani_env * env,unique_ptr<PhotoAlbumAniContext> & context)925 static ani_string GetFaceIdComplete(ani_env *env, unique_ptr<PhotoAlbumAniContext> &context)
926 {
927     ani_string result {};
928     ani_object errorObj {};
929     if (context->error != ERR_DEFAULT) {
930         context->HandleError(env, errorObj);
931     } else {
932         CHECK_COND_RET(MediaLibraryAniUtils::ToAniString(env, context->faceTag, result) == ANI_OK, nullptr,
933             "ToAniString faceTag fail");
934     }
935     context.reset();
936     return result;
937 }
938 
PhotoAccessHelperGetFaceId(ani_env * env,ani_object object)939 ani_string PhotoAlbumAni::PhotoAccessHelperGetFaceId(ani_env *env, ani_object object)
940 {
941     MediaLibraryTracer tracer;
942     tracer.Start("PhotoAccessHelperGetFaceId");
943     if (!MediaLibraryAniUtils::IsSystemApp()) {
944         AniError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get the Face ID of the album");
945         return nullptr;
946     }
947 
948     unique_ptr<PhotoAlbumAniContext> context = make_unique<PhotoAlbumAniContext>();
949     context->objectInfo = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
950     if (context->objectInfo == nullptr) {
951         AniError::ThrowError(env, JS_ERR_PARAMETER_INVALID, __FUNCTION__, __LINE__);
952         return nullptr;
953     }
954     PhotoAccessHelperGetFaceIdExec(env, context);
955     return GetFaceIdComplete(env, context);
956 }
957 
GetImageCount(ani_env * env,ani_object object)958 ani_double PhotoAlbumAni::GetImageCount(ani_env *env, ani_object object)
959 {
960     PhotoAlbumAni *photoAlbumAni = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
961     if (photoAlbumAni == nullptr || photoAlbumAni->GetPhotoAlbumInstance() == nullptr) {
962         ANI_ERR_LOG("photoAlbumAni or photoAlbum is nullptr");
963         return 0;
964     }
965     int32_t imageCount = photoAlbumAni->GetPhotoAlbumInstance()->GetImageCount();
966     return static_cast<ani_double>(imageCount);
967 }
968 
GetVideoCount(ani_env * env,ani_object object)969 ani_double PhotoAlbumAni::GetVideoCount(ani_env *env, ani_object object)
970 {
971     PhotoAlbumAni *photoAlbumAni = PhotoAlbumAni::UnwrapPhotoAlbumObject(env, object);
972     if (photoAlbumAni == nullptr || photoAlbumAni->GetPhotoAlbumInstance() == nullptr) {
973         ANI_ERR_LOG("photoAlbumAni or photoAlbum is nullptr");
974         return 0;
975     }
976     int32_t videoCount = photoAlbumAni->GetPhotoAlbumInstance()->GetVideoCount();
977     return static_cast<ani_double>(videoCount);
978 }
979 } // namespace OHOS::Media