Chromium Code Reviews| Index: chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc |
| diff --git a/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc b/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc |
| index 4aac3243ec9eb58433335777f15351688d62ac75..1617af99ea1719c2eefdc552df978acd9c7d001c 100644 |
| --- a/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc |
| +++ b/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc |
| @@ -4,6 +4,8 @@ |
| #include "chrome/browser/extensions/api/system_info_storage/storage_info_provider.h" |
| +#include <cmath> |
| + |
| #include "base/stl_util.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "content/public/browser/browser_thread.h" |
| @@ -26,11 +28,14 @@ const char kStorageTypeRemovable[] = "removable"; |
| } // namespace systeminfo |
| // Default watching interval is 1000 ms. |
| -const unsigned int kDefaultPollingIntervalMs = 1000; |
| +const int kDefaultPollingIntervalMs = 1000; |
| + |
| +// Default threshold for free space change. |
| +const int kDefaultThresholdBytes = 4096; |
| StorageInfoProvider::StorageInfoProvider() |
| : watching_timer_(NULL), |
| - observers_(new ObserverListThreadSafe<Observer>()), |
| + observers_(new ObserverListThreadSafe<StorageInfoObserver>()), |
| watching_interval_(kDefaultPollingIntervalMs) { |
| registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, |
| content::NotificationService::AllSources()); |
| @@ -41,28 +46,31 @@ StorageInfoProvider::~StorageInfoProvider() { |
| registrar_.RemoveAll(); |
| } |
| -void StorageInfoProvider::AddObserver(Observer* obs) { |
| +void StorageInfoProvider::AddObserver(StorageInfoObserver* obs) { |
| observers_->AddObserver(obs); |
| } |
| -void StorageInfoProvider::RemoveObserver(Observer* obs) { |
| +void StorageInfoProvider::RemoveObserver(StorageInfoObserver* obs) { |
| observers_->RemoveObserver(obs); |
| } |
| -void StorageInfoProvider::StartWatching(const std::string& id) { |
| +void StorageInfoProvider::StartWatching(const std::string& id, int threshold) { |
| + if (threshold <= 0) |
| + threshold = kDefaultThresholdBytes; |
| + |
| BrowserThread::PostTask( |
| BrowserThread::FILE, |
| FROM_HERE, |
| base::Bind(&StorageInfoProvider::StartWatchingOnFileThread, |
| - base::Unretained(this), id)); |
| + base::Unretained(this), id, threshold)); |
| } |
| -void StorageInfoProvider::StopWatching(const std::string& id) { |
| +void StorageInfoProvider::StopWatching(const std::string& id, int threshold) { |
| BrowserThread::PostTask( |
| BrowserThread::FILE, |
| FROM_HERE, |
| base::Bind(&StorageInfoProvider::StopWatchingOnFileThread, |
| - base::Unretained(this), id)); |
| + base::Unretained(this), id, threshold)); |
| } |
| void StorageInfoProvider::Observe( |
| @@ -82,21 +90,28 @@ void StorageInfoProvider::Observe( |
| } |
| } |
| -void StorageInfoProvider::StartWatchingOnFileThread(const std::string& id) { |
| +void StorageInfoProvider::StartWatchingOnFileThread(const std::string& id, |
| + int threshold) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| - // If the storage |id| is already being watched. |
| - if (ContainsKey(storage_id_to_size_map_, id)) |
| - return; |
| + |
| + FreeSpaceWatcher watcher(id, threshold); |
|
benwells
2012/12/11 04:40:40
This can move to line 111.
|
| + for (FreeSpaceWatchers::iterator it = id_to_watcher_map_[id].begin(); |
| + it != id_to_watcher_map_[id].end(); ++it) { |
| + // Returns back if the same watcher is already existing. |
| + if (it->threshold == threshold) |
|
benwells
2012/12/11 04:40:40
What if two extensions start watching using the sa
Hongbo Min
2012/12/11 05:08:50
Good catch! It will lead to the second one can not
|
| + return; |
| + } |
| StorageUnitInfo info; |
| - if (!QueryUnitInfo(id, &info)) |
| + if (!QueryUnitInfo(id, &info)) { |
| + AbortWatching(id); |
| return; |
| + } |
| - storage_id_to_size_map_[id] = info.available_capacity; |
| + watcher.recent_free_space = info.available_capacity; |
| + id_to_watcher_map_[id].push_back(watcher); |
| - // If it is the first storage to be watched, we need to start the watching |
| - // timer. |
| - if (storage_id_to_size_map_.size() == 1) { |
| + if (!watching_timer_) { |
| watching_timer_ = new base::RepeatingTimer<StorageInfoProvider>(); |
| watching_timer_->Start(FROM_HERE, |
| base::TimeDelta::FromMilliseconds(watching_interval_), |
| @@ -104,39 +119,63 @@ void StorageInfoProvider::StartWatchingOnFileThread(const std::string& id) { |
| } |
| } |
| -void StorageInfoProvider::StopWatchingOnFileThread(const std::string& id) { |
| +void StorageInfoProvider::StopWatchingOnFileThread(const std::string& id, |
| + int threshold) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| - if (!ContainsKey(storage_id_to_size_map_, id)) |
| + if (!ContainsKey(id_to_watcher_map_, id)) |
| return; |
| - storage_id_to_size_map_.erase(id); |
| + for (FreeSpaceWatchers::iterator it = id_to_watcher_map_[id].begin(); |
| + it != id_to_watcher_map_[id].end(); ++it) { |
| + if (it->threshold == threshold) { |
| + id_to_watcher_map_[id].erase(it); |
| + break; |
| + } |
| + } |
| + |
| + if (id_to_watcher_map_[id].empty()) |
| + id_to_watcher_map_.erase(id); |
| // If there is no storage to be watched, we need to destroy the watching |
| // timer. |
| - if (storage_id_to_size_map_.size() == 0) |
| + if (id_to_watcher_map_.empty()) |
| DestroyWatchingTimer(); |
| } |
| void StorageInfoProvider::CheckWatchedStorages() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| - DCHECK(storage_id_to_size_map_.size() > 0); |
| + DCHECK(!id_to_watcher_map_.empty()); |
| - StorageIDToSizeMap::iterator it = storage_id_to_size_map_.begin(); |
| - for (; it != storage_id_to_size_map_.end(); ++it) { |
| + StorageIDToWatcherMap::iterator it = id_to_watcher_map_.begin(); |
| + for (; it != id_to_watcher_map_.end(); ++it) { |
| StorageUnitInfo info; |
| - if (!QueryUnitInfo(it->first, &info)) { |
| - storage_id_to_size_map_.erase(it); |
| - if (storage_id_to_size_map_.size() == 0) { |
| - DestroyWatchingTimer(); |
| - return; |
| - } |
| - } |
| - if (it->second != info.available_capacity) { |
| - observers_->Notify(&Observer::OnStorageFreeSpaceChanged, |
| - it->first, /* storage id */ |
| - it->second, /* old free space value */ |
| - info.available_capacity /* new value */); |
| - it->second = info.available_capacity; |
| + if (!QueryUnitInfo(it->first, &info)) |
| + AbortWatching(it->first); |
| + NotifyFreeSpaceChangedIfNeeded(it->first, info.available_capacity); |
| + } |
| +} |
| + |
| +void StorageInfoProvider::AbortWatching(const std::string& id) { |
| + if (!ContainsKey(id_to_watcher_map_, id)) |
| + return; |
| + id_to_watcher_map_.erase(id); |
| + if (id_to_watcher_map_.empty()) |
| + DestroyWatchingTimer(); |
| +} |
| + |
| +void StorageInfoProvider::NotifyFreeSpaceChangedIfNeeded( |
| + const std::string& id, double latest_free_space) { |
| + for (FreeSpaceWatchers::iterator it = id_to_watcher_map_[id].begin(); |
| + it != id_to_watcher_map_[id].end(); ++it) { |
| + int delta = static_cast<int>(latest_free_space - it->recent_free_space); |
| + if (it->recent_free_space != latest_free_space && |
| + it->threshold <= abs(delta)) { |
| + observers_->Notify(&StorageInfoObserver::OnStorageFreeSpaceChanged, |
| + it->id, /* storage id */ |
| + it->recent_free_space, /* old free space value */ |
| + latest_free_space /* new value */, |
| + it->threshold /* change threshold */); |
|
benwells
2012/12/11 04:40:40
Why do we pass the threshold back in the event?
Hongbo Min
2012/12/11 05:08:50
The SystemInfoEventRouter needs it to marshal the
|
| + it->recent_free_space = latest_free_space; |
| } |
| } |
| } |