Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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(), ¤t_vec); | 962 manager_->SearchDownloads(string16(), ¤t_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 } |
| OLD | NEW |