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 <chrono>
17 #include <vector>
18 #include <string>
19 #include <thread>
20
21 #include "cloud_sync_observer.h"
22
23 #include "cloud_media_asset_manager.h"
24 #include "cloud_sync_notify_handler.h"
25 #include "media_analysis_helper.h"
26 #include "media_file_utils.h"
27 #include "medialibrary_unistore_manager.h"
28 #include "media_column.h"
29 #include "media_log.h"
30 #include "result_set_utils.h"
31 #include "albums_refresh_manager.h"
32 #include "photo_album_column.h"
33 #include "albums_refresh_notify.h"
34 #include "notify_responsibility_chain_factory.h"
35 #include "post_event_utils.h"
36
37 using namespace std;
38
39 namespace OHOS {
40 namespace Media {
41 constexpr int32_t SYNC_INTERVAL = 10000;
HandleCloudNotify(AsyncTaskData * data)42 static void HandleCloudNotify(AsyncTaskData *data)
43 {
44 auto* taskData = static_cast<CloudSyncNotifyData*>(data);
45 shared_ptr<CloudSyncNotifyHandler> notifyHandler = make_shared<CloudSyncNotifyHandler>(taskData->notifyInfo_);
46 notifyHandler->MakeResponsibilityChain();
47 }
48
DealCloudSync(const ChangeInfo & changeInfo)49 void CloudSyncObserver::DealCloudSync(const ChangeInfo &changeInfo)
50 {
51 SyncNotifyInfo info;
52 info.uris = changeInfo.uris_;
53 std::string dataString = (const char *)changeInfo.data_;
54 if (!nlohmann::json::accept(dataString)) {
55 MEDIA_WARN_LOG("Failed to verify the meataData format, metaData is: %{public}s", dataString.c_str());
56 return;
57 }
58 nlohmann::json jsonData = nlohmann::json::parse(dataString);
59 if (jsonData.contains("taskType")) {
60 info.taskType = jsonData["taskType"];
61 }
62 if (jsonData.contains("syncId")) {
63 info.syncId = jsonData["syncId"];
64 }
65 if (jsonData.contains("syncType")) {
66 info.syncType = jsonData["syncType"];
67 }
68 if (jsonData.contains("totalAssets")) {
69 info.totalAssets = jsonData["totalAssets"];
70 }
71 if (jsonData.contains("totalAlbums")) {
72 info.totalAlbums = jsonData["totalAlbums"];
73 }
74 if (info.taskType == TIME_BEGIN_SYNC) {
75 PostEventUtils::GetInstance().CreateCloudDownloadSyncStat(info.syncId);
76 VariantMap map = {
77 {KEY_START_DOWNLOAD_TIME, MediaFileUtils::UTCTimeMilliSeconds()}, {KEY_DOWNLOAD_TYPE, info.syncType}};
78 PostEventUtils::GetInstance().UpdateCloudDownloadSyncStat(map);
79 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
80 } else if (info.taskType == TIME_END_SYNC) {
81 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
82 }
83 }
84
DealAlbumGallery(CloudSyncNotifyInfo & notifyInfo)85 void CloudSyncObserver::DealAlbumGallery(CloudSyncNotifyInfo ¬ifyInfo)
86 {
87 SyncNotifyInfo info = AlbumsRefreshManager::GetInstance().GetSyncNotifyInfo(notifyInfo, ALBUM_URI_TYPE);
88 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
89 VariantMap map;
90 if (info.notifyType == NOTIFY_ADD) {
91 map = {{KEY_TOTAL_ALBUM_NUM, info.urisSize}, {KEY_ADD_ALBUM_NUM, info.urisSize}};
92 } else if (info.notifyType == NOTIFY_UPDATE) {
93 map = {{KEY_TOTAL_ALBUM_NUM, info.urisSize}, {KEY_UPDATE_ALBUM_NUM, info.urisSize}};
94 } else if (info.notifyType == NOTIFY_REMOVE) {
95 map = {{KEY_TOTAL_ALBUM_NUM, info.urisSize}, {KEY_DELETE_ALBUM_NUM, info.urisSize}};
96 }
97 PostEventUtils::GetInstance().UpdateCloudDownloadSyncStat(map);
98 }
99
DealPhotoGallery(CloudSyncNotifyInfo & notifyInfo)100 void CloudSyncObserver::DealPhotoGallery(CloudSyncNotifyInfo ¬ifyInfo)
101 {
102 if (notifyInfo.type == ChangeType::UPDATE || notifyInfo.type == ChangeType::OTHER) {
103 CloudSyncHandleData handleData;
104 handleData.orgInfo = notifyInfo;
105 shared_ptr<BaseHandler> chain = NotifyResponsibilityChainFactory::CreateChain(GALLERY_PHOTO_DELETE);
106 if (chain != nullptr) {
107 chain->Handle(handleData);
108 } else {
109 MEDIA_ERR_LOG("uri OR type is Invalid");
110 }
111 }
112 SyncNotifyInfo info = AlbumsRefreshManager::GetInstance().GetSyncNotifyInfo(notifyInfo, PHOTO_URI_TYPE);
113 AlbumsRefreshManager::GetInstance().AddAlbumRefreshTask(info);
114 VariantMap map;
115 if (info.notifyType == NOTIFY_ADD) {
116 map = {{KEY_TOTAL_ASSET_NUM, info.urisSize}, {KEY_ADD_ASSET_NUM, info.urisSize}};
117 } else if (info.notifyType == NOTIFY_UPDATE) {
118 map = {{KEY_TOTAL_ASSET_NUM, info.urisSize}, {KEY_UPDATE_ASSET_NUM, info.urisSize}};
119 } else if (info.notifyType == NOTIFY_REMOVE) {
120 map = {{KEY_TOTAL_ASSET_NUM, info.urisSize}, {KEY_DELETE_ASSET_NUM, info.urisSize}};
121 }
122 PostEventUtils::GetInstance().UpdateCloudDownloadSyncStat(map);
123 if (notifyInfo.type == ChangeType::DELETE) {
124 CloudMediaAssetManager::GetInstance().SetIsThumbnailUpdate();
125 }
126 }
127
DealGalleryDownload(CloudSyncNotifyInfo & notifyInfo)128 void CloudSyncObserver::DealGalleryDownload(CloudSyncNotifyInfo ¬ifyInfo)
129 {
130 if (notifyInfo.type == ChangeType::OTHER) {
131 if (notifyInfo.uris.empty()) {
132 MEDIA_ERR_LOG("gallery download notify uri empty");
133 return;
134 }
135 string uriString = notifyInfo.uris.front().ToString();
136 string downloadString = "gallery/download";
137 string::size_type pos = uriString.find(downloadString);
138 if (pos == string::npos) {
139 MEDIA_ERR_LOG("gallery download notify uri err");
140 return;
141 }
142 auto it = notifyInfo.uris.begin();
143 *it = Uri(uriString.replace(pos, downloadString.length(), "Photo"));
144 notifyInfo.type = ChangeType::UPDATE;
145 CloudSyncHandleData handleData;
146 handleData.orgInfo = notifyInfo;
147 shared_ptr<BaseHandler> chain = NotifyResponsibilityChainFactory::CreateChain(TRANSPARENT);
148 if (chain != nullptr) {
149 chain->Handle(handleData);
150 }
151 }
152 }
153
OnChange(const ChangeInfo & changeInfo)154 void CloudSyncObserver::OnChange(const ChangeInfo &changeInfo)
155 {
156 CloudSyncNotifyInfo notifyInfo = {changeInfo.uris_, changeInfo.changeType_, changeInfo.data_};
157 string uriString = notifyInfo.uris.front().ToString();
158 MEDIA_DEBUG_LOG("#uriString: %{public}s, #uriSize: %{public}zu changeType: %{public}d",
159 uriString.c_str(), changeInfo.uris_.size(), changeInfo.changeType_);
160
161 if (uriString.find(PhotoAlbumColumns::PHOTO_GALLERY_CLOUD_SYNC_INFO_URI_PREFIX) != string::npos) {
162 DealCloudSync(changeInfo);
163 return;
164 }
165
166 if (uriString.find(PhotoColumn::PHOTO_CLOUD_URI_PREFIX) != string::npos && notifyInfo.type == ChangeType::OTHER) {
167 lock_guard<mutex> lock(syncMutex_);
168 if (!isPending_) {
169 MEDIA_INFO_LOG("set timer handle index");
170 std::thread([this]() { this->HandleIndex(); }).detach();
171 isPending_ = true;
172 }
173 }
174
175 if (uriString.find(PhotoAlbumColumns::ALBUM_GALLERY_CLOUD_URI_PREFIX) != string::npos) {
176 DealAlbumGallery(notifyInfo);
177 return;
178 }
179
180 if (uriString.find(PhotoColumn::PHOTO_GALLERY_CLOUD_URI_PREFIX) != string::npos) {
181 DealPhotoGallery(notifyInfo);
182 return;
183 }
184
185 if (uriString.find(PhotoAlbumColumns::PHOTO_GALLERY_DOWNLOAD_URI_PREFIX) != string::npos) {
186 DealGalleryDownload(notifyInfo);
187 return;
188 }
189
190 auto *taskData = new (nothrow) CloudSyncNotifyData(notifyInfo);
191 CHECK_AND_RETURN_LOG(taskData != nullptr, "Failed to new taskData");
192 shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
193 if (asyncWorker == nullptr) {
194 MEDIA_ERR_LOG("Can not get asyncWorker");
195 delete taskData;
196 return;
197 }
198 shared_ptr<MediaLibraryAsyncTask> notifyHandleAsyncTask = make_shared<MediaLibraryAsyncTask>(
199 HandleCloudNotify, taskData);
200 if (notifyHandleAsyncTask != nullptr) {
201 asyncWorker->AddTask(notifyHandleAsyncTask, true);
202 }
203 }
204
HandleIndex()205 void CloudSyncObserver::HandleIndex()
206 {
207 std::this_thread::sleep_for(std::chrono::milliseconds(SYNC_INTERVAL));
208 lock_guard<mutex> lock(syncMutex_);
209 std::vector<std::string> idToDeleteIndex;
210 MediaAnalysisHelper::AsyncStartMediaAnalysisService(
211 static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_DELETE_INDEX), idToDeleteIndex);
212
213 //update index
214 auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
215 CHECK_AND_RETURN_LOG(uniStore != nullptr, "uniStore is nullptr!");
216 const std::string queryIdToUpdateIndex = "SELECT file_id FROM tab_analysis_search_index WHERE photo_status = 2";
217 auto resultSetUpdateIndex = uniStore->QuerySql(queryIdToUpdateIndex);
218 CHECK_AND_RETURN_LOG(resultSetUpdateIndex != nullptr, "resultSetUpdateIndex is nullptr!");
219 std::vector<std::string> idToUpdateIndex;
220 while (resultSetUpdateIndex->GoToNextRow() == NativeRdb::E_OK) {
221 idToUpdateIndex.push_back(to_string(GetInt32Val("file_id", resultSetUpdateIndex)));
222 }
223
224 MEDIA_INFO_LOG("HandleIndex idToUpdateIndex size: %{public}zu", idToUpdateIndex.size());
225 if (!idToUpdateIndex.empty()) {
226 MediaAnalysisHelper::AsyncStartMediaAnalysisService(
227 static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_UPDATE_INDEX), idToUpdateIndex);
228 }
229 isPending_ = false;
230 }
231 } // namespace Media
232 } // namespace OHOS
233