Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(427)

Side by Side Diff: chrome/browser/download/download_extension_api.cc

Issue 8203005: Implement chrome.experimental.downloads.onChanged (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: filename windows Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/download/download_extension_api.h" 5 #include "chrome/browser/download/download_extension_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cctype> 8 #include <cctype>
9 #include <iterator> 9 #include <iterator>
10 #include <set> 10 #include <set>
(...skipping 846 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
858 if (url.empty()) 858 if (url.empty())
859 error_ = download_extension_errors::kIconNotFoundError; 859 error_ = download_extension_errors::kIconNotFoundError;
860 else 860 else
861 result_.reset(base::Value::CreateStringValue(url)); 861 result_.reset(base::Value::CreateStringValue(url));
862 SendResponse(error_.empty()); 862 SendResponse(error_.empty());
863 } 863 }
864 864
865 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile) 865 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile)
866 : profile_(profile), 866 : profile_(profile),
867 manager_(NULL) { 867 manager_(NULL),
868 delete_item_jsons_(&item_jsons_),
869 delete_on_changed_stats_(&on_changed_stats_) {
868 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 870 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
869 DCHECK(profile_); 871 DCHECK(profile_);
870 // Register a callback with the DownloadService for this profile to be called 872 // Register a callback with the DownloadService for this profile to be called
871 // when it creates the DownloadManager, or now if the manager already exists. 873 // when it creates the DownloadManager, or now if the manager already exists.
872 DownloadServiceFactory::GetForProfile(profile)->OnManagerCreated(base::Bind( 874 DownloadServiceFactory::GetForProfile(profile)->OnManagerCreated(base::Bind(
873 &ExtensionDownloadsEventRouter::Init, base::Unretained(this))); 875 &ExtensionDownloadsEventRouter::Init, base::Unretained(this)));
874 } 876 }
875 877
876 // The only public methods on this class are ModelChanged() and 878 // The only public methods on this class are ModelChanged() and
877 // ManagerGoingDown(), and they are only called by DownloadManager, so 879 // ManagerGoingDown(), and they are only called by DownloadManager, so
878 // there's no way for any methods on this class to be called before 880 // there's no way for any methods on this class to be called before
879 // DownloadService calls Init() via the OnManagerCreated Callback above. 881 // DownloadService calls Init() via the OnManagerCreated Callback above.
880 void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) { 882 void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) {
881 DCHECK(manager_ == NULL); 883 DCHECK(manager_ == NULL);
882 manager_ = manager; 884 manager_ = manager;
885 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
883 manager_->AddObserver(this); 886 manager_->AddObserver(this);
884 } 887 }
885 888
886 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { 889 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
887 if (manager_ != NULL) 890 if (manager_ != NULL)
888 manager_->RemoveObserver(this); 891 manager_->RemoveObserver(this);
892 for (ItemMap::const_iterator iter = downloads_.begin();
893 iter != downloads_.end(); ++iter) {
894 if (iter->second != NULL)
895 iter->second->RemoveObserver(this);
896 }
897 }
898
899 ExtensionDownloadsEventRouter::OnChangedStat::OnChangedStat()
900 : fires(0),
901 total(0) {
902 }
903
904 ExtensionDownloadsEventRouter::OnChangedStat::~OnChangedStat() {
905 if (total > 0)
906 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", (fires * 100 / total));
907 }
908
909 void ExtensionDownloadsEventRouter::OnDownloadUpdated(DownloadItem* item) {
910 int download_id = item->GetId();
911 if (item->GetState() == DownloadItem::REMOVING) {
Randy Smith (Not in Mondays) 2012/02/02 18:10:07 The code would be enhanced by a few comments indic
benjhayden 2012/02/02 20:40:38 Done.
912 downloads_.erase(download_id);
913 item->RemoveObserver(this);
914 DispatchEvent(extension_event_names::kOnDownloadErased,
915 base::Value::CreateIntegerValue(download_id));
916 delete item_jsons_[download_id];
917 item_jsons_.erase(download_id);
918 delete on_changed_stats_[download_id];
919 on_changed_stats_.erase(download_id);
920 return;
921 }
922
923 base::DictionaryValue* old_json = item_jsons_[download_id];
924 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(item));
925 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue());
926 delta->SetInteger(kIdKey, download_id);
927 bool changed = false;
928
929 for (base::DictionaryValue::Iterator iter(*new_json.get());
930 iter.HasNext(); iter.Advance()) {
931 if (iter.key() != kBytesReceivedKey) {
Randy Smith (Not in Mondays) 2012/02/02 18:10:07 My inclination would be to have changes in BytesRe
benjhayden 2012/02/02 20:40:38 API purity. If I write an onChanged listener witho
932 base::Value* old_value = NULL;
933 if (!old_json->HasKey(iter.key()) ||
934 (old_json->Get(iter.key(), &old_value) &&
935 !iter.value().Equals(old_value))) {
Randy Smith (Not in Mondays) 2012/02/02 18:10:07 This looks like it'll leave out cases in which we'
benjhayden 2012/02/02 20:40:38 Good catch!
936 delta->Set(iter.key() + ".new", iter.value().DeepCopy());
937 if (old_value)
938 delta->Set(iter.key() + ".old", old_value->DeepCopy());
939 changed = true;
940 }
941 }
942 }
943
944 ++(on_changed_stats_[download_id]->total);
945 if (changed) {
946 DispatchEvent(extension_event_names::kOnDownloadChanged, delta.release());
947 ++(on_changed_stats_[download_id]->fires);
948 }
949 item_jsons_[download_id]->Swap(new_json.get());
950 }
951
952 void ExtensionDownloadsEventRouter::OnDownloadOpened(DownloadItem* item) {
889 } 953 }
890 954
891 void ExtensionDownloadsEventRouter::ModelChanged() { 955 void ExtensionDownloadsEventRouter::ModelChanged() {
Randy Smith (Not in Mondays) 2012/02/02 18:10:07 Again, I think just one or two comments would help
benjhayden 2012/02/02 20:40:38 Done.
956 typedef std::set<int> DownloadIdSet;
957
892 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 958 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
893 if (manager_ == NULL) 959 if (manager_ == NULL)
894 return; 960 return;
895 DownloadManager::DownloadVector current_vec; 961 DownloadManager::DownloadVector current_vec;
896 manager_->SearchDownloads(string16(), &current_vec); 962 manager_->SearchDownloads(string16(), &current_vec);
897 DownloadIdSet current_set; 963 DownloadIdSet current_set, prev_set;
964 for (ItemMap::const_iterator iter = downloads_.begin();
965 iter != downloads_.end(); ++iter) {
966 prev_set.insert(iter->first);
967 }
898 ItemMap current_map; 968 ItemMap current_map;
899 for (DownloadManager::DownloadVector::const_iterator iter = 969 for (DownloadManager::DownloadVector::const_iterator iter =
900 current_vec.begin(); 970 current_vec.begin();
901 iter != current_vec.end(); ++iter) { 971 iter != current_vec.end(); ++iter) {
902 DownloadItem* item = *iter; 972 DownloadItem* item = *iter;
903 int item_id = item->GetId(); 973 int item_id = item->GetId();
904 // TODO(benjhayden): Remove the following line when every item's id >= 0, 974 CHECK(item_id >= 0);
905 // which will allow firing onErased events for items from the history.
906 if (item_id < 0) continue;
907 DCHECK(current_map.find(item_id) == current_map.end()); 975 DCHECK(current_map.find(item_id) == current_map.end());
908 current_set.insert(item_id); 976 current_set.insert(item_id);
909 current_map[item_id] = item; 977 current_map[item_id] = item;
910 } 978 }
911 DownloadIdSet new_set; // current_set - downloads_; 979 DownloadIdSet new_set; // current_set - prev_set;
912 DownloadIdSet erased_set; // downloads_ - current_set;
913 std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin());
914 std::insert_iterator<DownloadIdSet> erased_insertor(
915 erased_set, erased_set.begin());
916 std::set_difference(current_set.begin(), current_set.end(), 980 std::set_difference(current_set.begin(), current_set.end(),
917 downloads_.begin(), downloads_.end(), 981 prev_set.begin(), prev_set.end(),
918 new_insertor); 982 std::insert_iterator<DownloadIdSet>(
919 std::set_difference(downloads_.begin(), downloads_.end(), 983 new_set, new_set.begin()));
920 current_set.begin(), current_set.end(),
921 erased_insertor);
922 for (DownloadIdSet::const_iterator iter = new_set.begin(); 984 for (DownloadIdSet::const_iterator iter = new_set.begin();
923 iter != new_set.end(); ++iter) { 985 iter != new_set.end(); ++iter) {
924 scoped_ptr<base::DictionaryValue> item( 986 scoped_ptr<base::DictionaryValue> item(
925 DownloadItemToJSON(current_map[*iter])); 987 DownloadItemToJSON(current_map[*iter]));
926 DispatchEvent(extension_event_names::kOnDownloadCreated, item.release()); 988 DispatchEvent(extension_event_names::kOnDownloadCreated, item->DeepCopy());
Randy Smith (Not in Mondays) 2012/02/02 18:10:07 I think it's worthwhile having a comment in this r
benjhayden 2012/02/02 20:40:38 Done.
989 DCHECK(item_jsons_.find(*iter) == item_jsons_.end());
990 on_changed_stats_[*iter] = new OnChangedStat();
991 current_map[*iter]->AddObserver(this);
992 item_jsons_[*iter] = item.release();
927 } 993 }
928 for (DownloadIdSet::const_iterator iter = erased_set.begin(); 994 downloads_.swap(current_map);
929 iter != erased_set.end(); ++iter) {
930 DispatchEvent(extension_event_names::kOnDownloadErased,
931 base::Value::CreateIntegerValue(*iter));
932 }
933 downloads_.swap(current_set);
934 } 995 }
935 996
936 void ExtensionDownloadsEventRouter::ManagerGoingDown() { 997 void ExtensionDownloadsEventRouter::ManagerGoingDown() {
937 manager_->RemoveObserver(this); 998 manager_->RemoveObserver(this);
938 manager_ = NULL; 999 manager_ = NULL;
939 } 1000 }
940 1001
941 void ExtensionDownloadsEventRouter::DispatchEvent( 1002 void ExtensionDownloadsEventRouter::DispatchEvent(
942 const char* event_name, base::Value* arg) { 1003 const char* event_name, base::Value* arg) {
943 ListValue args; 1004 ListValue args;
944 args.Append(arg); 1005 args.Append(arg);
945 std::string json_args; 1006 std::string json_args;
946 base::JSONWriter::Write(&args, false, &json_args); 1007 base::JSONWriter::Write(&args, false, &json_args);
947 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( 1008 profile_->GetExtensionEventRouter()->DispatchEventToRenderers(
948 event_name, 1009 event_name,
949 json_args, 1010 json_args,
950 profile_, 1011 profile_,
951 GURL()); 1012 GURL());
952 } 1013 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698