OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 // | |
5 // GalleryWatchManager implementation. | |
6 | |
7 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_ma nager.h" | |
8 | |
9 #include <list> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/compiler_specific.h" | |
13 #include "base/location.h" | |
14 #include "base/stl_util.h" | |
15 #include "base/time.h" | |
16 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_ma nager_factory.h" | |
17 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_ private_api.h" | |
18 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_ private_api_factory.h" | |
19 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_ private_event_router.h" | |
20 #include "chrome/browser/profiles/profile.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 | |
23 namespace extensions { | |
24 | |
25 namespace { | |
26 | |
27 using content::BrowserThread; | |
28 | |
29 // Dispatches the gallery changed event on the UI thread. | |
30 void SendGalleryChangedEventOnUIThread( | |
31 const Profile* profile, | |
32 const std::string& gallery_id, | |
33 const std::set<std::string>& extension_ids) { | |
34 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
35 DCHECK(profile); | |
36 MediaGalleriesPrivateEventRouter* router = | |
37 MediaGalleriesPrivateAPIFactory::GetForProfile( | |
38 const_cast<Profile*>(profile))->event_router(); | |
39 if (!router) | |
40 return; | |
41 router->OnGalleryChanged(gallery_id, extension_ids); | |
42 } | |
43 | |
44 } // namespace | |
45 | |
46 | |
47 /////////////////////////////////////////////////////////////////////////////// | |
48 // GalleryWatchManager // | |
49 /////////////////////////////////////////////////////////////////////////////// | |
50 | |
51 GalleryWatchManager::GalleryWatchManager(const Profile* profile) | |
52 : profile_(profile) { | |
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
54 } | |
55 | |
56 GalleryWatchManager::~GalleryWatchManager() { | |
57 DCHECK(thread_checker_.CalledOnValidThread()); | |
58 if (!gallery_watchers_.empty()) { | |
59 // Profile is in shutdown mode. | |
60 STLDeleteValues(&gallery_watchers_); | |
61 } | |
62 } | |
63 | |
64 bool GalleryWatchManager::StartGalleryWatch( | |
65 const std::string& gallery_id, | |
66 const FilePath& watch_path, | |
67 const std::string& extension_id) { | |
68 DCHECK(thread_checker_.CalledOnValidThread()); | |
69 WatcherMap::const_iterator iter = gallery_watchers_.find(watch_path); | |
Lei Zhang
2012/12/15 04:13:21
It's easier to understand if you write the code as
kmadhusu
2012/12/17 23:58:05
Done.
| |
70 if (iter == gallery_watchers_.end()) { | |
71 scoped_ptr<GalleryFilePathWatcher> watch( | |
72 new GalleryFilePathWatcher(profile_, gallery_id, watch_path, | |
73 extension_id)); | |
74 | |
75 if (watch->SetupWatch()) | |
76 gallery_watchers_[watch_path] = watch.release(); | |
77 else | |
78 return false; | |
79 } else { | |
80 iter->second->AddExtension(extension_id); | |
81 } | |
82 return true; | |
83 } | |
84 | |
85 void GalleryWatchManager::StopGalleryWatch( | |
86 const FilePath& watch_path, | |
87 const std::string& extension_id) { | |
88 DCHECK(thread_checker_.CalledOnValidThread()); | |
89 WatcherMap::iterator iter = gallery_watchers_.find(watch_path); | |
90 if (iter == gallery_watchers_.end()) | |
91 return; | |
92 // Remove the renderer process for this watch. | |
93 iter->second->RemoveExtension(extension_id); | |
94 if (iter->second->GetRefCount() == 0) { | |
95 delete iter->second; | |
96 gallery_watchers_.erase(iter); | |
97 } | |
98 } | |
99 | |
100 void GalleryWatchManager::OnExtensionDestroyed( | |
101 const std::string& extension_id) { | |
102 DCHECK(thread_checker_.CalledOnValidThread()); | |
103 std::list<FilePath> watchers_to_erase; | |
104 for (WatcherMap::iterator iter = gallery_watchers_.begin(); | |
105 iter != gallery_watchers_.end(); ++iter) { | |
106 // Remove the renderer process for this watch. | |
107 iter->second->OnExtensionDestroyed(extension_id); | |
108 if (iter->second->GetRefCount() == 0) | |
109 watchers_to_erase.push_back(iter->first); | |
110 } | |
111 | |
112 for (std::list<FilePath>::const_iterator path = watchers_to_erase.begin(); | |
113 path != watchers_to_erase.end(); ++path) { | |
114 WatcherMap::iterator iter = gallery_watchers_.find(*path); | |
115 DCHECK(iter != gallery_watchers_.end()); | |
116 delete iter->second; | |
117 gallery_watchers_.erase(iter); | |
118 } | |
119 } | |
120 | |
121 | |
122 /////////////////////////////////////////////////////////////////////////////// | |
123 // GalleryWatchManager::GalleryFilePathWatcher // | |
124 /////////////////////////////////////////////////////////////////////////////// | |
125 | |
126 GalleryWatchManager::GalleryFilePathWatcher::GalleryFilePathWatcher( | |
127 const Profile* profile, | |
128 const std::string& gallery_id, | |
129 const FilePath& path, | |
130 const std::string& extension_id) | |
131 : profile_(profile), | |
132 gallery_id_(gallery_id), | |
133 ref_count_(0), | |
134 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
136 file_watcher_.reset(new base::files::FilePathWatcher()); | |
137 gallery_path_ = path; | |
138 AddExtension(extension_id); | |
139 } | |
140 | |
141 GalleryWatchManager::GalleryFilePathWatcher::~GalleryFilePathWatcher() { | |
142 DCHECK(thread_check_.CalledOnValidThread()); | |
143 } | |
144 | |
145 void GalleryWatchManager::GalleryFilePathWatcher::AddExtension( | |
146 const std::string& extension_id) { | |
147 DCHECK(thread_check_.CalledOnValidThread()); | |
148 ExtensionUsageRegistry::iterator it = extensions_.find(extension_id); | |
149 if (it != extensions_.end()) | |
150 it->second++; | |
151 else | |
152 extensions_.insert(ExtensionUsageRegistry::value_type(extension_id, 1)); | |
153 ref_count_++; | |
154 } | |
155 | |
156 void GalleryWatchManager::GalleryFilePathWatcher::RemoveExtension( | |
157 const std::string& extension_id) { | |
158 DCHECK(thread_check_.CalledOnValidThread()); | |
159 ExtensionUsageRegistry::iterator it = extensions_.find(extension_id); | |
160 if (it == extensions_.end()) | |
161 return; | |
162 // If entry found - decrease it's count and remove if necessary | |
163 it->second--; | |
164 if (0 == it->second) | |
165 extensions_.erase(it); | |
166 ref_count_--; | |
167 } | |
168 | |
169 void GalleryWatchManager::GalleryFilePathWatcher::OnExtensionDestroyed( | |
170 const std::string& extension_id) { | |
171 DCHECK(thread_check_.CalledOnValidThread()); | |
172 ExtensionUsageRegistry::iterator it = extensions_.find(extension_id); | |
173 if (it == extensions_.end()) | |
174 return; | |
175 ref_count_ -= it->second; | |
176 extensions_.erase(it); | |
177 } | |
178 | |
179 unsigned int GalleryWatchManager::GalleryFilePathWatcher::GetRefCount() const { | |
180 DCHECK(thread_check_.CalledOnValidThread()); | |
181 return ref_count_; | |
182 } | |
183 | |
184 bool GalleryWatchManager::GalleryFilePathWatcher::SetupWatch() { | |
185 DCHECK(thread_check_.CalledOnValidThread()); | |
186 return file_watcher_->Watch( | |
187 gallery_path_, true, | |
188 base::Bind( | |
189 &GalleryWatchManager::GalleryFilePathWatcher::OnFilePathChanged, | |
190 weak_ptr_factory_.GetWeakPtr())); | |
191 } | |
192 | |
193 void GalleryWatchManager::GalleryFilePathWatcher::OnFilePathChanged( | |
194 const FilePath& path, | |
195 bool error) { | |
196 DCHECK(thread_check_.CalledOnValidThread()); | |
197 if (error || (path != gallery_path_)) | |
198 return; | |
199 | |
200 if (!last_gallery_changed_event_.is_null()) { | |
201 // Ignore gallery change event if it is received too frequently. | |
202 // For example, when an user copies/deletes 1000 media files from a gallery, | |
203 // this callback is called 1000 times within a span of 10ms. | |
204 // GalleryWatchManager should not send 1000 gallery changed events to | |
205 // the watching extension. | |
206 const int kMinSecondsToIgnoreGalleryChangedEvent = 3; | |
207 base::TimeDelta diff = base::Time::Now() - last_gallery_changed_event_; | |
208 if (diff.InSeconds() < kMinSecondsToIgnoreGalleryChangedEvent) | |
209 return; | |
210 } | |
211 | |
212 last_gallery_changed_event_ = base::Time::Now(); | |
213 ExtensionIdSet extension_ids; | |
214 for (ExtensionUsageRegistry::const_iterator iter = extensions_.begin(); | |
215 iter != extensions_.end(); ++iter) | |
216 extension_ids.insert(iter->first); | |
217 content::BrowserThread::PostTask( | |
218 content::BrowserThread::UI, FROM_HERE, | |
219 base::Bind(SendGalleryChangedEventOnUIThread, profile_, gallery_id_, | |
220 extension_ids)); | |
221 } | |
222 | |
223 } // namespace extensions | |
OLD | NEW |