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 "ptp_media_sync_observer.h"
17
18 #include <chrono>
19 #include <cctype>
20
21 #include "media_log.h"
22 #include "ptp_album_handles.h"
23 #include "photo_album_column.h"
24 #include "datashare_predicates.h"
25 #include "datashare_abs_result_set.h"
26 #include "result_set_utils.h"
27 #include "media_file_uri.h"
28
29 using namespace std;
30
31 namespace OHOS {
32 namespace Media {
33 constexpr int32_t RESERVE_ALBUM = 10;
34 constexpr int32_t PARENT_ID = 0;
35 constexpr int32_t DELETE_LIMIT_TIME = 5000;
36 constexpr int32_t ERR_NUM = -1;
37 const string BURST_COVER_LEVEL = "1";
38 const string BURST_NOT_COVER_LEVEL = "2";
39 const string IS_LOCAL = "2";
40 const std::string HIDDEN_ALBUM = ".hiddenAlbum";
41 const string POSITION = "2";
42 const string INVALID_FILE_ID = "-1";
startsWith(const std::string & str,const std::string & prefix)43 bool startsWith(const std::string& str, const std::string& prefix)
44 {
45 if (prefix.size() > str.size() || prefix.empty() || str.empty()) {
46 MEDIA_ERR_LOG("MtpMediaLibrary::StartsWith prefix size error");
47 return false;
48 }
49
50 for (size_t i = 0; i < prefix.size(); ++i) {
51 if (str[i] != prefix[i]) {
52 return false;
53 }
54 }
55 return true;
56 }
57
SendEventPackets(uint32_t objectHandle,uint16_t eventCode)58 void MediaSyncObserver::SendEventPackets(uint32_t objectHandle, uint16_t eventCode)
59 {
60 EventMtp event;
61 event.length = MTP_CONTAINER_HEADER_SIZE + sizeof(objectHandle);
62 vector<uint8_t> outBuffer;
63 MtpPacketTool::PutUInt32(outBuffer, event.length);
64 MtpPacketTool::PutUInt16(outBuffer, EVENT_CONTAINER_TYPE);
65 MtpPacketTool::PutUInt16(outBuffer, eventCode);
66 CHECK_AND_RETURN_LOG(context_ != nullptr, "Mtp Ptp context is nullptr");
67 MtpPacketTool::PutUInt32(outBuffer, context_->transactionID);
68 MtpPacketTool::PutUInt32(outBuffer, objectHandle);
69 MEDIA_DEBUG_LOG("MtpMediaLibrary album [%{public}d]", objectHandle);
70
71 event.data = outBuffer;
72 CHECK_AND_RETURN_LOG(context_->mtpDriver != nullptr, "Mtp Ptp mtpDriver is nullptr");
73 context_->mtpDriver->WriteEvent(event);
74 }
75
SendEventPacketAlbum(uint32_t objectHandle,uint16_t eventCode)76 void MediaSyncObserver::SendEventPacketAlbum(uint32_t objectHandle, uint16_t eventCode)
77 {
78 EventMtp event;
79 event.length = MTP_CONTAINER_HEADER_SIZE + sizeof(objectHandle);
80 vector<uint8_t> outBuffer;
81 MtpPacketTool::PutUInt32(outBuffer, event.length);
82 MtpPacketTool::PutUInt16(outBuffer, EVENT_CONTAINER_TYPE);
83 MtpPacketTool::PutUInt16(outBuffer, eventCode);
84 MtpPacketTool::PutUInt32(outBuffer, PARENT_ID);
85 MtpPacketTool::PutUInt32(outBuffer, objectHandle);
86
87 event.data = outBuffer;
88 MEDIA_DEBUG_LOG("MtpMediaLibrary album [%{public}d]", objectHandle);
89 CHECK_AND_RETURN_LOG(context_ != nullptr, "Mtp Ptp context is nullptr");
90 CHECK_AND_RETURN_LOG(context_->mtpDriver != nullptr, "Mtp Ptp mtpDriver is nullptr");
91 context_->mtpDriver->WriteEvent(event);
92 }
93
IsNumber(const string & str)94 static bool IsNumber(const string& str)
95 {
96 CHECK_AND_RETURN_RET_LOG(!str.empty(), false, "IsNumber input is empty");
97 for (char const& c : str) {
98 if (isdigit(c) == 0) {
99 return false;
100 }
101 }
102 return true;
103 }
104
GetHandlesFromPhotosInfoBurstKeys(vector<std::string> & handles)105 vector<int32_t> MediaSyncObserver::GetHandlesFromPhotosInfoBurstKeys(vector<std::string> &handles)
106 {
107 vector<int32_t> handlesResult;
108 CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, handlesResult,
109 "Mtp GetHandlesFromPhotosInfoBurstKeys fail to get datasharehelper");
110 CHECK_AND_RETURN_RET_LOG(!handles.empty(), handlesResult, "Mtp handles have no elements!");
111 Uri uri(PAH_QUERY_PHOTO);
112 vector<string> columns;
113 columns.push_back(PhotoColumn::PHOTO_BURST_KEY);
114 DataShare::DataSharePredicates predicates;
115 predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL, BURST_COVER_LEVEL);
116 predicates.IsNotNull(PhotoColumn::PHOTO_BURST_KEY);
117 predicates.In(PhotoColumn::MEDIA_ID, handles);
118 shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
119
120 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
121 handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys fail to get PHOTO_BURST_KEY");
122 CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
123 handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys have no PHOTO_BURST_KEY");
124 vector<string> burstKey;
125 do {
126 burstKey.push_back(GetStringVal(PhotoColumn::PHOTO_BURST_KEY, resultSet));
127 } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
128
129 CHECK_AND_RETURN_RET_LOG(!burstKey.empty(), handlesResult,
130 "Mtp GetHandlesFromPhotosInfoBurstKeys burstKey is empty");
131
132 columns.clear();
133 columns.push_back(PhotoColumn::MEDIA_ID);
134 DataShare::DataSharePredicates predicatesHandles;
135 predicatesHandles.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL, BURST_NOT_COVER_LEVEL);
136 predicatesHandles.IsNotNull(PhotoColumn::PHOTO_BURST_KEY);
137 predicatesHandles.In(PhotoColumn::PHOTO_BURST_KEY, burstKey);
138 resultSet = dataShareHelper_->Query(uri, predicatesHandles, columns);
139 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
140 handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys fail to get handles");
141 CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
142 handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys have no handles");
143 do {
144 string file_id = GetStringVal(PhotoColumn::MEDIA_ID, resultSet);
145 if (!IsNumber(file_id)) {
146 MEDIA_ERR_LOG("Mtp GetHandlesFromPhotosInfoBurstKeys id is incorrect ");
147 continue;
148 }
149 handlesResult.push_back(atoi(file_id.c_str()));
150 } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
151 return handlesResult;
152 }
153
GetAllDeleteHandles()154 vector<string> MediaSyncObserver::GetAllDeleteHandles()
155 {
156 vector<string> handlesResult;
157 CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, handlesResult,
158 "Mtp GetAllDeleteHandles fail to get datasharehelper");
159 Uri uri(PAH_QUERY_PHOTO);
160 vector<string> columns;
161 columns.push_back(MediaColumn::MEDIA_ID);
162 DataShare::DataSharePredicates predicates;
163 auto now = std::chrono::system_clock::now();
164 auto now_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
165 auto new_timestamp = now_milliseconds - DELETE_LIMIT_TIME;
166 predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(new_timestamp));
167 shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
168
169 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
170 handlesResult, "Mtp GetAllDeleteHandles fail to get PHOTO_ALL_DELETE_KEY");
171 CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
172 handlesResult, "Mtp GetAllDeleteHandles have no PHOTO_ALL_DELETE_KEY");
173 do {
174 string file_id = GetStringVal(PhotoColumn::MEDIA_ID, resultSet);
175 handlesResult.push_back(file_id);
176 } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
177 return handlesResult;
178 }
179
AddPhotoHandle(int32_t handle)180 void MediaSyncObserver::AddPhotoHandle(int32_t handle)
181 {
182 CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp AddPhotoHandle fail to get datasharehelper");
183 Uri uri(PAH_QUERY_PHOTO);
184 vector<string> columns;
185 DataShare::DataSharePredicates predicates;
186 shared_ptr<DataShare::DataShareResultSet> resultSet;
187 columns.push_back(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
188 columns.push_back(PhotoColumn::PHOTO_SUBTYPE);
189 predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(handle));
190 predicates.NotEqualTo(PhotoColumn::PHOTO_POSITION, POSITION);
191 CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp AddPhotoHandle dataShareHelper_ is nullptr");
192 resultSet = dataShareHelper_->Query(uri, predicates, columns);
193 CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp AddPhotoHandle fail to get handles");
194 CHECK_AND_RETURN_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
195 "Mtp AddPhotoHandle failed to get resultSet");
196 SendEventPackets(handle + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_ADDED_CODE);
197 int32_t ownerAlbumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
198 int32_t subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
199 if (subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
200 SendEventPackets(handle + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_ADDED_CODE);
201 SendEventPacketAlbum(ownerAlbumId, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
202 }
203 auto albumHandles = PtpAlbumHandles::GetInstance();
204 if (!albumHandles->FindHandle(ownerAlbumId)) {
205 albumHandles->AddHandle(ownerAlbumId);
206 SendEventPacketAlbum(ownerAlbumId, MTP_EVENT_OBJECT_ADDED_CODE);
207 SendEventPacketAlbum(ownerAlbumId, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
208 SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
209 }
210 }
211
GetAddEditPhotoHandles(int32_t handle)212 void MediaSyncObserver::GetAddEditPhotoHandles(int32_t handle)
213 {
214 vector<int32_t> handlesResult;
215 CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr,
216 "Mtp GetAddEditPhotoHandles fail to get datasharehelper");
217 Uri uri(PAH_QUERY_PHOTO);
218 vector<string> columns;
219 DataShare::DataSharePredicates predicates;
220 columns.push_back(PhotoColumn::PHOTO_SUBTYPE);
221 predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(handle));
222 shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
223 CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp GetAddEditPhotoHandles fail to get PHOTO_ALL_DELETE_KEY");
224 CHECK_AND_RETURN_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
225 "Mtp GetAddEditPhotoHandles have no PHOTO_ALL_DELETE_KEY");
226
227 do {
228 int32_t subType = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
229 if (subType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
230 SendEventPackets(handle + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
231 } else if (subType == static_cast<int32_t>(PhotoSubType::DEFAULT)) {
232 SendEventPackets(handle + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
233 }
234 } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
235 }
236
GetAddEditAlbumHandle(int32_t handle)237 int32_t MediaSyncObserver::GetAddEditAlbumHandle(int32_t handle)
238 {
239 Uri uri(PAH_QUERY_PHOTO);
240 vector<string> columns;
241 DataShare::DataSharePredicates predicates;
242 columns.push_back(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
243 predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(handle));
244 CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr,
245 ERR_NUM, "Mtp GetAddEditAlbumHandle dataShareHelper_ is nullptr");
246 shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
247 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
248 ERR_NUM, "Mtp GetAddEditAlbumHandle fail to get album id");
249 CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
250 ERR_NUM, "Mtp GetAddEditAlbumHandle have no row");
251 int32_t album_id = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
252 return album_id;
253 }
254
SendPhotoRemoveEvent(std::string & suffixString)255 void MediaSyncObserver::SendPhotoRemoveEvent(std::string &suffixString)
256 {
257 vector<string> allDeletedHandles;
258 vector<int32_t> handles;
259 if (suffixString.empty()) {
260 allDeletedHandles = GetAllDeleteHandles();
261 for (auto deleteHandle : allDeletedHandles) {
262 if (!IsNumber(deleteHandle)) {
263 MEDIA_ERR_LOG("Mtp SendPhotoRemoveEvent deleteHandle is incorrect ");
264 continue;
265 }
266 SendEventPackets(atoi(deleteHandle.c_str()) + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
267 SendEventPackets(atoi(deleteHandle.c_str()) + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
268 }
269 } else {
270 CHECK_AND_RETURN_LOG(IsNumber(suffixString), "Mtp SendPhotoRemoveEvent deleteHandle is incorrect ");
271 SendEventPackets(atoi(suffixString.c_str()) + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
272 SendEventPackets(atoi(suffixString.c_str()) + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
273 vector<std::string> allDeleted;
274 allDeletedHandles.push_back(suffixString);
275 }
276 handles = GetHandlesFromPhotosInfoBurstKeys(allDeletedHandles);
277 for (const auto handle : handles) {
278 SendEventPackets(handle + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
279 }
280 }
281
SendPhotoEvent(ChangeType changeType,string suffixString)282 void MediaSyncObserver::SendPhotoEvent(ChangeType changeType, string suffixString)
283 {
284 if (!suffixString.empty() && !std::isdigit(suffixString[0])) {
285 return;
286 }
287 if (!suffixString.empty() && atoi(suffixString.c_str()) <= 0) {
288 return;
289 }
290 switch (changeType) {
291 case static_cast<int32_t>(NotifyType::NOTIFY_ADD):
292 MEDIA_DEBUG_LOG("MtpMediaLibrary PHOTO ADD");
293 AddPhotoHandle(atoi(suffixString.c_str()));
294 break;
295 case static_cast<int32_t>(NotifyType::NOTIFY_UPDATE):
296 MEDIA_DEBUG_LOG("MtpMediaLibrary PHOTO UPDATE");
297 SendEventPackets(atoi(suffixString.c_str()) + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
298 GetAddEditPhotoHandles(atoi(suffixString.c_str()));
299 break;
300 case static_cast<int32_t>(NotifyType::NOTIFY_REMOVE):
301 MEDIA_DEBUG_LOG("MtpMediaLibrary PHOTO REMOVE");
302 SendPhotoRemoveEvent(suffixString);
303 break;
304 default:
305 break;
306 }
307 }
308
GetAlbumInfo()309 std::shared_ptr<DataShare::DataShareResultSet> MediaSyncObserver::GetAlbumInfo()
310 {
311 DataShare::DataSharePredicates predicates;
312 Uri uri(PAH_QUERY_PHOTO_ALBUM);
313 vector<string> columns;
314 columns.push_back(PhotoAlbumColumns::ALBUM_ID + " as " + MEDIA_DATA_DB_ID);
315 predicates.IsNotNull(MEDIA_DATA_DB_ALBUM_NAME);
316 predicates.NotEqualTo(MEDIA_DATA_DB_ALBUM_NAME, HIDDEN_ALBUM);
317 predicates.BeginWrap();
318 predicates.NotEqualTo(MEDIA_DATA_DB_IS_LOCAL, IS_LOCAL);
319 predicates.Or();
320 predicates.IsNull(MEDIA_DATA_DB_IS_LOCAL);
321 predicates.EndWrap();
322 return dataShareHelper_->Query(uri, predicates, columns);
323 }
324
SendEventToPTP(int32_t suff_int,ChangeType changeType)325 void MediaSyncObserver::SendEventToPTP(int32_t suff_int, ChangeType changeType)
326 {
327 auto albumHandles = PtpAlbumHandles::GetInstance();
328 CHECK_AND_RETURN_LOG(albumHandles != nullptr, "albumHandles is nullptr");
329 switch (changeType) {
330 case static_cast<int32_t>(NotifyType::NOTIFY_ADD):
331 MEDIA_DEBUG_LOG("MtpMediaLibrary ALBUM ADD");
332 albumHandles->AddHandle(suff_int);
333 SendEventPacketAlbum(suff_int, MTP_EVENT_OBJECT_ADDED_CODE);
334 SendEventPacketAlbum(suff_int, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
335 SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
336 break;
337 case static_cast<int32_t>(NotifyType::NOTIFY_UPDATE):
338 MEDIA_DEBUG_LOG("MtpMediaLibrary ALBUM UPDATE");
339 if (albumHandles->FindHandle(suff_int)) {
340 SendEventPacketAlbum(suff_int, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
341 SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
342 } else {
343 albumHandles->AddHandle(suff_int);
344 auto suff_removed_int = albumHandles->ChangeHandle(GetAlbumInfo());
345 if (suff_removed_int != E_ERR) {
346 albumHandles->RemoveHandle(suff_removed_int);
347 SendEventPacketAlbum(suff_removed_int, MTP_EVENT_OBJECT_REMOVED_CODE);
348 SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
349 }
350 SendEventPacketAlbum(suff_int, MTP_EVENT_OBJECT_ADDED_CODE);
351 SendEventPacketAlbum(suff_int, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
352 SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
353 }
354 break;
355 case static_cast<int32_t>(NotifyType::NOTIFY_REMOVE):
356 MEDIA_DEBUG_LOG("MtpMediaLibrary ALBUM REMOVE");
357 albumHandles->RemoveHandle(suff_int);
358 SendEventPacketAlbum(suff_int, MTP_EVENT_OBJECT_REMOVED_CODE);
359 SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
360 break;
361 default:
362 break;
363 }
364 }
365
OnChangeEx(const ChangeInfo & changeInfo)366 void MediaSyncObserver::OnChangeEx(const ChangeInfo &changeInfo)
367 {
368 std::string PhotoPrefix = PhotoColumn::PHOTO_URI_PREFIX;
369 std::string PhotoAlbumPrefix = PhotoAlbumColumns::ALBUM_URI_PREFIX;
370 MEDIA_DEBUG_LOG("MtpMediaLibrary changeType [%{public}d]", changeInfo.changeType_);
371 for (const auto& it : changeInfo.uris_) {
372 std::string uri = it.ToString();
373 MediaFileUri fileUri(uri);
374 MEDIA_DEBUG_LOG("MtpMediaLibrary uris [%{public}s]", uri.c_str());
375 if (startsWith(uri, PhotoPrefix)) {
376 std::string fileId = fileUri.GetFileId();
377 if (fileId.compare(INVALID_FILE_ID) == 0) {
378 fileId = "";
379 }
380 if (fileId.empty() && changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_REMOVE)) {
381 MEDIA_ERR_LOG("MtpMediaLibrary suffixString is empty");
382 continue;
383 }
384 MEDIA_DEBUG_LOG("MtpMediaLibrary suffixString [%{public}s]", fileId.c_str());
385 SendPhotoEvent(changeInfo.changeType_, fileId);
386 } else if (startsWith(uri, PhotoAlbumPrefix)) {
387 std::string albumId = fileUri.GetFileId();
388 MEDIA_DEBUG_LOG("MtpMediaLibrary suffixString [%{public}s]", albumId.c_str());
389 if (!IsNumber(albumId)) {
390 continue;
391 }
392 int32_t albumIdNum = atoi(albumId.c_str());
393 if (albumIdNum <= RESERVE_ALBUM) {
394 continue;
395 }
396 SendEventToPTP(albumIdNum, changeInfo.changeType_);
397 }
398 }
399 }
400
OnChange(const ChangeInfo & changeInfo)401 void MediaSyncObserver::OnChange(const ChangeInfo &changeInfo)
402 {
403 {
404 std::lock_guard<std::mutex> lock(mutex_);
405 changeInfoQueue_.push(changeInfo);
406 }
407 cv_.notify_one();
408 }
409
StartNotifyThread()410 void MediaSyncObserver::StartNotifyThread()
411 {
412 MEDIA_INFO_LOG("start notify thread");
413 isRunning_.store(true);
414 notifythread_ = std::thread([this] {this->ChangeNotifyThread();});
415 }
416
StopNotifyThread()417 void MediaSyncObserver::StopNotifyThread()
418 {
419 MEDIA_INFO_LOG("stop notify thread");
420 isRunning_.store(false);
421 cv_.notify_all();
422 if (notifythread_.joinable()) {
423 notifythread_.join();
424 }
425 }
426
ChangeNotifyThread()427 void MediaSyncObserver::ChangeNotifyThread()
428 {
429 while (isRunning_.load()) {
430 ChangeInfo changeInfo;
431 {
432 std::unique_lock<std::mutex> lock(mutex_);
433 cv_.wait(lock, [this] { return !changeInfoQueue_.empty() || !isRunning_.load(); });
434 if (!isRunning_.load()) {
435 MEDIA_INFO_LOG("notify thread is stopped");
436 break;
437 }
438 changeInfo = changeInfoQueue_.front();
439 changeInfoQueue_.pop();
440 }
441 OnChangeEx(changeInfo);
442 }
443 }
444 } // namespace Media
445 } // namespace OHOS