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

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: kill console.logs 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 842 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 853 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
854 if (url.empty()) 854 if (url.empty())
855 error_ = download_extension_errors::kIconNotFoundError; 855 error_ = download_extension_errors::kIconNotFoundError;
856 else 856 else
857 result_.reset(base::Value::CreateStringValue(url)); 857 result_.reset(base::Value::CreateStringValue(url));
858 SendResponse(error_.empty()); 858 SendResponse(error_.empty());
859 } 859 }
860 860
861 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile) 861 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile)
862 : profile_(profile), 862 : profile_(profile),
863 manager_(NULL) { 863 manager_(NULL),
864 delete_item_jsons_(&item_jsons_),
865 delete_on_changed_stats_(&on_changed_stats_) {
864 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 866 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
865 DCHECK(profile_); 867 DCHECK(profile_);
866 // Register a callback with the DownloadService for this profile to be called 868 // Register a callback with the DownloadService for this profile to be called
867 // when it creates the DownloadManager, or now if the manager already exists. 869 // when it creates the DownloadManager, or now if the manager already exists.
868 DownloadServiceFactory::GetForProfile(profile)->OnManagerCreated(base::Bind( 870 DownloadServiceFactory::GetForProfile(profile)->OnManagerCreated(base::Bind(
869 &ExtensionDownloadsEventRouter::Init, base::Unretained(this))); 871 &ExtensionDownloadsEventRouter::Init, base::Unretained(this)));
870 } 872 }
871 873
872 // The only public methods on this class are ModelChanged() and 874 // The only public methods on this class are ModelChanged() and
873 // ManagerGoingDown(), and they are only called by DownloadManager, so 875 // ManagerGoingDown(), and they are only called by DownloadManager, so
874 // there's no way for any methods on this class to be called before 876 // there's no way for any methods on this class to be called before
875 // DownloadService calls Init() via the OnManagerCreated Callback above. 877 // DownloadService calls Init() via the OnManagerCreated Callback above.
876 void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) { 878 void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) {
877 DCHECK(manager_ == NULL); 879 DCHECK(manager_ == NULL);
878 manager_ = manager; 880 manager_ = manager;
881 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
879 manager_->AddObserver(this); 882 manager_->AddObserver(this);
880 } 883 }
881 884
882 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { 885 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
883 if (manager_ != NULL) 886 if (manager_ != NULL)
884 manager_->RemoveObserver(this); 887 manager_->RemoveObserver(this);
888 for (ItemMap::const_iterator iter = downloads_.begin();
889 iter != downloads_.end(); ++iter) {
890 if (iter->second != NULL)
891 iter->second->RemoveObserver(this);
892 }
893 }
894
895 ExtensionDownloadsEventRouter::OnChangedStat::OnChangedStat()
896 : fires(0),
897 total(0) {
898 }
899
900 ExtensionDownloadsEventRouter::OnChangedStat::~OnChangedStat() {
901 if (total > 0)
902 UMA_HISTOGRAM_PERCENTAGE("Download.OnChanged", (fires * 100 / total));
903 }
904
905 void ExtensionDownloadsEventRouter::OnDownloadUpdated(DownloadItem* item) {
906 int download_id = item->GetId();
907 if (item->GetState() == DownloadItem::REMOVING) {
908 // The REMOVING state indicates that this item is being erased.
909 // Let's unregister as an observer so that we don't see any more updates
910 // from it, dispatch the onErased event, and remove its json and is
911 // OnChangedStat from our maps.
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 std::set<std::string> new_fields;
928 bool changed = false;
929
930 // For each field in the new json representation of the item except the
931 // bytesReceived field, if the field has changed from the previous old json,
932 // set the differences in the |delta| object and remember that something
933 // significant changed.
934 for (base::DictionaryValue::Iterator iter(*new_json.get());
935 iter.HasNext(); iter.Advance()) {
936 new_fields.insert(iter.key());
937 if (iter.key() != kBytesReceivedKey) {
938 base::Value* old_value = NULL;
939 if (!old_json->HasKey(iter.key()) ||
940 (old_json->Get(iter.key(), &old_value) &&
941 !iter.value().Equals(old_value))) {
942 delta->Set(iter.key() + ".new", iter.value().DeepCopy());
943 if (old_value)
944 delta->Set(iter.key() + ".old", old_value->DeepCopy());
945 changed = true;
946 }
947 }
948 }
949
950 // If a field was in the previous json but is not in the new json, set the
951 // difference in |delta|.
952 for (base::DictionaryValue::Iterator iter(*old_json);
953 iter.HasNext(); iter.Advance()) {
954 if (new_fields.find(iter.key()) == new_fields.end()) {
955 delta->Set(iter.key() + ".old", iter.value().DeepCopy());
956 changed = true;
957 }
958 }
959
960 // Update the OnChangedStat and dispatch the event if something significant
961 // changed. Replace the stored json with the new json.
962 ++(on_changed_stats_[download_id]->total);
963 if (changed) {
964 DispatchEvent(extension_event_names::kOnDownloadChanged, delta.release());
965 ++(on_changed_stats_[download_id]->fires);
966 }
967 item_jsons_[download_id]->Swap(new_json.get());
968 }
969
970 void ExtensionDownloadsEventRouter::OnDownloadOpened(DownloadItem* item) {
885 } 971 }
886 972
887 void ExtensionDownloadsEventRouter::ModelChanged(DownloadManager* manager) { 973 void ExtensionDownloadsEventRouter::ModelChanged(DownloadManager* manager) {
888 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 974 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
889 DCHECK(manager_ == manager); 975 DCHECK(manager_ == manager);
976 typedef std::set<int> DownloadIdSet;
977
978 // Get all the download items.
890 DownloadManager::DownloadVector current_vec; 979 DownloadManager::DownloadVector current_vec;
891 manager_->SearchDownloads(string16(), &current_vec); 980 manager_->SearchDownloads(string16(), &current_vec);
892 DownloadIdSet current_set; 981
982 // Populate set<>s of download item identifiers so that we can find
983 // differences between the old and the new set of download items.
984 DownloadIdSet current_set, prev_set;
985 for (ItemMap::const_iterator iter = downloads_.begin();
986 iter != downloads_.end(); ++iter) {
987 prev_set.insert(iter->first);
988 }
893 ItemMap current_map; 989 ItemMap current_map;
894 for (DownloadManager::DownloadVector::const_iterator iter = 990 for (DownloadManager::DownloadVector::const_iterator iter =
895 current_vec.begin(); 991 current_vec.begin();
896 iter != current_vec.end(); ++iter) { 992 iter != current_vec.end(); ++iter) {
897 DownloadItem* item = *iter; 993 DownloadItem* item = *iter;
898 int item_id = item->GetId(); 994 int item_id = item->GetId();
899 // TODO(benjhayden): Remove the following line when every item's id >= 0, 995 CHECK(item_id >= 0);
900 // which will allow firing onErased events for items from the history.
901 if (item_id < 0) continue;
902 DCHECK(current_map.find(item_id) == current_map.end()); 996 DCHECK(current_map.find(item_id) == current_map.end());
903 current_set.insert(item_id); 997 current_set.insert(item_id);
904 current_map[item_id] = item; 998 current_map[item_id] = item;
905 } 999 }
906 DownloadIdSet new_set; // current_set - downloads_; 1000 DownloadIdSet new_set; // current_set - prev_set;
907 DownloadIdSet erased_set; // downloads_ - current_set;
908 std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin());
909 std::insert_iterator<DownloadIdSet> erased_insertor(
910 erased_set, erased_set.begin());
911 std::set_difference(current_set.begin(), current_set.end(), 1001 std::set_difference(current_set.begin(), current_set.end(),
912 downloads_.begin(), downloads_.end(), 1002 prev_set.begin(), prev_set.end(),
913 new_insertor); 1003 std::insert_iterator<DownloadIdSet>(
914 std::set_difference(downloads_.begin(), downloads_.end(), 1004 new_set, new_set.begin()));
915 current_set.begin(), current_set.end(), 1005
916 erased_insertor); 1006 // For each download that was not in the old set of downloads but is in the
1007 // new set of downloads, fire an onCreated event, register as an Observer of
1008 // the item, store a json representation of the item so that we can easily
1009 // find changes in that json representation, and make an OnChangedStat.
917 for (DownloadIdSet::const_iterator iter = new_set.begin(); 1010 for (DownloadIdSet::const_iterator iter = new_set.begin();
918 iter != new_set.end(); ++iter) { 1011 iter != new_set.end(); ++iter) {
919 scoped_ptr<base::DictionaryValue> item( 1012 scoped_ptr<base::DictionaryValue> item(
920 DownloadItemToJSON(current_map[*iter])); 1013 DownloadItemToJSON(current_map[*iter]));
921 DispatchEvent(extension_event_names::kOnDownloadCreated, item.release()); 1014 DispatchEvent(extension_event_names::kOnDownloadCreated, item->DeepCopy());
1015 DCHECK(item_jsons_.find(*iter) == item_jsons_.end());
1016 on_changed_stats_[*iter] = new OnChangedStat();
1017 current_map[*iter]->AddObserver(this);
1018 item_jsons_[*iter] = item.release();
922 } 1019 }
923 for (DownloadIdSet::const_iterator iter = erased_set.begin(); 1020 downloads_.swap(current_map);
924 iter != erased_set.end(); ++iter) { 1021
925 DispatchEvent(extension_event_names::kOnDownloadErased, 1022 // Dispatching onErased is handled in OnDownloadUpdated when an item
926 base::Value::CreateIntegerValue(*iter)); 1023 // transitions to the REMOVING state.
927 }
928 downloads_.swap(current_set);
929 } 1024 }
930 1025
931 void ExtensionDownloadsEventRouter::ManagerGoingDown( 1026 void ExtensionDownloadsEventRouter::ManagerGoingDown(
932 DownloadManager* manager) { 1027 DownloadManager* manager) {
933 manager_->RemoveObserver(this); 1028 manager_->RemoveObserver(this);
934 manager_ = NULL; 1029 manager_ = NULL;
935 } 1030 }
936 1031
937 void ExtensionDownloadsEventRouter::DispatchEvent( 1032 void ExtensionDownloadsEventRouter::DispatchEvent(
938 const char* event_name, base::Value* arg) { 1033 const char* event_name, base::Value* arg) {
939 ListValue args; 1034 ListValue args;
940 args.Append(arg); 1035 args.Append(arg);
941 std::string json_args; 1036 std::string json_args;
942 base::JSONWriter::Write(&args, false, &json_args); 1037 base::JSONWriter::Write(&args, false, &json_args);
943 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( 1038 profile_->GetExtensionEventRouter()->DispatchEventToRenderers(
944 event_name, 1039 event_name,
945 json_args, 1040 json_args,
946 profile_, 1041 profile_,
947 GURL()); 1042 GURL());
948 } 1043 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698