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 #include <string>
16 #include <vector>
17
18 #include "photos_restore.h"
19 #include "backup_const.h"
20 #include "backup_file_utils.h"
21 #include "userfile_manager_types.h"
22 #include "rdb_store.h"
23 #include "result_set_utils.h"
24 #include "media_log.h"
25 #include "photo_album_dao.h"
26 #include "album_plugin_config.h"
27 #include "backup_file_utils.h"
28 #include "mimetype_utils.h"
29
30 namespace OHOS::Media {
31 /**
32 * @brief Get the gallery_media to restore to Photos.
33 */
GetGalleryMedia(int32_t offset,int pageSize,bool shouldIncludeSd,bool hasLowQualityImage)34 std::shared_ptr<NativeRdb::ResultSet> PhotosRestore::GetGalleryMedia(
35 int32_t offset, int pageSize, bool shouldIncludeSd, bool hasLowQualityImage)
36 {
37 return this->galleryMediaDao_.GetGalleryMedia(offset, pageSize, shouldIncludeSd, hasLowQualityImage);
38 }
39
40 /**
41 * @brief Get the row count of gallery_media.
42 */
GetGalleryMediaCount(bool shouldIncludeSd,bool hasLowQualityImage)43 int32_t PhotosRestore::GetGalleryMediaCount(bool shouldIncludeSd, bool hasLowQualityImage)
44 {
45 return this->galleryMediaDao_.GetGalleryMediaCount(shouldIncludeSd, hasLowQualityImage);
46 }
47
48 /**
49 * @brief Parse the sourcePath to lPath.
50 * example, sourcePath=/storage/emulated/0/DCIM/Camera/IMG_20240829_072213.jpg, lPath=/DCIM/Camera
51 * if the sourcePath can not be parsed, return /Pictures/其它.
52 */
ParseSourcePathToLPath(const std::string & sourcePath)53 std::string PhotosRestore::ParseSourcePathToLPath(const std::string &sourcePath)
54 {
55 size_t start_pos = sourcePath.find(GALLERT_ROOT_PATH);
56 size_t end_pos = sourcePath.find_last_of("/");
57
58 std::string result = "/Pictures/其它";
59 if (start_pos != std::string::npos && end_pos != std::string::npos) {
60 start_pos += GALLERT_ROOT_PATH.length();
61 result = sourcePath.substr(start_pos, end_pos - start_pos);
62 start_pos = result.find_first_of("/");
63 if (start_pos != std::string::npos) {
64 result = result.substr(start_pos);
65 }
66 }
67 return result;
68 }
69
70 /**
71 * @brief Build PhotoAlbumRowData from lPath.
72 */
BuildAlbumInfoByLPath(const std::string & lPath)73 PhotoAlbumDao::PhotoAlbumRowData PhotosRestore::BuildAlbumInfoByLPath(const std::string &lPath)
74 {
75 PhotoAlbumDao::PhotoAlbumRowData albumInfo;
76 // find albumName from lPath
77 std::string albumName = "其它";
78 std::string albumlPath = lPath;
79 size_t fileIndex = albumlPath.find_last_of(FILE_SEPARATOR);
80 if (fileIndex != string::npos) {
81 albumName = albumlPath.substr(fileIndex + 1);
82 } else {
83 albumlPath = "/Pictures/其它";
84 }
85 albumInfo.albumName = albumName;
86 albumInfo.lPath = albumlPath;
87 albumInfo.albumType = static_cast<int32_t>(PhotoAlbumType::SOURCE);
88 albumInfo.albumSubType = static_cast<int32_t>(PhotoAlbumSubType::SOURCE_GENERIC);
89 albumInfo.priority = 1;
90 return albumInfo;
91 }
92
93 /**
94 * @brief Get the PhotoAlbum basic info.
95 */
FindAlbumInfo(const FileInfo & fileInfo)96 PhotoAlbumDao::PhotoAlbumRowData PhotosRestore::FindAlbumInfo(const FileInfo &fileInfo)
97 {
98 PhotoAlbumDao::PhotoAlbumRowData albumInfo;
99 // Scenario 1, WHEN FileInfo is in /Pictures/Screenshots and Video type, THEN redirect to /Pictures/Screenrecords
100 std::string lPathForScreenshot =
101 fileInfo.lPath.empty() ? this->ParseSourcePathToLPath(fileInfo.sourcePath) : fileInfo.lPath;
102 if (this->ToLower(lPathForScreenshot) == this->ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
103 fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
104 MEDIA_INFO_LOG("Media_Restore: screenshots redirect to screenrecords, fileInfo.lPath: %{public}s, "
105 "lPathForScreenshot: %{public}s, Object: %{public}s",
106 fileInfo.lPath.c_str(),
107 lPathForScreenshot.c_str(),
108 this->ToString(fileInfo).c_str());
109 albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
110 albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
111 return albumInfo;
112 }
113 // Scenario 2, WHEN FileInfo is in hidden album, THEN override lPath to the folder in sourcePath.
114 // Scenario 3, WHEN FileInfo is not belongs to any album, THEN override lPath to the folder in sourcePath.
115 if (fileInfo.lPath.empty() || this->ToLower(fileInfo.lPath) == this->ToLower(GALLERT_HIDDEN_ALBUM)) {
116 std::string lPathFromSourcePath = this->ParseSourcePathToLPath(fileInfo.sourcePath);
117 albumInfo = this->BuildAlbumInfoByLPath(lPathFromSourcePath);
118 albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
119 MEDIA_INFO_LOG("Media_Restore: fix lPath of album.fileInfo.lPath: %{public}s, "
120 "lPathFromSourcePath: %{public}s, lowercase: %{public}s, "
121 "FileInfo Object: %{public}s, AlbumInfo Object: %{public}s",
122 fileInfo.lPath.c_str(),
123 lPathFromSourcePath.c_str(),
124 this->ToLower(lPathFromSourcePath).c_str(),
125 this->ToString(fileInfo).c_str(),
126 this->photoAlbumDao_.ToString(albumInfo).c_str());
127 return albumInfo;
128 }
129 return this->photoAlbumDao_.GetPhotoAlbum(fileInfo.lPath);
130 }
131
132 /**
133 * @brief Get the PhotoAlbum basic info.
134 */
FindAlbumId(const FileInfo & fileInfo)135 int32_t PhotosRestore::FindAlbumId(const FileInfo &fileInfo)
136 {
137 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
138 if (albumInfo.lPath.empty()) {
139 MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
140 fileInfo.lPath.c_str(),
141 fileInfo.sourcePath.c_str());
142 }
143 return albumInfo.albumId;
144 }
145
146 /**
147 * @brief find lPath by FileInfo.
148 */
FindlPath(const FileInfo & fileInfo)149 std::string PhotosRestore::FindlPath(const FileInfo &fileInfo)
150 {
151 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
152 if (albumInfo.lPath.empty()) {
153 MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
154 fileInfo.lPath.c_str(),
155 fileInfo.sourcePath.c_str());
156 }
157 return albumInfo.lPath;
158 }
159
160 /**
161 * @brief Find PackageName by FileInfo.
162 */
FindPackageName(const FileInfo & fileInfo)163 std::string PhotosRestore::FindPackageName(const FileInfo &fileInfo)
164 {
165 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
166 if (albumInfo.lPath.empty()) {
167 MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
168 fileInfo.lPath.c_str(),
169 fileInfo.sourcePath.c_str());
170 }
171 return albumInfo.albumName;
172 }
173
174 /**
175 * @brief Find BundleName by FileInfo.
176 */
FindBundleName(const FileInfo & fileInfo)177 std::string PhotosRestore::FindBundleName(const FileInfo &fileInfo)
178 {
179 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
180 if (albumInfo.lPath.empty()) {
181 MEDIA_ERR_LOG("Can not find PhotoAlbum. fileInfo.lPath= %{public}s, fileInfo.sourcePath= %{public}s",
182 fileInfo.lPath.c_str(),
183 fileInfo.sourcePath.c_str());
184 }
185 return albumInfo.bundleName;
186 }
187
188 /**
189 * @brief Find BurstKey by FileInfo.
190 */
FindBurstKey(const FileInfo & fileInfo)191 std::string PhotosRestore::FindBurstKey(const FileInfo &fileInfo)
192 {
193 if (fileInfo.burstKey.size() > 0) {
194 return fileInfo.burstKey;
195 }
196 return "";
197 }
198
199 /**
200 * @brief Find Dirty by FileInfo.
201 */
FindDirty(const FileInfo & fileInfo)202 int32_t PhotosRestore::FindDirty(const FileInfo &fileInfo)
203 {
204 return static_cast<int32_t>(DirtyTypes::TYPE_NEW);
205 }
206
207 /**
208 * @brief Find burst_cover_level by FileInfo.
209 */
FindBurstCoverLevel(const FileInfo & fileInfo)210 int32_t PhotosRestore::FindBurstCoverLevel(const FileInfo &fileInfo)
211 {
212 // identify burst photo
213 if (fileInfo.isBurst == static_cast<int32_t>(BurstCoverLevelType::COVER) ||
214 fileInfo.isBurst == static_cast<int32_t>(BurstCoverLevelType::MEMBER)) {
215 return fileInfo.isBurst;
216 }
217 return static_cast<int32_t>(BurstCoverLevelType::COVER);
218 }
219
220 /**
221 * @brief Find subtype by FileInfo.
222 */
FindSubtype(const FileInfo & fileInfo)223 int32_t PhotosRestore::FindSubtype(const FileInfo &fileInfo)
224 {
225 if (fileInfo.burstKey.size() > 0) {
226 return static_cast<int32_t>(PhotoSubType::BURST);
227 }
228 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
229 return static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
230 }
231 return static_cast<int32_t>(PhotoSubType::DEFAULT);
232 }
233
234 /**
235 * @brief Find date_trashed by FileInfo.
236 */
FindDateTrashed(const FileInfo & fileInfo)237 int64_t PhotosRestore::FindDateTrashed(const FileInfo &fileInfo)
238 {
239 // prevent Photos marked as deleted when it's in use.
240 if (fileInfo.recycleFlag == 0) {
241 return 0;
242 }
243 // LOG INFO for analyser.
244 if (fileInfo.recycledTime != 0) {
245 string fileName = fileInfo.displayName;
246 MEDIA_WARN_LOG("the file :%{public}s is trash.", BackupFileUtils::GarbleFileName(fileName).c_str());
247 }
248 return fileInfo.recycledTime;
249 }
250
251 /**
252 * @brief Get duplicate data in gallery db.
253 */
GetDuplicateData(int32_t duplicateDataCount)254 void PhotosRestore::GetDuplicateData(int32_t duplicateDataCount)
255 {
256 if (duplicateDataCount <= 0) {
257 return;
258 }
259 std::string querySql = this->SQL_GALLERY_MEDIA_QUERY_DUPLICATE_DATA;
260 int rowCount = 0;
261 int offset = 0;
262 int pageSize = 200;
263 do {
264 std::vector<NativeRdb::ValueObject> params = {offset, pageSize};
265 if (this->galleryRdb_ == nullptr) {
266 MEDIA_ERR_LOG("Media_Restore: galleryRdb_ is null.");
267 break;
268 }
269 auto resultSet = this->galleryRdb_->QuerySql(querySql, params);
270 if (resultSet == nullptr) {
271 MEDIA_ERR_LOG("Query resultSql is null.");
272 break;
273 }
274 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
275 std::string data = GetStringVal(GALLERY_FILE_DATA, resultSet);
276 int32_t count = GetInt32Val(CUSTOM_COUNT, resultSet);
277 this->duplicateDataUsedCountMap_[data] = 0;
278 MEDIA_INFO_LOG("Get duplicate data: %{public}s, count: %{public}d",
279 BackupFileUtils::GarbleFilePath(data, DEFAULT_RESTORE_ID).c_str(),
280 count);
281 }
282 // Check if there are more rows to fetch.
283 resultSet->GetRowCount(rowCount);
284 offset += pageSize;
285 } while (rowCount > 0);
286 }
287
288 /**
289 * @brief Check if it is duplicate data in gallery db.
290 */
IsDuplicateData(const std::string & data)291 bool PhotosRestore::IsDuplicateData(const std::string &data)
292 {
293 std::lock_guard<mutex> lock(this->duplicateDataUsedCountMutex_);
294 if (this->duplicateDataUsedCountMap_.count(data) == 0) {
295 return false;
296 }
297 this->duplicateDataUsedCountMap_[data]++;
298 return this->duplicateDataUsedCountMap_.at(data) > 1;
299 }
300
301 /**
302 * @brief Find PhotoQuality by FileInfo.
303 */
FindPhotoQuality(const FileInfo & fileInfo)304 int32_t PhotosRestore::FindPhotoQuality(const FileInfo &fileInfo)
305 {
306 if (fileInfo.photoQuality == 1 && fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
307 return 0;
308 }
309 return fileInfo.photoQuality;
310 }
311
312 /**
313 * @brief Find suffix of displayName. include dot, e.g. ".jpg"
314 * @return return the suffix of displayName. "" if not found.
315 */
GetSuffix(const std::string & displayName)316 std::string PhotosRestore::GetSuffix(const std::string &displayName)
317 {
318 size_t dotPos = displayName.rfind('.');
319 if (dotPos != std::string::npos) {
320 return this->ToLower(displayName.substr(dotPos + 1)); // without dot, e.g. "jpg"
321 }
322 return "";
323 }
324
325 /**
326 * @brief Find media_type by FileInfo.
327 */
FindMediaType(const FileInfo & fileInfo)328 int32_t PhotosRestore::FindMediaType(const FileInfo &fileInfo)
329 {
330 int32_t dualMediaType = fileInfo.fileType;
331 if (dualMediaType == DUAL_MEDIA_TYPE::IMAGE_TYPE || dualMediaType == DUAL_MEDIA_TYPE::VIDEO_TYPE) {
332 return dualMediaType == DUAL_MEDIA_TYPE::VIDEO_TYPE ? MediaType::MEDIA_TYPE_VIDEO : MediaType::MEDIA_TYPE_IMAGE;
333 }
334 std::string suffix = this->GetSuffix(fileInfo.displayName);
335 MediaType mediaType = MimeTypeUtils::GetMediaTypeFromMimeType(MimeTypeUtils::GetMimeTypeFromExtension(suffix));
336 MEDIA_INFO_LOG("Media_Restore: correct mediaType from %{public}d to %{public}d, displayName: %{public}s",
337 fileInfo.fileType,
338 mediaType,
339 fileInfo.displayName.c_str());
340 return mediaType;
341 }
342 } // namespace OHOS::Media