| 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 842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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(), ¤t_vec); | 980 manager_->SearchDownloads(string16(), ¤t_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 } |
| OLD | NEW |