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 17 matching lines...) Expand all Loading... | |
28 #include "chrome/browser/download/download_util.h" | 28 #include "chrome/browser/download/download_util.h" |
29 #include "chrome/browser/extensions/extension_event_names.h" | 29 #include "chrome/browser/extensions/extension_event_names.h" |
30 #include "chrome/browser/extensions/extension_event_router.h" | 30 #include "chrome/browser/extensions/extension_event_router.h" |
31 #include "chrome/browser/icon_loader.h" | 31 #include "chrome/browser/icon_loader.h" |
32 #include "chrome/browser/icon_manager.h" | 32 #include "chrome/browser/icon_manager.h" |
33 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | 33 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
34 #include "chrome/browser/ui/browser_list.h" | 34 #include "chrome/browser/ui/browser_list.h" |
35 #include "chrome/browser/ui/webui/web_ui_util.h" | 35 #include "chrome/browser/ui/webui/web_ui_util.h" |
36 #include "content/browser/download/download_id.h" | 36 #include "content/browser/download/download_id.h" |
37 #include "content/browser/download/download_state_info.h" | 37 #include "content/browser/download/download_state_info.h" |
38 #include "content/browser/download/download_stats.h" | |
38 #include "content/browser/download/download_types.h" | 39 #include "content/browser/download/download_types.h" |
39 #include "content/browser/download/interrupt_reasons.h" | 40 #include "content/browser/download/interrupt_reasons.h" |
40 #include "content/browser/renderer_host/render_view_host.h" | 41 #include "content/browser/renderer_host/render_view_host.h" |
41 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 42 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
42 #include "content/public/browser/download_item.h" | 43 #include "content/public/browser/download_item.h" |
43 #include "content/public/browser/render_process_host.h" | 44 #include "content/public/browser/render_process_host.h" |
44 #include "net/http/http_util.h" | 45 #include "net/http/http_util.h" |
45 #include "net/url_request/url_request.h" | |
46 | 46 |
47 using content::BrowserThread; | 47 using content::BrowserThread; |
48 using content::DownloadItem; | 48 using content::DownloadItem; |
49 using content::DownloadManager; | 49 using content::DownloadManager; |
50 | 50 |
51 namespace download_extension_errors { | 51 namespace download_extension_errors { |
52 | 52 |
53 // Error messages | 53 // Error messages |
54 const char kGenericError[] = "I'm afraid I can't do that."; | 54 const char kGenericError[] = "I'm afraid I can't do that."; |
55 const char kIconNotFoundError[] = "Icon not found."; | 55 const char kIconNotFoundError[] = "Icon not found."; |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
658 (item->GetStartTime() - base::Time::UnixEpoch()).InMilliseconds()); | 658 (item->GetStartTime() - base::Time::UnixEpoch()).InMilliseconds()); |
659 json->SetInteger(kBytesReceivedKey, item->GetReceivedBytes()); | 659 json->SetInteger(kBytesReceivedKey, item->GetReceivedBytes()); |
660 json->SetInteger(kTotalBytesKey, item->GetTotalBytes()); | 660 json->SetInteger(kTotalBytesKey, item->GetTotalBytes()); |
661 if (item->GetState() == DownloadItem::INTERRUPTED) | 661 if (item->GetState() == DownloadItem::INTERRUPTED) |
662 json->SetInteger(kErrorKey, static_cast<int>(item->GetLastReason())); | 662 json->SetInteger(kErrorKey, static_cast<int>(item->GetLastReason())); |
663 // TODO(benjhayden): Implement endTime and fileSize. | 663 // TODO(benjhayden): Implement endTime and fileSize. |
664 // json->SetInteger(kEndTimeKey, -1); | 664 // json->SetInteger(kEndTimeKey, -1); |
665 json->SetInteger(kFileSizeKey, item->GetTotalBytes()); | 665 json->SetInteger(kFileSizeKey, item->GetTotalBytes()); |
666 return json; | 666 return json; |
667 } | 667 } |
668 | |
669 typedef std::set<int> DownloadIdSet; | |
670 | |
668 } // anonymous namespace | 671 } // anonymous namespace |
669 | 672 |
670 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile) | 673 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(Profile* profile) |
671 : profile_(profile), | 674 : profile_(profile), |
672 manager_(NULL) { | 675 manager_(NULL), |
676 delete_item_jsons_(&item_jsons_), | |
677 delete_on_changed_stats_(&on_changed_stats_) { | |
673 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
674 DCHECK(profile_); | 679 DCHECK(profile_); |
675 // Register a callback with the DownloadService for this profile to be called | 680 // Register a callback with the DownloadService for this profile to be called |
676 // when it creates the DownloadManager, or now if the manager already exists. | 681 // when it creates the DownloadManager, or now if the manager already exists. |
677 DownloadServiceFactory::GetForProfile(profile)->OnManagerCreated(base::Bind( | 682 DownloadServiceFactory::GetForProfile(profile)->OnManagerCreated(base::Bind( |
678 &ExtensionDownloadsEventRouter::Init, base::Unretained(this))); | 683 &ExtensionDownloadsEventRouter::Init, base::Unretained(this))); |
679 } | 684 } |
680 | 685 |
681 // The only public methods on this class are ModelChanged() and | 686 // The only public methods on this class are ModelChanged() and |
682 // ManagerGoingDown(), and they are only called by DownloadManager, so | 687 // ManagerGoingDown(), and they are only called by DownloadManager, so |
683 // there's no way for any methods on this class to be called before | 688 // there's no way for any methods on this class to be called before |
684 // DownloadService calls Init() via the OnManagerCreated Callback above. | 689 // DownloadService calls Init() via the OnManagerCreated Callback above. |
685 void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) { | 690 void ExtensionDownloadsEventRouter::Init(DownloadManager* manager) { |
686 DCHECK(manager_ == NULL); | 691 DCHECK(manager_ == NULL); |
687 manager_ = manager; | 692 manager_ = manager; |
693 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
688 manager_->AddObserver(this); | 694 manager_->AddObserver(this); |
689 } | 695 } |
690 | 696 |
691 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { | 697 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
692 if (manager_ != NULL) | 698 if (manager_ != NULL) |
693 manager_->RemoveObserver(this); | 699 manager_->RemoveObserver(this); |
700 for (ItemMap::const_iterator iter = downloads_.begin(); | |
701 iter != downloads_.end(); ++iter) { | |
702 if (iter->second != NULL) | |
703 iter->second->RemoveObserver(this); | |
704 } | |
705 } | |
706 | |
707 ExtensionDownloadsEventRouter::OnChangedStat::OnChangedStat() | |
708 : fires(0), total(0) { | |
709 } | |
710 | |
711 ExtensionDownloadsEventRouter::OnChangedStat::~OnChangedStat() { | |
712 download_stats::RecordOnChanged(fires * 100 / total); | |
713 } | |
714 | |
715 void ExtensionDownloadsEventRouter::OnDownloadUpdated(DownloadItem* item) { | |
716 int download_id = item->GetId(); | |
717 if (item->GetState() == DownloadItem::REMOVING) { | |
718 // Remove item from downloads_, but keep the id in downloads_ so that we | |
719 // notice its absence in ModelChanged() and fire an onErased. | |
Randy Smith (Not in Mondays)
2012/01/15 18:47:13
Idea (i.e. the notch below "suggestion"; just some
benjhayden
2012/02/01 21:42:40
Done.
| |
720 ItemMap::const_iterator it = downloads_.find(download_id); | |
721 DCHECK(it != downloads_.end()); | |
722 DCHECK(it->second == item); | |
723 downloads_[download_id] = NULL; | |
724 item->RemoveObserver(this); | |
725 return; | |
726 } | |
727 base::DictionaryValue* current_json = item_jsons_[download_id]; | |
728 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(item)); | |
729 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); | |
730 delta->SetInteger(kIdKey, download_id); | |
731 bool changed = false; | |
732 for (base::DictionaryValue::key_iterator key = new_json->begin_keys(); | |
733 key != new_json->end_keys(); ++key) { | |
734 if (*key != kBytesReceivedKey) { | |
735 base::Value* new_value = NULL; | |
736 base::Value* old_value = NULL; | |
737 if (new_json->Get(*key, &new_value) && | |
Randy Smith (Not in Mondays)
2012/01/15 18:47:13
So this isn't performance critical code, but (:-})
benjhayden
2012/02/01 21:42:40
Done.
| |
738 (!current_json->HasKey(*key) || | |
739 (current_json->Get(*key, &old_value) && | |
740 !new_value->Equals(old_value)))) { | |
741 delta->Set(*key + ".old", (old_value ? old_value->DeepCopy() | |
742 : base::Value::CreateNullValue())); | |
743 delta->Set(*key + ".new", new_value->DeepCopy()); | |
744 changed = true; | |
745 } | |
746 } | |
747 } | |
748 ++(on_changed_stats_[download_id]->total); | |
749 if (changed) { | |
750 DispatchEvent(extension_event_names::kOnDownloadChanged, delta.release()); | |
751 ++(on_changed_stats_[download_id]->fires); | |
752 } | |
753 current_json->Swap(new_json.get()); | |
754 } | |
755 | |
756 void ExtensionDownloadsEventRouter::OnDownloadOpened(DownloadItem* item) { | |
694 } | 757 } |
695 | 758 |
696 void ExtensionDownloadsEventRouter::ModelChanged() { | 759 void ExtensionDownloadsEventRouter::ModelChanged() { |
697 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 760 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
698 if (manager_ == NULL) | 761 if (manager_ == NULL) |
699 return; | 762 return; |
700 DownloadManager::DownloadVector current_vec; | 763 DownloadManager::DownloadVector current_vec; |
701 manager_->SearchDownloads(string16(), ¤t_vec); | 764 manager_->SearchDownloads(string16(), ¤t_vec); |
702 DownloadIdSet current_set; | 765 DownloadIdSet current_set, prev_set; |
766 for (ItemMap::const_iterator iter = downloads_.begin(); | |
767 iter != downloads_.end(); ++iter) { | |
768 prev_set.insert(iter->first); | |
769 } | |
703 ItemMap current_map; | 770 ItemMap current_map; |
704 for (DownloadManager::DownloadVector::const_iterator iter = | 771 for (DownloadManager::DownloadVector::const_iterator iter = |
705 current_vec.begin(); | 772 current_vec.begin(); |
706 iter != current_vec.end(); ++iter) { | 773 iter != current_vec.end(); ++iter) { |
707 DownloadItem* item = *iter; | 774 DownloadItem* item = *iter; |
708 int item_id = item->GetId(); | 775 int item_id = item->GetId(); |
709 // TODO(benjhayden): Remove the following line when every item's id >= 0, | 776 // TODO(benjhayden): Remove the following line when every item's id >= 0, |
710 // which will allow firing onErased events for items from the history. | 777 // which will allow firing onErased events for items from the history. |
711 if (item_id < 0) continue; | 778 if (item_id < 0) continue; |
712 DCHECK(current_map.find(item_id) == current_map.end()); | 779 DCHECK(current_map.find(item_id) == current_map.end()); |
713 current_set.insert(item_id); | 780 current_set.insert(item_id); |
714 current_map[item_id] = item; | 781 current_map[item_id] = item; |
715 } | 782 } |
716 DownloadIdSet new_set; // current_set - downloads_; | 783 DownloadIdSet new_set; // current_set - prev_set; |
Randy Smith (Not in Mondays)
2012/01/15 18:47:13
semi-nit: I think this section would be clearer if
benjhayden
2012/02/01 21:42:40
erased_set isn't necessary now that the onErased i
| |
717 DownloadIdSet erased_set; // downloads_ - current_set; | 784 DownloadIdSet erased_set; // prev_set - current_set; |
718 std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin()); | 785 std::insert_iterator<DownloadIdSet> new_insertor(new_set, new_set.begin()); |
719 std::insert_iterator<DownloadIdSet> erased_insertor( | 786 std::insert_iterator<DownloadIdSet> erased_insertor( |
720 erased_set, erased_set.begin()); | 787 erased_set, erased_set.begin()); |
721 std::set_difference(current_set.begin(), current_set.end(), | 788 std::set_difference(current_set.begin(), current_set.end(), |
722 downloads_.begin(), downloads_.end(), | 789 prev_set.begin(), prev_set.end(), |
723 new_insertor); | 790 new_insertor); |
724 std::set_difference(downloads_.begin(), downloads_.end(), | 791 std::set_difference(prev_set.begin(), prev_set.end(), |
725 current_set.begin(), current_set.end(), | 792 current_set.begin(), current_set.end(), |
726 erased_insertor); | 793 erased_insertor); |
727 for (DownloadIdSet::const_iterator iter = new_set.begin(); | 794 for (DownloadIdSet::const_iterator iter = new_set.begin(); |
728 iter != new_set.end(); ++iter) { | 795 iter != new_set.end(); ++iter) { |
729 DispatchEvent(extension_event_names::kOnDownloadCreated, | 796 DispatchEvent(extension_event_names::kOnDownloadCreated, |
730 DownloadItemToJSON(current_map[*iter])); | 797 DownloadItemToJSON(current_map[*iter])); |
798 DCHECK(item_jsons_.find(*iter) == item_jsons_.end()); | |
799 on_changed_stats_[*iter] = new OnChangedStat(); | |
800 item_jsons_[*iter] = DownloadItemToJSON(current_map[*iter]); | |
801 current_map[*iter]->AddObserver(this); | |
731 } | 802 } |
732 for (DownloadIdSet::const_iterator iter = erased_set.begin(); | 803 for (DownloadIdSet::const_iterator iter = erased_set.begin(); |
733 iter != erased_set.end(); ++iter) { | 804 iter != erased_set.end(); ++iter) { |
734 DispatchEvent(extension_event_names::kOnDownloadErased, | 805 DispatchEvent(extension_event_names::kOnDownloadErased, |
735 base::Value::CreateIntegerValue(*iter)); | 806 base::Value::CreateIntegerValue(*iter)); |
807 delete item_jsons_[*iter]; | |
808 item_jsons_.erase(*iter); | |
809 delete on_changed_stats_[*iter]; | |
810 on_changed_stats_.erase(*iter); | |
736 } | 811 } |
737 downloads_.swap(current_set); | 812 downloads_.swap(current_map); |
738 } | 813 } |
739 | 814 |
740 void ExtensionDownloadsEventRouter::ManagerGoingDown() { | 815 void ExtensionDownloadsEventRouter::ManagerGoingDown() { |
741 manager_->RemoveObserver(this); | 816 manager_->RemoveObserver(this); |
742 manager_ = NULL; | 817 manager_ = NULL; |
743 } | 818 } |
744 | 819 |
745 void ExtensionDownloadsEventRouter::DispatchEvent( | 820 void ExtensionDownloadsEventRouter::DispatchEvent( |
746 const char* event_name, base::Value* arg) { | 821 const char* event_name, base::Value* arg) { |
747 ListValue args; | 822 ListValue args; |
748 args.Append(arg); | 823 args.Append(arg); |
749 std::string json_args; | 824 std::string json_args; |
750 base::JSONWriter::Write(&args, false, &json_args); | 825 base::JSONWriter::Write(&args, false, &json_args); |
751 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( | 826 profile_->GetExtensionEventRouter()->DispatchEventToRenderers( |
752 event_name, | 827 event_name, |
753 json_args, | 828 json_args, |
754 profile_, | 829 profile_, |
755 GURL()); | 830 GURL()); |
756 } | 831 } |
OLD | NEW |