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