Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / media_galleries_private / gallery_watch_state_tracker.cc
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 // GalleryWatchStateTracker implementation.
6
7 #include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_state_tracker.h"
8
9 #include "base/bind.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"
27
28 namespace extensions {
29
30 namespace {
31
32 // State store key to track the registered gallery watchers for the extensions.
33 const char kRegisteredGalleryWatchers[] = "media_gallery_watchers";
34
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())
43       continue;
44     MediaGalleryPrefId gallery_id;
45     if (base::StringToUint64(gallery_id_str, &gallery_id))
46       gallery_ids.insert(gallery_id);
47   }
48   return gallery_ids;
49 }
50
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));
59   return list.Pass();
60 }
61
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(
66       extension_id);
67 }
68
69 }  // namespace
70
71 GalleryWatchStateTracker::GalleryWatchStateTracker(Profile* profile)
72     : profile_(profile), extension_registry_observer_(this) {
73   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
74   DCHECK(profile_);
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);
79 }
80
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);
86 }
87
88 // static
89 GalleryWatchStateTracker* GalleryWatchStateTracker::GetForProfile(
90     Profile* profile) {
91   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
92   DCHECK(profile);
93   MediaGalleriesPrivateAPI* private_api =
94       MediaGalleriesPrivateAPI::Get(profile);
95   // In unit tests, we don't have a MediaGalleriesPrivateAPI.
96   if (private_api)
97     return private_api->GetGalleryWatchStateTracker();
98   return NULL;
99 }
100
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);
109 }
110
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);
119 }
120
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();
126        ++it) {
127     if (it->second.find(gallery_id) != it->second.end())
128       RemoveGalleryWatch(it->first, gallery_id, pref);
129   }
130 }
131
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();
142          ++gallery_id_iter) {
143       gallery_ids.insert(gallery_id_iter->first);
144     }
145   }
146   return gallery_ids;
147 }
148
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())
155     return;
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);
162 }
163
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);
170   if (update_storage)
171     WriteToStorage(extension_id);
172 }
173
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))
179     return;
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);
184 }
185
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();
191   if (!storage)
192     return;
193   storage->GetExtensionValue(
194       extension->id(),
195       kRegisteredGalleryWatchers,
196       base::Bind(&GalleryWatchStateTracker::ReadFromStorage,
197                  AsWeakPtr(),
198                  extension->id()));
199 }
200
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()))
207     return;
208   content::BrowserThread::PostTask(
209       content::BrowserThread::FILE, FROM_HERE,
210       base::Bind(&GalleryWatchManager::OnExtensionUnloaded,
211                  profile_,
212                  extension->id()));
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;
217   }
218 }
219
220 void GalleryWatchStateTracker::WriteToStorage(const std::string& extension_id) {
221   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
222   StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
223   if (!storage)
224     return;
225   MediaGalleryPrefIdSet gallery_ids =
226       GetAllWatchedGalleryIDsForExtension(extension_id);
227   storage->SetExtensionValue(extension_id,
228                              kRegisteredGalleryWatchers,
229                              WatchedGalleryIdsToValue(gallery_ids));
230 }
231
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))
240     return;
241   MediaGalleryPrefIdSet gallery_ids = WatchedGalleryIdsFromValue(list);
242   if (gallery_ids.empty())
243     return;
244
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);
249   }
250 }
251
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);
258   DCHECK(extension);
259   base::FilePath gallery_file_path(preferences->LookUpGalleryPathForExtension(
260       gallery_id, extension, false));
261   if (gallery_file_path.empty())
262     return;
263   MediaGalleriesPrivateEventRouter* router =
264       MediaGalleriesPrivateAPI::Get(profile_)->GetEventRouter();
265   DCHECK(router);
266   content::BrowserThread::PostTaskAndReplyWithResult(
267       content::BrowserThread::FILE,
268       FROM_HERE,
269       base::Bind(&GalleryWatchManager::SetupGalleryWatch,
270                  profile_,
271                  gallery_id,
272                  gallery_file_path,
273                  extension_id,
274                  router->AsWeakPtr()),
275       base::Bind(&GalleryWatchStateTracker::HandleSetupGalleryWatchResponse,
276                  AsWeakPtr(),
277                  extension_id,
278                  gallery_id));
279 }
280
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);
287   DCHECK(extension);
288   base::FilePath gallery_file_path(preferences->LookUpGalleryPathForExtension(
289       gallery_id, extension, true));
290   if (gallery_file_path.empty())
291     return;
292   content::BrowserThread::PostTask(
293       content::BrowserThread::FILE, FROM_HERE,
294       base::Bind(&GalleryWatchManager::RemoveGalleryWatch,
295                  profile_,
296                  gallery_file_path,
297                  extension_id));
298   watched_extensions_map_[extension_id][gallery_id] = false;
299 }
300
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] ==
309               has_active_watcher);
310 }
311
312 void GalleryWatchStateTracker::HandleSetupGalleryWatchResponse(
313     const std::string& extension_id,
314     MediaGalleryPrefId gallery_id,
315     bool success) {
316   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
317   if (!success)
318     return;  // Failed to setup the gallery watch for the given extension.
319   AddWatchedGalleryIdInfoForExtension(extension_id, gallery_id);
320 }
321
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))
327     return false;
328   watched_extensions_map_[extension_id][gallery_id] = true;
329   return true;
330 }
331
332 }  // namespace extensions