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
Delegate()23 ExtensionMessageBubbleController::Delegate::Delegate() {
24 }
25
~Delegate()26 ExtensionMessageBubbleController::Delegate::~Delegate() {
27 }
28
RestrictToSingleExtension(const std::string & extension_id)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
ExtensionMessageBubbleController(Delegate * delegate,Profile * profile)37 ExtensionMessageBubbleController::ExtensionMessageBubbleController(
38 Delegate* delegate, Profile* profile)
39 : profile_(profile),
40 user_action_(ACTION_BOUNDARY),
41 delegate_(delegate),
42 initialized_(false) {
43 }
44
~ExtensionMessageBubbleController()45 ExtensionMessageBubbleController::~ExtensionMessageBubbleController() {
46 }
47
48 std::vector<base::string16>
GetExtensionList()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
GetExtensionIdList()71 const ExtensionIdList& ExtensionMessageBubbleController::GetExtensionIdList() {
72 return *GetOrCreateExtensionList();
73 }
74
CloseOnDeactivate()75 bool ExtensionMessageBubbleController::CloseOnDeactivate() { return false; }
76
Show(ExtensionMessageBubble * bubble)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
OnBubbleAction()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
OnBubbleDismiss()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
OnLinkClicked()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
AcknowledgeExtensions()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
GetOrCreateExtensionList()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