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