Home | History | Annotate | Download | only in media_galleries_private
      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(
    228       extension_id,
    229       kRegisteredGalleryWatchers,
    230       WatchedGalleryIdsToValue(gallery_ids).PassAs<base::Value>());
    231 }
    232 
    233 void GalleryWatchStateTracker::ReadFromStorage(
    234     const std::string& extension_id,
    235     scoped_ptr<base::Value> value) {
    236   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    237   MediaGalleriesPreferences* preferences =
    238       g_browser_process->media_file_system_registry()->GetPreferences(profile_);
    239   base::ListValue* list = NULL;
    240   if (!value.get() || !value->GetAsList(&list))
    241     return;
    242   MediaGalleryPrefIdSet gallery_ids = WatchedGalleryIdsFromValue(list);
    243   if (gallery_ids.empty())
    244     return;
    245 
    246   for (MediaGalleryPrefIdSet::const_iterator id_iter = gallery_ids.begin();
    247        id_iter != gallery_ids.end(); ++id_iter) {
    248     watched_extensions_map_[extension_id][*id_iter] = false;
    249     SetupGalleryWatch(extension_id, *id_iter, preferences);
    250   }
    251 }
    252 
    253 void GalleryWatchStateTracker::SetupGalleryWatch(
    254     const std::string& extension_id,
    255     MediaGalleryPrefId gallery_id,
    256     MediaGalleriesPreferences* preferences) {
    257   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    258   const Extension* extension = GetExtensionById(profile_, extension_id);
    259   DCHECK(extension);
    260   base::FilePath gallery_file_path(preferences->LookUpGalleryPathForExtension(
    261       gallery_id, extension, false));
    262   if (gallery_file_path.empty())
    263     return;
    264   MediaGalleriesPrivateEventRouter* router =
    265       MediaGalleriesPrivateAPI::Get(profile_)->GetEventRouter();
    266   DCHECK(router);
    267   content::BrowserThread::PostTaskAndReplyWithResult(
    268       content::BrowserThread::FILE,
    269       FROM_HERE,
    270       base::Bind(&GalleryWatchManager::SetupGalleryWatch,
    271                  profile_,
    272                  gallery_id,
    273                  gallery_file_path,
    274                  extension_id,
    275                  router->AsWeakPtr()),
    276       base::Bind(&GalleryWatchStateTracker::HandleSetupGalleryWatchResponse,
    277                  AsWeakPtr(),
    278                  extension_id,
    279                  gallery_id));
    280 }
    281 
    282 void GalleryWatchStateTracker::RemoveGalleryWatch(
    283     const std::string& extension_id,
    284     MediaGalleryPrefId gallery_id,
    285     MediaGalleriesPreferences* preferences) {
    286   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    287   const Extension* extension = GetExtensionById(profile_, extension_id);
    288   DCHECK(extension);
    289   base::FilePath gallery_file_path(preferences->LookUpGalleryPathForExtension(
    290       gallery_id, extension, true));
    291   if (gallery_file_path.empty())
    292     return;
    293   content::BrowserThread::PostTask(
    294       content::BrowserThread::FILE, FROM_HERE,
    295       base::Bind(&GalleryWatchManager::RemoveGalleryWatch,
    296                  profile_,
    297                  gallery_file_path,
    298                  extension_id));
    299   watched_extensions_map_[extension_id][gallery_id] = false;
    300 }
    301 
    302 bool GalleryWatchStateTracker::HasGalleryWatchInfo(
    303     const std::string& extension_id,
    304     MediaGalleryPrefId gallery_id,
    305     bool has_active_watcher) {
    306   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    307   return (ContainsKey(watched_extensions_map_, extension_id) &&
    308           ContainsKey(watched_extensions_map_[extension_id], gallery_id) &&
    309           watched_extensions_map_[extension_id][gallery_id] ==
    310               has_active_watcher);
    311 }
    312 
    313 void GalleryWatchStateTracker::HandleSetupGalleryWatchResponse(
    314     const std::string& extension_id,
    315     MediaGalleryPrefId gallery_id,
    316     bool success) {
    317   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    318   if (!success)
    319     return;  // Failed to setup the gallery watch for the given extension.
    320   AddWatchedGalleryIdInfoForExtension(extension_id, gallery_id);
    321 }
    322 
    323 bool GalleryWatchStateTracker::AddWatchedGalleryIdInfoForExtension(
    324     const std::string& extension_id,
    325     MediaGalleryPrefId gallery_id) {
    326   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    327   if (HasGalleryWatchInfo(extension_id, gallery_id, true))
    328     return false;
    329   watched_extensions_map_[extension_id][gallery_id] = true;
    330   return true;
    331 }
    332 
    333 }  // namespace extensions
    334