1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/extension_message_bubble_controller.h" 6 7 #include "base/bind.h" 8 #include "base/metrics/histogram.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/browser/extensions/extension_message_bubble.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser_finder.h" 14 #include "chrome/common/url_constants.h" 15 #include "content/public/browser/user_metrics.h" 16 #include "extensions/browser/extension_registry.h" 17 18 namespace extensions { 19 20 //////////////////////////////////////////////////////////////////////////////// 21 // ExtensionMessageBubbleController::Delegate 22 23 ExtensionMessageBubbleController::Delegate::Delegate() { 24 } 25 26 ExtensionMessageBubbleController::Delegate::~Delegate() { 27 } 28 29 void ExtensionMessageBubbleController::Delegate::RestrictToSingleExtension( 30 const std::string& extension_id) { 31 NOTIMPLEMENTED(); // Derived classes that need this should implement. 32 } 33 34 //////////////////////////////////////////////////////////////////////////////// 35 // ExtensionMessageBubbleController 36 37 ExtensionMessageBubbleController::ExtensionMessageBubbleController( 38 Delegate* delegate, Profile* profile) 39 : profile_(profile), 40 user_action_(ACTION_BOUNDARY), 41 delegate_(delegate), 42 initialized_(false) { 43 } 44 45 ExtensionMessageBubbleController::~ExtensionMessageBubbleController() { 46 } 47 48 std::vector<base::string16> 49 ExtensionMessageBubbleController::GetExtensionList() { 50 ExtensionIdList* list = GetOrCreateExtensionList(); 51 if (list->empty()) 52 return std::vector<base::string16>(); 53 54 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); 55 std::vector<base::string16> return_value; 56 for (ExtensionIdList::const_iterator it = list->begin(); 57 it != list->end(); ++it) { 58 const Extension* extension = 59 registry->GetExtensionById(*it, ExtensionRegistry::EVERYTHING); 60 if (extension) { 61 return_value.push_back(base::UTF8ToUTF16(extension->name())); 62 } else { 63 return_value.push_back( 64 base::ASCIIToUTF16(std::string("(unknown name) ") + *it)); 65 // TODO(finnur): Add this as a string to the grd, for next milestone. 66 } 67 } 68 return return_value; 69 } 70 71 const ExtensionIdList& ExtensionMessageBubbleController::GetExtensionIdList() { 72 return *GetOrCreateExtensionList(); 73 } 74 75 bool ExtensionMessageBubbleController::CloseOnDeactivate() { return false; } 76 77 void ExtensionMessageBubbleController::Show(ExtensionMessageBubble* bubble) { 78 // Wire up all the callbacks, to get notified what actions the user took. 79 base::Closure dismiss_button_callback = 80 base::Bind(&ExtensionMessageBubbleController::OnBubbleDismiss, 81 base::Unretained(this)); 82 base::Closure action_button_callback = 83 base::Bind(&ExtensionMessageBubbleController::OnBubbleAction, 84 base::Unretained(this)); 85 base::Closure link_callback = 86 base::Bind(&ExtensionMessageBubbleController::OnLinkClicked, 87 base::Unretained(this)); 88 bubble->OnActionButtonClicked(action_button_callback); 89 bubble->OnDismissButtonClicked(dismiss_button_callback); 90 bubble->OnLinkClicked(link_callback); 91 92 bubble->Show(); 93 } 94 95 void ExtensionMessageBubbleController::OnBubbleAction() { 96 DCHECK_EQ(ACTION_BOUNDARY, user_action_); 97 user_action_ = ACTION_EXECUTE; 98 99 delegate_->LogAction(ACTION_EXECUTE); 100 delegate_->PerformAction(*GetOrCreateExtensionList()); 101 AcknowledgeExtensions(); 102 delegate_->OnClose(); 103 } 104 105 void ExtensionMessageBubbleController::OnBubbleDismiss() { 106 // OnBubbleDismiss() can be called twice when we receive multiple 107 // "OnWidgetDestroying" notifications (this can at least happen when we close 108 // a window with a notification open). Handle this gracefully. 109 if (user_action_ != ACTION_BOUNDARY) { 110 DCHECK(user_action_ == ACTION_DISMISS); 111 return; 112 } 113 114 user_action_ = ACTION_DISMISS; 115 116 delegate_->LogAction(ACTION_DISMISS); 117 AcknowledgeExtensions(); 118 delegate_->OnClose(); 119 } 120 121 void ExtensionMessageBubbleController::OnLinkClicked() { 122 DCHECK_EQ(ACTION_BOUNDARY, user_action_); 123 user_action_ = ACTION_LEARN_MORE; 124 125 delegate_->LogAction(ACTION_LEARN_MORE); 126 Browser* browser = 127 chrome::FindBrowserWithProfile(profile_, chrome::GetActiveDesktop()); 128 if (browser) { 129 browser->OpenURL( 130 content::OpenURLParams(delegate_->GetLearnMoreUrl(), 131 content::Referrer(), 132 NEW_FOREGROUND_TAB, 133 ui::PAGE_TRANSITION_LINK, 134 false)); 135 } 136 AcknowledgeExtensions(); 137 delegate_->OnClose(); 138 } 139 140 void ExtensionMessageBubbleController::AcknowledgeExtensions() { 141 ExtensionIdList* list = GetOrCreateExtensionList(); 142 for (ExtensionIdList::const_iterator it = list->begin(); 143 it != list->end(); ++it) 144 delegate_->AcknowledgeExtension(*it, user_action_); 145 } 146 147 ExtensionIdList* ExtensionMessageBubbleController::GetOrCreateExtensionList() { 148 if (!initialized_) { 149 scoped_ptr<const ExtensionSet> extension_set( 150 ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet()); 151 for (ExtensionSet::const_iterator it = extension_set->begin(); 152 it != extension_set->end(); ++it) { 153 std::string id = (*it)->id(); 154 if (!delegate_->ShouldIncludeExtension(id)) 155 continue; 156 extension_list_.push_back(id); 157 } 158 159 delegate_->LogExtensionCount(extension_list_.size()); 160 initialized_ = true; 161 } 162 163 return &extension_list_; 164 } 165 166 } // namespace extensions 167