• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "album_operation_uri.h"
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 
GetAlbumUpdateCoverUri(shared_ptr<PhotoAlbum> & photoAlbum,string & uri)254 static void GetAlbumUpdateCoverUri(shared_ptr<PhotoAlbum>& photoAlbum, string& uri)
255 {
256     if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
257         uri = PAH_PORTRAIT_ANAALBUM_COVER_URI;
258     } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
259         uri = PAH_GROUP_ANAALBUM_COVER_URI;
260     } else if (PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
261         uri = PAH_UPDATE_USER_ALBUM_COVER_URI;
262     } else if (PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
263         uri = PAH_UPDATE_USER_ALBUM_COVER_URI;
264     } else if (PhotoAlbum::IsSourceAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
265         uri = PAH_UPDATE_SOURCE_ALBUM_COVER_URI;
266     } else {
267         uri = PAH_UPDATE_SYSTEM_ALBUM_COVER_URI;
268     }
269 }
270 
GetAlbumUpdateValue(shared_ptr<PhotoAlbum> & photoAlbum,const AlbumChangeOperation changeOperation,string & uri,DataShare::DataShareValuesBucket & valuesBucket,string & property)271 static bool GetAlbumUpdateValue(shared_ptr<PhotoAlbum>& photoAlbum, const AlbumChangeOperation changeOperation,
272     string& uri, DataShare::DataShareValuesBucket& valuesBucket, string& property)
273 {
274     if (photoAlbum == nullptr) {
275         LOGE("photoAlbum is null");
276         return false;
277     }
278 
279     switch (changeOperation) {
280         case AlbumChangeOperation::SET_ALBUM_NAME:
281             if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::PORTRAIT) {
282                 uri = PAH_PORTRAIT_ANAALBUM_ALBUM_NAME;
283             } else if (photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::GROUP_PHOTO) {
284                 uri = PAH_GROUP_ANAALBUM_ALBUM_NAME;
285             } else {
286                 uri = PAH_SET_PHOTO_ALBUM_NAME;
287             }
288             property = PhotoAlbumColumns::ALBUM_NAME;
289             valuesBucket.Put(property, photoAlbum->GetAlbumName());
290             break;
291         case AlbumChangeOperation::SET_COVER_URI:
292             GetAlbumUpdateCoverUri(photoAlbum, uri);
293             property = PhotoAlbumColumns::ALBUM_COVER_URI;
294             valuesBucket.Put(property, photoAlbum->GetCoverUri());
295             break;
296         case AlbumChangeOperation::RESET_COVER_URI:
297             uri = PAH_RESET_ALBUM_COVER_URI;
298             break;
299         case AlbumChangeOperation::SET_DISPLAY_LEVEL:
300             uri = PAH_PORTRAIT_DISPLAY_LEVLE;
301             property = USER_DISPLAY_LEVEL;
302             valuesBucket.Put(property, photoAlbum->GetDisplayLevel());
303             break;
304         case AlbumChangeOperation::SET_IS_ME:
305             uri = PAH_PORTRAIT_IS_ME;
306             property = IS_ME;
307             valuesBucket.Put(property, 1);
308             break;
309         case AlbumChangeOperation::DISMISS:
310             uri = PAH_GROUP_ANAALBUM_DISMISS;
311             property = IS_REMOVED;
312             valuesBucket.Put(property, 1);
313             break;
314         default:
315             return false;
316     }
317     return true;
318 }
319 
SetAlbumPropertyExecute(MediaAlbumChangeRequestImpl * changeRequest,const AlbumChangeOperation changeOperation)320 static bool SetAlbumPropertyExecute(
321     MediaAlbumChangeRequestImpl* changeRequest, const AlbumChangeOperation changeOperation)
322 {
323     if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME &&
324         changeRequest->GetAlbumChangeOperations().front() == AlbumChangeOperation::CREATE_ALBUM) {
325         return true;
326     }
327 
328     DataShare::DataSharePredicates predicates;
329     DataShare::DataShareValuesBucket valuesBucket;
330     auto photoAlbum = changeRequest->GetPhotoAlbumInstance();
331     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, std::to_string(photoAlbum->GetAlbumId()));
332     string uri;
333     string property;
334     if (!GetAlbumUpdateValue(photoAlbum, changeOperation, uri, valuesBucket, property)) {
335         LOGE("Failed to parse album change operation: %{public}d", changeOperation);
336         return false;
337     }
338     valuesBucket.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbum->GetPhotoAlbumSubType());
339     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
340     Uri updateAlbumUri(uri);
341     int32_t changedRows = UserFileClient::Update(updateAlbumUri, predicates, valuesBucket);
342     if (changedRows < 0) {
343         LOGE("Failed to set %{public}s, err: %{public}d", property.c_str(), changedRows);
344         return false;
345     }
346     return true;
347 }
348 
349 static const unordered_map<AlbumChangeOperation, bool (*)(MediaAlbumChangeRequestImpl*)> EXECUTE_MAP = {
350     { AlbumChangeOperation::ADD_ASSETS, AddAssetsExecute },
351     { AlbumChangeOperation::REMOVE_ASSETS, RemoveAssetsExecute },
352 };
353 
ApplyChanges()354 int32_t MediaAlbumChangeRequestImpl::ApplyChanges()
355 {
356     if (!CheckChangeOperations()) {
357         LOGE("Failed to check album change request operations");
358         return OHOS_INVALID_PARAM_CODE;
359     }
360     unordered_set<AlbumChangeOperation> appliedOperations;
361     for (const auto& changeOperation : albumChangeOperations_) {
362         // Keep the final result(s) of each operation, and commit only once.
363         if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
364             continue;
365         }
366 
367         bool valid = false;
368         auto iter = EXECUTE_MAP.find(changeOperation);
369         if (iter != EXECUTE_MAP.end()) {
370             valid = iter->second(this);
371         } else if (changeOperation == AlbumChangeOperation::SET_ALBUM_NAME ||
372                    changeOperation == AlbumChangeOperation::SET_COVER_URI ||
373                    changeOperation == AlbumChangeOperation::SET_IS_ME ||
374                    changeOperation == AlbumChangeOperation::SET_DISPLAY_LEVEL ||
375                    changeOperation == AlbumChangeOperation::DISMISS ||
376                    changeOperation == AlbumChangeOperation::RESET_COVER_URI) {
377             valid = SetAlbumPropertyExecute(this, changeOperation);
378         } else {
379             LOGE("Invalid album change operation: %{public}d", changeOperation);
380             albumChangeOperations_.clear();
381             return OHOS_INVALID_PARAM_CODE;
382         }
383 
384         if (!valid) {
385             LOGE("Failed to apply album change request, operation: %{public}d", changeOperation);
386             albumChangeOperations_.clear();
387             return 0;
388         }
389         appliedOperations.insert(changeOperation);
390     }
391     albumChangeOperations_.clear();
392     return 0;
393 }
394 } // namespace Media
395 } // namespace OHOS