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