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.
5 // GalleryWatchStateTracker implementation.
7 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.h"
10 #include "base/files/file_path.h"
11 #include "base/location.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.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_event_router.h"
19 #include "chrome/browser/media_galleries/media_file_system_registry.h"
20 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/browser/state_store.h"
26 #include "extensions/common/extension.h"
28 namespace extensions {
32 // State store key to track the registered gallery watchers for the extensions.
33 const char kRegisteredGalleryWatchers[] = "media_gallery_watchers";
35 // Converts the storage |list| value to WatchedGalleryIds.
36 MediaGalleryPrefIdSet WatchedGalleryIdsFromValue(
37 const base::ListValue* list) {
38 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
39 MediaGalleryPrefIdSet gallery_ids;
40 std::string gallery_id_str;
41 for (size_t i = 0; i < list->GetSize(); ++i) {
42 if (!list->GetString(i, &gallery_id_str) || gallery_id_str.empty())
44 MediaGalleryPrefId gallery_id;
45 if (base::StringToUint64(gallery_id_str, &gallery_id))
46 gallery_ids.insert(gallery_id);
51 // Converts WatchedGalleryIds to a storage list value.
52 scoped_ptr<base::ListValue> WatchedGalleryIdsToValue(
53 const MediaGalleryPrefIdSet gallery_ids) {
54 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
55 scoped_ptr<base::ListValue> list(new base::ListValue());
56 for (MediaGalleryPrefIdSet::const_iterator id_iter = gallery_ids.begin();
57 id_iter != gallery_ids.end(); ++id_iter)
58 list->AppendString(base::Uint64ToString(*id_iter));
62 // Looks up an extension by ID. Does not include disabled extensions.
63 const Extension* GetExtensionById(Profile* profile,
64 const std::string& extension_id) {
65 return ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
71 GalleryWatchStateTracker::GalleryWatchStateTracker(Profile* profile)
72 : profile_(profile), extension_registry_observer_(this) {
73 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
75 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
76 MediaGalleriesPreferences* preferences =
77 g_browser_process->media_file_system_registry()->GetPreferences(profile);
78 preferences->AddGalleryChangeObserver(this);
81 GalleryWatchStateTracker::~GalleryWatchStateTracker() {
82 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
83 MediaGalleriesPreferences* preferences =
84 g_browser_process->media_file_system_registry()->GetPreferences(profile_);
85 preferences->RemoveGalleryChangeObserver(this);
89 GalleryWatchStateTracker* GalleryWatchStateTracker::GetForProfile(
91 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
93 MediaGalleriesPrivateAPI* private_api =
94 MediaGalleriesPrivateAPI::Get(profile);
95 // In unit tests, we don't have a MediaGalleriesPrivateAPI.
97 return private_api->GetGalleryWatchStateTracker();
101 void GalleryWatchStateTracker::OnPermissionAdded(
102 MediaGalleriesPreferences* preferences,
103 const std::string& extension_id,
104 MediaGalleryPrefId gallery_id) {
105 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
106 // Granted gallery permission.
107 if (HasGalleryWatchInfo(extension_id, gallery_id, false))
108 SetupGalleryWatch(extension_id, gallery_id, preferences);
111 void GalleryWatchStateTracker::OnPermissionRemoved(
112 MediaGalleriesPreferences* preferences,
113 const std::string& extension_id,
114 MediaGalleryPrefId gallery_id) {
115 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
116 // Revoked gallery permission.
117 if (HasGalleryWatchInfo(extension_id, gallery_id, true))
118 RemoveGalleryWatch(extension_id, gallery_id, preferences);
121 void GalleryWatchStateTracker::OnGalleryRemoved(MediaGalleriesPreferences* pref,
122 MediaGalleryPrefId gallery_id) {
123 for (WatchedExtensionsMap::const_iterator it =
124 watched_extensions_map_.begin();
125 it != watched_extensions_map_.end();
127 if (it->second.find(gallery_id) != it->second.end())
128 RemoveGalleryWatch(it->first, gallery_id, pref);
132 MediaGalleryPrefIdSet
133 GalleryWatchStateTracker::GetAllWatchedGalleryIDsForExtension(
134 const std::string& extension_id) const {
135 MediaGalleryPrefIdSet gallery_ids;
136 WatchedExtensionsMap::const_iterator extension_id_iter =
137 watched_extensions_map_.find(extension_id);
138 if (extension_id_iter != watched_extensions_map_.end()) {
139 for (WatchedGalleriesMap::const_iterator gallery_id_iter =
140 extension_id_iter->second.begin();
141 gallery_id_iter != extension_id_iter->second.end();
143 gallery_ids.insert(gallery_id_iter->first);
149 void GalleryWatchStateTracker::RemoveAllGalleryWatchersForExtension(
150 const std::string& extension_id,
151 MediaGalleriesPreferences* preferences) {
152 WatchedExtensionsMap::iterator extension_id_iter =
153 watched_extensions_map_.find(extension_id);
154 if (extension_id_iter == watched_extensions_map_.end())
156 const WatchedGalleriesMap& galleries = extension_id_iter->second;
157 for (WatchedGalleriesMap::const_iterator gallery_id_iter = galleries.begin();
158 gallery_id_iter != galleries.end(); ++gallery_id_iter)
159 RemoveGalleryWatch(extension_id, gallery_id_iter->second, preferences);
160 watched_extensions_map_.erase(extension_id_iter);
161 WriteToStorage(extension_id);
164 void GalleryWatchStateTracker::OnGalleryWatchAdded(
165 const std::string& extension_id,
166 MediaGalleryPrefId gallery_id) {
167 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
168 bool update_storage =
169 AddWatchedGalleryIdInfoForExtension(extension_id, gallery_id);
171 WriteToStorage(extension_id);
174 void GalleryWatchStateTracker::OnGalleryWatchRemoved(
175 const std::string& extension_id,
176 MediaGalleryPrefId gallery_id) {
177 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
178 if (!ContainsKey(watched_extensions_map_, extension_id))
180 watched_extensions_map_[extension_id].erase(gallery_id);
181 if (watched_extensions_map_[extension_id].empty())
182 watched_extensions_map_.erase(extension_id);
183 WriteToStorage(extension_id);
186 void GalleryWatchStateTracker::OnExtensionLoaded(
187 content::BrowserContext* browser_context,
188 const Extension* extension) {
189 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
190 StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
193 storage->GetExtensionValue(
195 kRegisteredGalleryWatchers,
196 base::Bind(&GalleryWatchStateTracker::ReadFromStorage,
201 void GalleryWatchStateTracker::OnExtensionUnloaded(
202 content::BrowserContext* browser_context,
203 const Extension* extension,
204 UnloadedExtensionInfo::Reason reason) {
205 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
206 if (!ContainsKey(watched_extensions_map_, extension->id()))
208 content::BrowserThread::PostTask(
209 content::BrowserThread::FILE, FROM_HERE,
210 base::Bind(&GalleryWatchManager::OnExtensionUnloaded,
213 for (WatchedGalleriesMap::iterator iter =
214 watched_extensions_map_[extension->id()].begin();
215 iter != watched_extensions_map_[extension->id()].end(); ++iter) {
216 iter->second = false;
220 void GalleryWatchStateTracker::WriteToStorage(const std::string& extension_id) {
221 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
222 StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
225 MediaGalleryPrefIdSet gallery_ids =
226 GetAllWatchedGalleryIDsForExtension(extension_id);
227 storage->SetExtensionValue(extension_id,
228 kRegisteredGalleryWatchers,
229 WatchedGalleryIdsToValue(gallery_ids));
232 void GalleryWatchStateTracker::ReadFromStorage(
233 const std::string& extension_id,
234 scoped_ptr<base::Value> value) {
235 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
236 MediaGalleriesPreferences* preferences =
237 g_browser_process->media_file_system_registry()->GetPreferences(profile_);
238 base::ListValue* list = NULL;
239 if (!value.get() || !value->GetAsList(&list))
241 MediaGalleryPrefIdSet gallery_ids = WatchedGalleryIdsFromValue(list);
242 if (gallery_ids.empty())
245 for (MediaGalleryPrefIdSet::const_iterator id_iter = gallery_ids.begin();
246 id_iter != gallery_ids.end(); ++id_iter) {
247 watched_extensions_map_[extension_id][*id_iter] = false;
248 SetupGalleryWatch(extension_id, *id_iter, preferences);
252 void GalleryWatchStateTracker::SetupGalleryWatch(
253 const std::string& extension_id,
254 MediaGalleryPrefId gallery_id,
255 MediaGalleriesPreferences* preferences) {
256 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
257 const Extension* extension = GetExtensionById(profile_, extension_id);
259 base::FilePath gallery_file_path(preferences->LookUpGalleryPathForExtension(
260 gallery_id, extension, false));
261 if (gallery_file_path.empty())
263 MediaGalleriesPrivateEventRouter* router =
264 MediaGalleriesPrivateAPI::Get(profile_)->GetEventRouter();
266 content::BrowserThread::PostTaskAndReplyWithResult(
267 content::BrowserThread::FILE,
269 base::Bind(&GalleryWatchManager::SetupGalleryWatch,
274 router->AsWeakPtr()),
275 base::Bind(&GalleryWatchStateTracker::HandleSetupGalleryWatchResponse,
281 void GalleryWatchStateTracker::RemoveGalleryWatch(
282 const std::string& extension_id,
283 MediaGalleryPrefId gallery_id,
284 MediaGalleriesPreferences* preferences) {
285 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
286 const Extension* extension = GetExtensionById(profile_, extension_id);
288 base::FilePath gallery_file_path(preferences->LookUpGalleryPathForExtension(
289 gallery_id, extension, true));
290 if (gallery_file_path.empty())
292 content::BrowserThread::PostTask(
293 content::BrowserThread::FILE, FROM_HERE,
294 base::Bind(&GalleryWatchManager::RemoveGalleryWatch,
298 watched_extensions_map_[extension_id][gallery_id] = false;
301 bool GalleryWatchStateTracker::HasGalleryWatchInfo(
302 const std::string& extension_id,
303 MediaGalleryPrefId gallery_id,
304 bool has_active_watcher) {
305 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
306 return (ContainsKey(watched_extensions_map_, extension_id) &&
307 ContainsKey(watched_extensions_map_[extension_id], gallery_id) &&
308 watched_extensions_map_[extension_id][gallery_id] ==
312 void GalleryWatchStateTracker::HandleSetupGalleryWatchResponse(
313 const std::string& extension_id,
314 MediaGalleryPrefId gallery_id,
316 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
318 return; // Failed to setup the gallery watch for the given extension.
319 AddWatchedGalleryIdInfoForExtension(extension_id, gallery_id);
322 bool GalleryWatchStateTracker::AddWatchedGalleryIdInfoForExtension(
323 const std::string& extension_id,
324 MediaGalleryPrefId gallery_id) {
325 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
326 if (HasGalleryWatchInfo(extension_id, gallery_id, true))
328 watched_extensions_map_[extension_id][gallery_id] = true;
332 } // namespace extensions