1 /*
2 * Copyright (c) 2024 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 "media_album_change_request_impl.h"
17
18 #include "result_set_utils.h"
19 #include "userfile_client.h"
20
21 namespace OHOS {
22 namespace Media {
MediaAlbumChangeRequestImpl(shared_ptr<PhotoAlbum> photoAlbumPtr)23 MediaAlbumChangeRequestImpl::MediaAlbumChangeRequestImpl(shared_ptr<PhotoAlbum> photoAlbumPtr)
24 {
25 photoAlbum_ = photoAlbumPtr;
26 }
27
GetPhotoAlbumInstance() const28 shared_ptr<PhotoAlbum> MediaAlbumChangeRequestImpl::GetPhotoAlbumInstance() const
29 {
30 return photoAlbum_;
31 }
32
GetAddAssetArray() const33 vector<string> MediaAlbumChangeRequestImpl::GetAddAssetArray() const
34 {
35 return assetsToAdd_;
36 }
37
GetRemoveAssetArray() const38 vector<string> MediaAlbumChangeRequestImpl::GetRemoveAssetArray() const
39 {
40 return assetsToRemove_;
41 }
42
GetAlbumChangeOperations() const43 std::vector<AlbumChangeOperation> MediaAlbumChangeRequestImpl::GetAlbumChangeOperations() const
44 {
45 return albumChangeOperations_;
46 }
47
ClearAddAssetArray()48 void MediaAlbumChangeRequestImpl::ClearAddAssetArray()
49 {
50 assetsToAdd_.clear();
51 }
52
ClearRemoveAssetArray()53 void MediaAlbumChangeRequestImpl::ClearRemoveAssetArray()
54 {
55 assetsToRemove_.clear();
56 }
57
CJGetAlbum(int32_t * errCode)58 int64_t MediaAlbumChangeRequestImpl::CJGetAlbum(int32_t* errCode)
59 {
60 if (photoAlbum_ == nullptr) {
61 *errCode = JS_INNER_FAIL;
62 return 0;
63 }
64 if (photoAlbum_->GetAlbumId() > 0) {
65 auto photoAlbumImpl = FFIData::Create<PhotoAlbumImpl>(photoAlbum_);
66 if (photoAlbumImpl == nullptr) {
67 *errCode = JS_INNER_FAIL;
68 return 0;
69 }
70 return photoAlbumImpl->GetID();
71 }
72 return 0;
73 }
74
CJSetAlbumName(std::string albumName)75 int32_t MediaAlbumChangeRequestImpl::CJSetAlbumName(std::string albumName)
76 {
77 if (MediaFileUtils::CheckAlbumName(albumName) != E_OK) {
78 LOGE("Invalid album name");
79 return OHOS_INVALID_PARAM_CODE;
80 }
81 if (photoAlbum_ == nullptr) {
82 LOGE("photoAlbum is null")
83 return OHOS_INVALID_PARAM_CODE;
84 }
85 bool isUserPhotoAlbum = PhotoAlbum::IsUserPhotoAlbum(photoAlbum_->GetPhotoAlbumType(),
86 photoAlbum_->GetPhotoAlbumSubType());
87 bool isSmartPortraitPhotoAlbum = PhotoAlbum::IsSmartPortraitPhotoAlbum(photoAlbum_->GetPhotoAlbumType(),
88 photoAlbum_->GetPhotoAlbumSubType());
89 bool isSmartGroupPhotoAlbum = PhotoAlbum::IsSmartGroupPhotoAlbum(photoAlbum_->GetPhotoAlbumType(),
90 photoAlbum_->GetPhotoAlbumSubType());
91 if (!(isUserPhotoAlbum || isSmartPortraitPhotoAlbum || isSmartGroupPhotoAlbum)) {
92 LOGE("Only user album, smart portrait album and group photo can set album name");
93 return OHOS_INVALID_PARAM_CODE;
94 }
95 photoAlbum_->SetAlbumName(albumName);
96 albumChangeOperations_.push_back(AlbumChangeOperation::SET_ALBUM_NAME);
97 return 0;
98 }
99
CheckDuplicatedAssetArray(const vector<string> & arrayToCheck,const vector<string> & currentArray)100 static bool CheckDuplicatedAssetArray(const vector<string>& arrayToCheck, const vector<string>& currentArray)
101 {
102 if (currentArray.empty()) {
103 return true;
104 }
105
106 for (const auto& element : arrayToCheck) {
107 if (std::find(currentArray.begin(), currentArray.end(), element) != currentArray.end()) {
108 return false;
109 }
110 }
111 return true;
112 }
113
CJAddAssets(std::vector<std::string> assetUriArray)114 int32_t MediaAlbumChangeRequestImpl::CJAddAssets(std::vector<std::string> assetUriArray)
115 {
116 if (photoAlbum_ == nullptr) {
117 LOGE("photoAlbum is null")
118 return OHOS_INVALID_PARAM_CODE;
119 }
120 if (!(PhotoAlbum::IsUserPhotoAlbum(photoAlbum_->GetPhotoAlbumType(), photoAlbum_->GetPhotoAlbumSubType()))) {
121 LOGE("Only user album can add assets");
122 return OHOS_INVALID_PARAM_CODE;
123 }
124 if (!CheckDuplicatedAssetArray(assetUriArray, assetsToAdd_)) {
125 LOGE("The previous addAssets operation has contained the same asset");
126 return JS_E_OPERATION_NOT_SUPPORT;
127 }
128 assetsToAdd_.insert(assetsToAdd_.end(), assetUriArray.begin(), assetUriArray.end());
129 albumChangeOperations_.push_back(AlbumChangeOperation::ADD_ASSETS);
130 return 0;
131 }
132
CJRemoveAssets(std::vector<std::string> assetUriArray)133 int32_t MediaAlbumChangeRequestImpl::CJRemoveAssets(std::vector<std::string> assetUriArray)
134 {
135 if (photoAlbum_ == nullptr) {
136 LOGE("photoAlbum is null")
137 return OHOS_INVALID_PARAM_CODE;
138 }
139 if (!(PhotoAlbum::IsUserPhotoAlbum(photoAlbum_->GetPhotoAlbumType(), photoAlbum_->GetPhotoAlbumSubType()))) {
140 LOGE("Only user album can add assets");
141 return OHOS_INVALID_PARAM_CODE;
142 }
143 if (!CheckDuplicatedAssetArray(assetUriArray, assetsToAdd_)) {
144 LOGE("The previous addAssets operation has contained the same asset");
145 return JS_E_OPERATION_NOT_SUPPORT;
146 }
147 assetsToRemove_.insert(assetsToRemove_.end(), assetUriArray.begin(), assetUriArray.end());
148 albumChangeOperations_.push_back(AlbumChangeOperation::REMOVE_ASSETS);
149 return 0;
150 }
151
CheckChangeOperations()152 bool MediaAlbumChangeRequestImpl::CheckChangeOperations()
153 {
154 if (albumChangeOperations_.empty()) {
155 LOGE("None request to apply");
156 return false;
157 }
158
159 auto photoAlbum = GetPhotoAlbumInstance();
160 if (photoAlbum == nullptr) {
161 LOGE("photoAlbum is null");
162 return false;
163 }
164
165 if (albumChangeOperations_.front() != AlbumChangeOperation::CREATE_ALBUM && photoAlbum->GetAlbumId() <= 0) {
166 LOGE("Invalid album change request");
167 return false;
168 }
169
170 return true;
171 }
172
FetchNewCount(shared_ptr<PhotoAlbum> & album)173 static bool FetchNewCount(shared_ptr<PhotoAlbum>& album)
174 {
175 if (album == nullptr) {
176 LOGE("Album is null");
177 return false;
178 }
179
180 Uri queryUri(PAH_QUERY_PHOTO_ALBUM);
181 DataShare::DataSharePredicates predicates;
182 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, album->GetAlbumId());
183 vector<string> fetchColumns = { PhotoAlbumColumns::ALBUM_ID, PhotoAlbumColumns::ALBUM_COUNT,
184 PhotoAlbumColumns::ALBUM_IMAGE_COUNT, PhotoAlbumColumns::ALBUM_VIDEO_COUNT };
185 int errCode = 0;
186 auto resultSet = UserFileClient::Query(queryUri, predicates, fetchColumns, errCode);
187 if (resultSet == nullptr) {
188 NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
189 return false;
190 }
191 if (resultSet->GoToFirstRow() != 0) {
192 NAPI_ERR_LOG("go to first row failed when fetch new count");
193 return false;
194 }
195
196 bool hiddenOnly = album->GetHiddenOnly();
197 int imageCount = hiddenOnly ? -1 : get<int32_t>(ResultSetUtils::GetValFromColumn(
198 PhotoAlbumColumns::ALBUM_IMAGE_COUNT, resultSet, TYPE_INT32));
199 int videoCount = hiddenOnly ? -1 : get<int32_t>(ResultSetUtils::GetValFromColumn(
200 PhotoAlbumColumns::ALBUM_VIDEO_COUNT, resultSet, TYPE_INT32));
201 album->SetCount(
202 get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_COUNT, resultSet, TYPE_INT32)));
203 album->SetImageCount(imageCount);
204 album->SetVideoCount(videoCount);
205 return true;
206 }
207
AddAssetsExecute(MediaAlbumChangeRequestImpl * changeRequest)208 static bool AddAssetsExecute(MediaAlbumChangeRequestImpl* changeRequest)
209 {
210 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
211 int32_t albumId = photoAlbum->GetAlbumId();
212 vector<DataShare::DataShareValuesBucket> valuesBuckets;
213 for (const auto& asset : changeRequest->GetAddAssetArray()) {
214 DataShare::DataShareValuesBucket pair;
215 pair.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
216 pair.Put(PhotoColumn::MEDIA_ID, asset);
217 valuesBuckets.push_back(pair);
218 }
219
220 Uri addAssetsUri(PAH_PHOTO_ALBUM_ADD_ASSET);
221 int ret = UserFileClient::BatchInsert(addAssetsUri, valuesBuckets);
222 changeRequest->ClearAddAssetArray();
223 if (ret < 0) {
224 LOGE("Failed to add assets into album %{public}d, err: %{public}d", albumId, ret);
225 return false;
226 }
227
228 LOGE("Add %{public}d asset(s) into album %{public}d", ret, albumId);
229 FetchNewCount(photoAlbum);
230 return true;
231 }
232
RemoveAssetsExecute(MediaAlbumChangeRequestImpl * changeRequest)233 static bool RemoveAssetsExecute(MediaAlbumChangeRequestImpl* changeRequest)
234 {
235 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
236 int32_t albumId = photoAlbum->GetAlbumId();
237 DataShare::DataSharePredicates predicates;
238 predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(albumId));
239 predicates.And()->In(PhotoColumn::MEDIA_ID, changeRequest->GetRemoveAssetArray());
240
241 Uri removeAssetsUri(PAH_PHOTO_ALBUM_REMOVE_ASSET);
242 int ret = UserFileClient::Delete(removeAssetsUri, predicates);
243 changeRequest->ClearRemoveAssetArray();
244 if (ret < 0) {
245 LOGE("Failed to remove assets from album %{public}d, err: %{public}d", albumId, ret);
246 return false;
247 }
248
249 LOGE("Remove %{public}d asset(s) from album %{public}d", ret, albumId);
250 FetchNewCount(photoAlbum);
251 return true;
252 }
253
GetAlbumUpdateValue(shared_ptr<PhotoAlbum> & photoAlbum,const AlbumChangeOperation changeOperation,string & uri,DataShare::DataShareValuesBucket & valuesBucket,string & property)254 static bool GetAlbumUpdateValue(shared_ptr<PhotoAlbum>& photoAlbum, const AlbumChangeOperation changeOperation,
255 string& uri, DataShare::DataShareValuesBucket& valuesBucket, string& property)
256 {
257 if (photoAlbum == nullptr) {
258 LOGE("photoAlbum is null");
259 return false;
260 }
261
262 switch (changeOperation) {
263 case AlbumChangeOperation::SET_ALBUM_NAME:
264 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
265 uri = PAH_PORTRAIT_ANAALBUM_ALBUM_NAME;
266 } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
267 uri = PAH_GROUP_ANAALBUM_ALBUM_NAME;
268 } else {
269 uri = PAH_SET_PHOTO_ALBUM_NAME;
270 }
271 property = PhotoAlbumColumns::ALBUM_NAME;
272 valuesBucket.Put(property, photoAlbum->GetAlbumName());
273 break;
274 case AlbumChangeOperation::SET_COVER_URI:
275 if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
276 uri = PAH_PORTRAIT_ANAALBUM_COVER_URI;
277 } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
278 uri = PAH_GROUP_ANAALBUM_COVER_URI;
279 } else {
280 uri = PAH_UPDATE_PHOTO_ALBUM;
281 }
282 property = PhotoAlbumColumns::ALBUM_COVER_URI;
283 valuesBucket.Put(property, photoAlbum->GetCoverUri());
284 break;
285 case AlbumChangeOperation::SET_DISPLAY_LEVEL:
286 uri = PAH_PORTRAIT_DISPLAY_LEVLE;
287 property = USER_DISPLAY_LEVEL;
288 valuesBucket.Put(property, photoAlbum->GetDisplayLevel());
289 break;
290 case AlbumChangeOperation::SET_IS_ME:
291 uri = PAH_PORTRAIT_IS_ME;
292 property = IS_ME;
293 valuesBucket.Put(property, 1);
294 break;
295 case AlbumChangeOperation::DISMISS:
296 uri = PAH_GROUP_ANAALBUM_DISMISS;
297 property = IS_REMOVED;
298 valuesBucket.Put(property, 1);
299 break;
300 default:
301 return false;
302 }
303 return true;
304 }
305
SetAlbumPropertyExecute(MediaAlbumChangeRequestImpl * changeRequest,const AlbumChangeOperation changeOperation)306 static bool SetAlbumPropertyExecute(
307 MediaAlbumChangeRequestImpl* changeRequest, const AlbumChangeOperation changeOperation)
308 {
309 if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME &&
310 changeRequest->GetAlbumChangeOperations().front() == AlbumChangeOperation::CREATE_ALBUM) {
311 return true;
312 }
313
314 DataShare::DataSharePredicates predicates;
315 DataShare::DataShareValuesBucket valuesBucket;
316 auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
317 predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, std::to_string(photoAlbum->GetAlbumId()));
318 string uri;
319 string property;
320 if (!GetAlbumUpdateValue(photoAlbum, changeOperation, uri, valuesBucket, property)) {
321 LOGE("Failed to parse album change operation: %{public}d", changeOperation);
322 return false;
323 }
324 valuesBucket.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbum->GetPhotoAlbumSubType());
325 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
326 Uri updateAlbumUri(uri);
327 int32_t changedRows = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
328 if (changedRows < 0) {
329 LOGE("Failed to set %{public}s, err: %{public}d", property.c_str(), changedRows);
330 return false;
331 }
332 return true;
333 }
334
335 static const unordered_map<AlbumChangeOperation, bool (*)(MediaAlbumChangeRequestImpl*)> EXECUTE_MAP = {
336 { AlbumChangeOperation::ADD_ASSETS, AddAssetsExecute },
337 { AlbumChangeOperation::REMOVE_ASSETS, RemoveAssetsExecute },
338 };
339
ApplyChanges()340 int32_t MediaAlbumChangeRequestImpl::ApplyChanges()
341 {
342 if (!CheckChangeOperations()) {
343 LOGE("Failed to check album change request operations");
344 return OHOS_INVALID_PARAM_CODE;
345 }
346 unordered_set<AlbumChangeOperation> appliedOperations;
347 for (const auto& changeOperation : albumChangeOperations_) {
348 // Keep the final result(s) of each operation, and commit only once.
349 if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
350 continue;
351 }
352
353 bool valid = false;
354 auto iter = EXECUTE_MAP.find(changeOperation);
355 if (iter != EXECUTE_MAP.end()) {
356 valid = iter->second(this);
357 } else if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME ||
358 changeOperation == AlbumChangeOperation::SET_COVER_URI ||
359 changeOperation == AlbumChangeOperation::SET_IS_ME ||
360 changeOperation == AlbumChangeOperation::SET_DISPLAY_LEVEL ||
361 changeOperation == AlbumChangeOperation::DISMISS) {
362 valid = SetAlbumPropertyExecute(this, changeOperation);
363 } else {
364 LOGE("Invalid album change operation: %{public}d", changeOperation);
365 albumChangeOperations_.clear();
366 return OHOS_INVALID_PARAM_CODE;
367 }
368
369 if (!valid) {
370 LOGE("Failed to apply album change request, operation: %{public}d", changeOperation);
371 albumChangeOperations_.clear();
372 return 0;
373 }
374 appliedOperations.insert(changeOperation);
375 }
376 albumChangeOperations_.clear();
377 return 0;
378 }
379 } // namespace Media
380 } // namespace OHOS