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

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: " Created 8 years, 11 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 17 matching lines...) Expand all
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
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(), &current_vec); 764 manager_->SearchDownloads(string16(), &current_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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698