This source file includes following definitions.
- SendGalleryChangedEventOnUIThread
- AddExtension
- RemoveExtension
- OnExtensionUnloaded
- SetupWatch
- RemoveAllWatchReferences
- OnFilePathChanged
- RemoveExtensionReferences
- GetForProfile
- HasForProfile
- OnProfileShutdown
- SetupGalleryWatch
- RemoveGalleryWatch
- OnExtensionUnloaded
- StartGalleryWatch
- StopGalleryWatch
- HandleExtensionUnloadedEvent
- DeleteAllWatchers
- RemoveGalleryFilePathWatcherEntry
#include "chrome/browser/extensions/api/media_galleries_private/gallery_watch_manager.h"
#include <list>
#include <set>
#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_path_watcher.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/stl_util.h"
#include "base/time/time.h"
#include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.h"
#include "content/public/browser/browser_thread.h"
namespace extensions {
namespace {
using content::BrowserThread;
typedef std::map<void*, extensions::GalleryWatchManager*> WatchManagerMap;
WatchManagerMap* g_gallery_watch_managers = NULL;
void SendGalleryChangedEventOnUIThread(
base::WeakPtr<MediaGalleriesPrivateEventRouter> event_router,
MediaGalleryPrefId gallery_id,
const std::set<std::string>& extension_ids) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (event_router.get())
event_router->OnGalleryChanged(gallery_id, extension_ids);
}
}
class GalleryWatchManager::GalleryFilePathWatcher
: public base::RefCounted<GalleryFilePathWatcher> {
public:
GalleryFilePathWatcher(
base::WeakPtr<MediaGalleriesPrivateEventRouter> event_router,
MediaGalleryPrefId gallery_id,
const base::FilePath& path,
const std::string& extension_id,
const base::Closure& on_destroyed_callback);
void AddExtension(const std::string& extension_id);
void RemoveExtension(const std::string& extension_id);
void OnExtensionUnloaded(const std::string& extension_id);
bool SetupWatch();
void RemoveAllWatchReferences();
private:
friend class base::RefCounted<GalleryFilePathWatcher>;
typedef std::map<std::string, base::Time> ExtensionWatchInfoMap;
virtual ~GalleryFilePathWatcher();
void OnFilePathChanged(const base::FilePath& path, bool error);
void RemoveExtensionReferences(const std::string& extension_id);
base::WeakPtr<MediaGalleriesPrivateEventRouter> event_router_;
MediaGalleryPrefId gallery_id_;
base::FilePathWatcher file_watcher_;
base::FilePath gallery_path_;
base::Closure on_destroyed_callback_;
ExtensionWatchInfoMap extension_watch_info_map_;
base::WeakPtrFactory<GalleryFilePathWatcher> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GalleryFilePathWatcher);
};
GalleryWatchManager::GalleryFilePathWatcher::GalleryFilePathWatcher(
base::WeakPtr<MediaGalleriesPrivateEventRouter> event_router,
MediaGalleryPrefId gallery_id,
const base::FilePath& path,
const std::string& extension_id,
const base::Closure& on_destroyed_callback)
: event_router_(event_router),
gallery_id_(gallery_id),
on_destroyed_callback_(on_destroyed_callback),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
gallery_path_ = path;
AddExtension(extension_id);
}
void GalleryWatchManager::GalleryFilePathWatcher::AddExtension(
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (ContainsKey(extension_watch_info_map_, extension_id))
return;
extension_watch_info_map_[extension_id] = base::Time();
AddRef();
}
void GalleryWatchManager::GalleryFilePathWatcher::RemoveExtension(
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (extension_watch_info_map_.erase(extension_id) == 1)
Release();
}
void GalleryWatchManager::GalleryFilePathWatcher::OnExtensionUnloaded(
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
RemoveExtensionReferences(extension_id);
}
bool GalleryWatchManager::GalleryFilePathWatcher::SetupWatch() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
return file_watcher_.Watch(
gallery_path_, true,
base::Bind(&GalleryFilePathWatcher::OnFilePathChanged,
weak_ptr_factory_.GetWeakPtr()));
}
void GalleryWatchManager::GalleryFilePathWatcher::RemoveAllWatchReferences() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
std::set<std::string> extension_ids;
for (ExtensionWatchInfoMap::iterator iter = extension_watch_info_map_.begin();
iter != extension_watch_info_map_.end(); ++iter)
extension_ids.insert(iter->first);
for (std::set<std::string>::const_iterator it = extension_ids.begin();
it != extension_ids.end(); ++it)
RemoveExtensionReferences(*it);
}
GalleryWatchManager::GalleryFilePathWatcher::~GalleryFilePathWatcher() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
on_destroyed_callback_.Run();
}
void GalleryWatchManager::GalleryFilePathWatcher::OnFilePathChanged(
const base::FilePath& path,
bool error) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (error || (path != gallery_path_))
return;
std::set<std::string> extension_ids;
for (ExtensionWatchInfoMap::iterator iter = extension_watch_info_map_.begin();
iter != extension_watch_info_map_.end(); ++iter) {
if (!iter->second.is_null()) {
const int kMinSecondsToIgnoreGalleryChangedEvent = 3;
base::TimeDelta diff = base::Time::Now() - iter->second;
if (diff.InSeconds() < kMinSecondsToIgnoreGalleryChangedEvent)
continue;
}
iter->second = base::Time::Now();
extension_ids.insert(iter->first);
}
if (!extension_ids.empty()) {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(SendGalleryChangedEventOnUIThread, event_router_,
gallery_id_, extension_ids));
}
}
void GalleryWatchManager::GalleryFilePathWatcher::RemoveExtensionReferences(
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
ExtensionWatchInfoMap::iterator it =
extension_watch_info_map_.find(extension_id);
if (it == extension_watch_info_map_.end())
return;
extension_watch_info_map_.erase(it);
Release();
}
GalleryWatchManager* GalleryWatchManager::GetForProfile(
void* profile_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(profile_id);
bool has_watch_manager = (g_gallery_watch_managers &&
GalleryWatchManager::HasForProfile(profile_id));
if (!g_gallery_watch_managers)
g_gallery_watch_managers = new WatchManagerMap;
if (!has_watch_manager)
(*g_gallery_watch_managers)[profile_id] = new GalleryWatchManager;
return (*g_gallery_watch_managers)[profile_id];
}
bool GalleryWatchManager::HasForProfile(void* profile_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(profile_id);
if (!g_gallery_watch_managers)
return false;
WatchManagerMap::const_iterator it =
g_gallery_watch_managers->find(profile_id);
return (it != g_gallery_watch_managers->end());
}
void GalleryWatchManager::OnProfileShutdown(void* profile_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DCHECK(profile_id);
if (!g_gallery_watch_managers || g_gallery_watch_managers->empty())
return;
WatchManagerMap::iterator it = g_gallery_watch_managers->find(profile_id);
if (it == g_gallery_watch_managers->end())
return;
delete it->second;
g_gallery_watch_managers->erase(it);
if (g_gallery_watch_managers->empty())
delete g_gallery_watch_managers;
}
bool GalleryWatchManager::SetupGalleryWatch(
void* profile_id,
MediaGalleryPrefId gallery_id,
const base::FilePath& watch_path,
const std::string& extension_id,
base::WeakPtr<MediaGalleriesPrivateEventRouter> event_router) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
return GalleryWatchManager::GetForProfile(profile_id)->StartGalleryWatch(
gallery_id, watch_path, extension_id, event_router);
}
void GalleryWatchManager::RemoveGalleryWatch(void* profile_id,
const base::FilePath& watch_path,
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (!GalleryWatchManager::HasForProfile(profile_id))
return;
GalleryWatchManager::GetForProfile(profile_id)->StopGalleryWatch(
watch_path, extension_id);
}
void GalleryWatchManager::OnExtensionUnloaded(void* profile_id,
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (!GalleryWatchManager::HasForProfile(profile_id))
return;
GalleryWatchManager::GetForProfile(profile_id)->HandleExtensionUnloadedEvent(
extension_id);
}
GalleryWatchManager::GalleryWatchManager() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
}
GalleryWatchManager::~GalleryWatchManager() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
DeleteAllWatchers();
}
bool GalleryWatchManager::StartGalleryWatch(
MediaGalleryPrefId gallery_id,
const base::FilePath& watch_path,
const std::string& extension_id,
base::WeakPtr<MediaGalleriesPrivateEventRouter> event_router) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
WatcherMap::const_iterator iter = gallery_watchers_.find(watch_path);
if (iter != gallery_watchers_.end()) {
iter->second->AddExtension(extension_id);
return true;
}
scoped_refptr<GalleryFilePathWatcher> watch(
new GalleryFilePathWatcher(
event_router, gallery_id, watch_path, extension_id,
base::Bind(&GalleryWatchManager::RemoveGalleryFilePathWatcherEntry,
base::Unretained(this),
watch_path)));
if (!watch->SetupWatch())
return false;
gallery_watchers_[watch_path] = watch.get();
return true;
}
void GalleryWatchManager::StopGalleryWatch(
const base::FilePath& watch_path,
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
WatcherMap::iterator iter = gallery_watchers_.find(watch_path);
if (iter == gallery_watchers_.end())
return;
iter->second->RemoveExtension(extension_id);
}
void GalleryWatchManager::HandleExtensionUnloadedEvent(
const std::string& extension_id) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
std::list<base::FilePath> watchers_to_notify;
for (WatcherMap::iterator iter = gallery_watchers_.begin();
iter != gallery_watchers_.end(); ++iter)
watchers_to_notify.push_back(iter->first);
for (std::list<base::FilePath>::const_iterator path =
watchers_to_notify.begin();
path != watchers_to_notify.end(); ++path) {
WatcherMap::iterator iter = gallery_watchers_.find(*path);
if (iter == gallery_watchers_.end())
continue;
iter->second->OnExtensionUnloaded(extension_id);
}
}
void GalleryWatchManager::DeleteAllWatchers() {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
if (gallery_watchers_.empty())
return;
WatcherMap watchers_to_delete(gallery_watchers_);
for (WatcherMap::const_iterator iter = watchers_to_delete.begin();
iter != watchers_to_delete.end(); ++iter)
iter->second->RemoveAllWatchReferences();
}
void GalleryWatchManager::RemoveGalleryFilePathWatcherEntry(
const base::FilePath& watch_path) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
gallery_watchers_.erase(watch_path);
}
}