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