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 #define MLOG_TAG "MediaLibraryCloudUploadChecker"
17 
18 #include "cloud_upload_checker.h"
19 
20 #include "media_file_utils.h"
21 #include "media_file_uri.h"
22 #include "medialibrary_unistore_manager.h"
23 #include "photo_album_column.h"
24 #include "thumbnail_const.h"
25 #include "media_column.h"
26 #include "preferences.h"
27 #include "preferences_helper.h"
28 #include "result_set_utils.h"
29 #include "thumbnail_const.h"
30 #include "medialibrary_object_utils.h"
31 #include "medialibrary_photo_operations.h"
32 
33 namespace OHOS {
34 namespace Media {
35 using namespace std;
36 using namespace NativeRdb;
37 const std::string BATCH_SIZE = "500";
38 const std::string TASK_PROGRESS_XML = "/data/storage/el2/base/preferences/task_progress.xml";
39 const std::string NO_ORIGIN_PHOTO_NUMBER = "no_origin_photo_number";
40 
41 static const int32_t NO_ORIGIN_BUT_LCD = 100;
42 static const int32_t NO_ORIGIN_NO_LCD = 101;
43 
HandleNoOriginPhoto()44 void CloudUploadChecker::HandleNoOriginPhoto()
45 {
46     MEDIA_INFO_LOG("start handle no origin photo!");
47     int32_t errCode;
48     shared_ptr<NativePreferences::Preferences> prefs =
49         NativePreferences::PreferencesHelper::GetPreferences(TASK_PROGRESS_XML, errCode);
50     if (!prefs) {
51         MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
52         return;
53     }
54     int32_t curFileId = prefs->GetInt(NO_ORIGIN_PHOTO_NUMBER, 0);
55     MEDIA_INFO_LOG("start file id: %{public}d", curFileId);
56     while (GetPhotoCount(curFileId) > 0) {
57         MEDIA_INFO_LOG("start handle origin photo start: %{public}d", curFileId);
58         int32_t nextFileId = curFileId;
59         std::vector<CheckedPhotoInfo> photoInfos = QueryPhotoInfo(curFileId, nextFileId);
60         HandlePhotoInfos(photoInfos);
61         curFileId = nextFileId + 1;
62         prefs->PutInt(NO_ORIGIN_PHOTO_NUMBER, curFileId);
63         prefs->FlushSync();
64     }
65     MEDIA_INFO_LOG("end handle no origin photo!");
66     return;
67 }
68 
HandlePhotoInfos(std::vector<CheckedPhotoInfo> photoInfos)69 void CloudUploadChecker::HandlePhotoInfos(std::vector<CheckedPhotoInfo> photoInfos)
70 {
71     std::vector<std::string> lcdList;
72     std::vector<std::string> noLcdList;
73     for (CheckedPhotoInfo photoInfo: photoInfos) {
74         if (MediaFileUtils::IsFileExists(photoInfo.path)) {
75             continue;
76         }
77         string lcdPath = GetThumbnailPath(photoInfo.path, THUMBNAIL_LCD_SUFFIX);
78         if (MediaFileUtils::IsFileExists(lcdPath)) {
79             lcdList.push_back(to_string(photoInfo.fileId));
80         } else {
81             noLcdList.push_back(to_string(photoInfo.fileId));
82         }
83     }
84     if (!lcdList.empty()) {
85         UpdateDirty(lcdList, NO_ORIGIN_BUT_LCD);
86     }
87     if (!noLcdList.empty()) {
88         UpdateDirty(noLcdList, NO_ORIGIN_NO_LCD);
89     }
90 }
91 
UpdateDirty(std::vector<std::string> idList,int32_t dirtyType)92 void CloudUploadChecker::UpdateDirty(std::vector<std::string> idList, int32_t dirtyType)
93 {
94     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
95     if (rdbStore == nullptr) {
96         MEDIA_ERR_LOG("Failed to get rdbstore!");
97         return;
98     }
99     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
100     predicates.In(MediaColumn::MEDIA_ID, idList);
101     ValuesBucket values;
102     values.PutInt(PhotoColumn::PHOTO_DIRTY, dirtyType);
103     int32_t updateCount = 0;
104     int32_t err = rdbStore->Update(updateCount, values, predicates);
105     MEDIA_INFO_LOG("dirty: %{public}d, idList size: %{public}d, update size: %{public}d, err: %{public}d", dirtyType,
106         static_cast<int32_t>(idList.size()), updateCount, err);
107 }
108 
GetPhotoCount(int32_t startFileId)109 int32_t CloudUploadChecker::GetPhotoCount(int32_t startFileId)
110 {
111     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
112     if (rdbStore == nullptr) {
113         MEDIA_ERR_LOG("Failed to get rdbstore!");
114         return 0;
115     }
116     std::string queryCount = " COUNT(*) AS Count";
117     std::string sql = GetQuerySql(startFileId, queryCount);
118     std::shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(sql);
119     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
120         MEDIA_ERR_LOG("resultSet is null or count is 0");
121         return 0;
122     }
123     int32_t count = get<int32_t>(ResultSetUtils::GetValFromColumn("Count", resultSet, TYPE_INT32));
124     return count;
125 }
126 
GetQuerySql(int32_t startFileId,std::string mediaColumns)127 std::string CloudUploadChecker::GetQuerySql(int32_t startFileId, std::string mediaColumns)
128 {
129     const std::string sql = "SELECT " + mediaColumns + " FROM Photos WHERE dirty = 1 AND thumbnail_ready >= 3 AND " +
130         "lcd_visit_time >= 2 AND date_trashed = 0 AND file_id > " + to_string(startFileId) + " LIMIT " + BATCH_SIZE;
131     return sql;
132 }
133 
QueryPhotoInfo(int32_t startFileId,int32_t & outFileId)134 std::vector<CheckedPhotoInfo> CloudUploadChecker::QueryPhotoInfo(int32_t startFileId, int32_t &outFileId)
135 {
136     std::vector<CheckedPhotoInfo> photoInfos;
137     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
138     if (rdbStore == nullptr) {
139         MEDIA_ERR_LOG("Failed to get rdbstore!");
140         return photoInfos;
141     }
142     const std::string mediaColumns = Media::PhotoColumn::MEDIA_ID + ", " + Media::PhotoColumn::MEDIA_FILE_PATH;
143     std::string sql = GetQuerySql(startFileId, mediaColumns);
144     std::shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(sql);
145     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
146         MEDIA_ERR_LOG("resultSet is null or count is 0");
147         return photoInfos;
148     }
149     int32_t fileId = startFileId;
150     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
151         CheckedPhotoInfo photoInfo;
152         std::string path =
153             get<std::string>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_FILE_PATH, resultSet, TYPE_STRING));
154         if (path.empty()) {
155             MEDIA_WARN_LOG("Failed to get data path");
156             continue;
157         }
158         fileId = get<int32_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_ID, resultSet, TYPE_INT32));
159         photoInfo.fileId = fileId;
160         photoInfo.path = path;
161         photoInfos.push_back(photoInfo);
162     }
163     outFileId = fileId;
164     return photoInfos;
165 }
166 } // namespace Media
167 } // namespace OHOS