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; |
} |
} |
} |