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 "cloud_sync_notify_handler.h"
17 
18 #include "cloud_media_asset_manager.h"
19 #include "cloud_media_asset_types.h"
20 #include "cloud_sync_utils.h"
21 #include "medialibrary_album_fusion_utils.h"
22 #include "notify_responsibility_chain_factory.h"
23 #include "thumbnail_service.h"
24 #include "medialibrary_rdb_utils.h"
25 #include "parameters.h"
26 #include "photo_album_column.h"
27 #include "media_log.h"
28 
29 using namespace std;
30 
31 namespace OHOS {
32 namespace Media {
33 using ChangeType = DataShare::DataShareObserver::ChangeType;
34 
35 const std::string INVALID_ZERO_ID = "0";
36 
IsCloudInsertTaskPriorityHigh()37 static bool IsCloudInsertTaskPriorityHigh()
38 {
39     int32_t cloudSyncStatus = static_cast<int32_t>(system::GetParameter(CLOUDSYNC_STATUS_KEY, "0").at(0) - '0');
40     return cloudSyncStatus == CloudSyncStatus::FIRST_FIVE_HUNDRED ||
41         cloudSyncStatus == CloudSyncStatus::INCREMENT_DOWNLOAD;
42 }
43 
IsCloudNotifyInfoValid(const string & cloudNotifyInfo)44 static inline bool IsCloudNotifyInfoValid(const string& cloudNotifyInfo)
45 {
46     if (cloudNotifyInfo.empty()) {
47         return false;
48     }
49     for (char const& ch : cloudNotifyInfo) {
50         if (isdigit(ch) == 0) {
51             return false;
52         }
53     }
54     return true;
55 }
56 
UpdateCloudAssetDownloadTask(const bool verifyFlag)57 static void UpdateCloudAssetDownloadTask(const bool verifyFlag)
58 {
59     if (!verifyFlag) {
60         MEDIA_INFO_LOG("Current status is not suitable for task.");
61         return;
62     }
63     if (!CloudMediaAssetManager::GetInstance().SetIsThumbnailUpdate() && CloudSyncUtils::IsCloudSyncSwitchOn() &&
64         CloudSyncUtils::IsCloudDataAgingPolicyOn()) {
65         CloudMediaAssetManager::GetInstance().StartDownloadCloudAsset(CloudMediaDownloadType::DOWNLOAD_GENTLE);
66     }
67 }
68 
HandleInsertEvent(const std::list<Uri> & uris)69 void CloudSyncNotifyHandler::HandleInsertEvent(const std::list<Uri> &uris)
70 {
71     bool isCloudInsertTaskPriorityHigh = IsCloudInsertTaskPriorityHigh();
72     if (!isCloudInsertTaskPriorityHigh && !ThumbnailService::GetInstance()->GetCurrentStatusForTask()) {
73         MEDIA_INFO_LOG("current status is not suitable for task");
74         return;
75     }
76     bool verifyFlag = false;
77     for (auto &uri : uris) {
78         string uriString = uri.ToString();
79         auto pos = uriString.find_last_of('/');
80         if (pos == string::npos) {
81             continue;
82         }
83         string idString = uriString.substr(pos + 1);
84         if (idString.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(idString)) {
85             MEDIA_WARN_LOG("cloud observer get no valid fileId and uri : %{public}s", uriString.c_str());
86             continue;
87         }
88         if (!verifyFlag) {
89             verifyFlag = true;
90         }
91         ThumbnailService::GetInstance()->CreateAstcCloudDownload(idString, isCloudInsertTaskPriorityHigh);
92     }
93     UpdateCloudAssetDownloadTask(verifyFlag);
94 }
95 
HandleDeleteEvent(const std::list<Uri> & uris)96 void CloudSyncNotifyHandler::HandleDeleteEvent(const std::list<Uri> &uris)
97 {
98     bool verifyFlag = false;
99     for (auto &uri : uris) {
100         string uriString = uri.ToString();
101         auto dateTakenPos = uriString.rfind('/');
102         if (dateTakenPos == string::npos) {
103             continue;
104         }
105         auto fileIdPos = uriString.rfind('/', dateTakenPos - 1);
106         if (fileIdPos == string::npos) {
107             continue;
108         }
109 
110         string dateTaken = uriString.substr(dateTakenPos + 1);
111         string fileId = uriString.substr(fileIdPos + 1, dateTakenPos - fileIdPos - 1);
112         if (!IsCloudNotifyInfoValid(dateTaken) || !IsCloudNotifyInfoValid(fileId)) {
113             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
114             continue;
115         }
116         if (!verifyFlag) {
117             verifyFlag = true;
118         }
119 
120         ThumbnailService::GetInstance()->DeleteAstcWithFileIdAndDateTaken(fileId, dateTaken);
121     }
122     if (verifyFlag) {
123         CloudMediaAssetManager::GetInstance().SetIsThumbnailUpdate();
124     }
125 }
126 
HandleTimeUpdateEvent(const std::list<Uri> & uris)127 void CloudSyncNotifyHandler::HandleTimeUpdateEvent(const std::list<Uri> &uris)
128 {
129     for (auto &uri : uris) {
130         string uriString = uri.ToString();
131         auto newDateTakenPos = uriString.rfind('/');
132         if (newDateTakenPos == string::npos) {
133             continue;
134         }
135         auto formerDateTakenPos = uriString.rfind('/', newDateTakenPos - 1);
136         if (formerDateTakenPos == string::npos) {
137             continue;
138         }
139         auto fileIdPos = uriString.rfind('/', formerDateTakenPos - 1);
140         if (fileIdPos == string::npos) {
141             continue;
142         }
143 
144         string newDateTaken = uriString.substr(newDateTakenPos + 1);
145         string formerDateTaken = uriString.substr(formerDateTakenPos + 1, newDateTakenPos - formerDateTakenPos - 1);
146         string fileId = uriString.substr(fileIdPos + 1, formerDateTakenPos - fileIdPos - 1);
147         if (!IsCloudNotifyInfoValid(newDateTaken) || !IsCloudNotifyInfoValid(formerDateTaken) ||
148             !IsCloudNotifyInfoValid(fileId)) {
149             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
150             continue;
151         }
152 
153         ThumbnailService::GetInstance()->UpdateAstcWithNewDateTaken(fileId, newDateTaken, formerDateTaken);
154     }
155 }
156 
HandleExtraEvent(const std::list<Uri> & uris,const ChangeType & type)157 void CloudSyncNotifyHandler::HandleExtraEvent(const std::list<Uri> &uris, const ChangeType &type)
158 {
159     ExtraChangeType extraType = static_cast<ExtraChangeType>(type);
160     if (extraType == ExtraChangeType::PHOTO_TIME_UPDATE) {
161         HandleTimeUpdateEvent(uris);
162         return;
163     }
164     MEDIA_DEBUG_LOG("change type is %{public}d, no need ThumbnailObserverOnChange", type);
165 }
166 
ThumbnailObserverOnChange(const list<Uri> & uris,const ChangeType & type)167 void CloudSyncNotifyHandler::ThumbnailObserverOnChange(const list<Uri> &uris, const ChangeType &type)
168 {
169     MediaLibraryRdbUtils::SetNeedRefreshAlbum(true);
170     switch (type) {
171         case ChangeType::INSERT:
172             HandleInsertEvent(uris);
173             break;
174         case ChangeType::DELETE:
175             HandleDeleteEvent(uris);
176             break;
177         default:
178             HandleExtraEvent(uris, type);
179             break;
180     }
181 }
182 
MakeResponsibilityChain()183 void CloudSyncNotifyHandler::MakeResponsibilityChain()
184 {
185     string uriString = notifyInfo_.uris.front().ToString();
186     MEDIA_DEBUG_LOG("observer get first uri is : %{public}s", uriString.c_str());
187 
188     if (uriString.find("file://cloudsync/Photo/HeightError/") != string::npos) {
189         return;
190     }
191 
192     if (uriString.find("file://cloudsync/Photo/DownloadSuccessed/") != string::npos) {
193         return;
194     }
195 
196     if (uriString.find(PhotoColumn::PHOTO_CLOUD_URI_PREFIX) != string::npos) {
197         ThumbnailObserverOnChange(notifyInfo_.uris, notifyInfo_.type);
198     }
199 
200     if (uriString.find("file://cloudsync/Photo/RebuildCloudData/") != string::npos) {
201         MEDIA_INFO_LOG("Get cloud rebuild cloud data notification : %{public}s",
202             "file://cloudsync/Photo/RebuildCloudData/");
203         MediaLibraryAlbumFusionUtils::CleanInvalidCloudAlbumAndData();
204     }
205 
206     shared_ptr<BaseHandler> chain = nullptr;
207 
208     if (uriString.find(PhotoAlbumColumns::ALBUM_CLOUD_URI_PREFIX) != string::npos) {
209         if (notifyInfo_.type == ChangeType::DELETE) {
210             chain = NotifyResponsibilityChainFactory::CreateChain(ALBUM_DELETE);
211         } else {
212             chain = NotifyResponsibilityChainFactory::CreateChain(TRANSPARENT);
213         }
214     }
215 
216     if (uriString.find(PhotoColumn::PHOTO_CLOUD_URI_PREFIX) != string::npos) {
217         if (notifyInfo_.type == ChangeType::UPDATE || notifyInfo_.type == ChangeType::OTHER) {
218             chain = NotifyResponsibilityChainFactory::CreateChain(PHOTODELETE);
219         } else {
220             chain = NotifyResponsibilityChainFactory::CreateChain(TRANSPARENT);
221         }
222     }
223     CloudSyncHandleData handleData;
224     handleData.orgInfo = notifyInfo_;
225     if (chain == nullptr) {
226         MEDIA_ERR_LOG("uri OR type is Invalid");
227         return;
228     }
229     chain->Handle(handleData);
230 }
231 } //namespace Media
232 } //namespace OHOS
233