OLD | NEW |
(Empty) | |
| 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/extensions/extension_prefs.h" |
| 12 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/ui/browser.h" |
| 14 #include "chrome/browser/ui/browser_finder.h" |
| 15 #include "chrome/common/url_constants.h" |
| 16 #include "content/public/browser/user_metrics.h" |
| 17 #include "grit/chromium_strings.h" |
| 18 #include "grit/generated_resources.h" |
| 19 #include "ui/base/l10n/l10n_util.h" |
| 20 |
| 21 namespace { |
| 22 |
| 23 // All the different titles we know about. |
| 24 static const int kTitleIds[extensions::NUM_BUBBLE_TYPES] = { |
| 25 IDS_EXTENSIONS_SUSPICIOUS_DISABLED_TITLE, |
| 26 IDS_EXTENSIONS_DISABLE_DEVELOPER_MODE_TITLE, |
| 27 }; |
| 28 |
| 29 // All the different message bodies we know about. See also kBodyInjectIds. |
| 30 static const int kBodyIds[extensions::NUM_BUBBLE_TYPES] = { |
| 31 IDS_EXTENSIONS_SUSPICIOUS_DISABLED_BODY, |
| 32 IDS_EXTENSIONS_DISABLE_DEVELOPER_MODE_BODY, |
| 33 }; |
| 34 |
| 35 // Sometimes we substitute a param in one of the kBodyIds, this specifies the |
| 36 // value to use to replace the param. A 0 value means Accept no substitutes! |
| 37 static const int kBodyInjectIds[extensions::NUM_BUBBLE_TYPES] = { |
| 38 IDS_EXTENSION_WEB_STORE_TITLE, |
| 39 0, |
| 40 }; |
| 41 |
| 42 // All the labels we use for the Accept button. A 0 value means the bubble has |
| 43 // no Accept button. |
| 44 static const int kAcceptIds[extensions::NUM_BUBBLE_TYPES] = { |
| 45 0, |
| 46 IDS_DISABLE, |
| 47 }; |
| 48 |
| 49 // All the labels we use for the Dismiss button. |
| 50 static const int kDismissIds[extensions::NUM_BUBBLE_TYPES] = { |
| 51 IDS_EXTENSIONS_SUSPICIOUS_DISABLED_BUTTON, |
| 52 IDS_CANCEL, |
| 53 }; |
| 54 |
| 55 static const char* kLearnMoreLikeIds[extensions::NUM_BUBBLE_TYPES] = { |
| 56 chrome::kRemoveNonCWSExtensionURL, |
| 57 chrome::kChromeUIExtensionsURL, |
| 58 }; |
| 59 |
| 60 static const bool kShowExtensionList[extensions::NUM_BUBBLE_TYPES] = { |
| 61 true, |
| 62 false, |
| 63 }; |
| 64 |
| 65 } // namespace |
| 66 |
| 67 namespace extensions { |
| 68 |
| 69 //////////////////////////////////////////////////////////////////////////////// |
| 70 // ExtensionMessageBubbleController |
| 71 |
| 72 ExtensionMessageBubbleController::ExtensionMessageBubbleController( |
| 73 ExtensionListType type, Profile* profile) |
| 74 : service_(extensions::ExtensionSystem::Get(profile)->extension_service()), |
| 75 profile_(profile), |
| 76 user_action_(ACTION_BOUNDARY), |
| 77 type_(type), |
| 78 has_notified_(false), |
| 79 showing_bubble_(false) { |
| 80 } |
| 81 |
| 82 ExtensionMessageBubbleController::~ExtensionMessageBubbleController() { |
| 83 } |
| 84 |
| 85 bool ExtensionMessageBubbleController::HasExtensionList() { |
| 86 if (has_notified_) |
| 87 return false; |
| 88 |
| 89 scoped_ptr<const ExtensionSet> extension_set( |
| 90 service_->GenerateInstalledExtensionsSet()); |
| 91 for (ExtensionSet::const_iterator it = extension_set->begin(); |
| 92 it != extension_set->end(); ++it) { |
| 93 std::string id = (*it)->id(); |
| 94 if (!ShouldIncludeExtension(id)) |
| 95 continue; |
| 96 extension_list_.push_back(id); |
| 97 } |
| 98 |
| 99 // Log the UMA histogram. |
| 100 switch (type_) { |
| 101 case SUSPICIOUS_EXTENSIONS: |
| 102 UMA_HISTOGRAM_COUNTS_100( |
| 103 "ExtensionWipeoutBubble.ExtensionWipeoutCount", |
| 104 extension_list_.size()); |
| 105 break; |
| 106 case DEV_MODE_EXTENSIONS: |
| 107 UMA_HISTOGRAM_COUNTS_100( |
| 108 "DevModeExtensionBubble.ExtensionsInDevModeCount", |
| 109 extension_list_.size()); |
| 110 break; |
| 111 case NUM_BUBBLE_TYPES: |
| 112 NOTREACHED(); |
| 113 break; |
| 114 } |
| 115 |
| 116 has_notified_ = true; |
| 117 return !extension_list_.empty(); |
| 118 } |
| 119 |
| 120 std::vector<string16> |
| 121 ExtensionMessageBubbleController::GetExtensionList() const { |
| 122 if (extension_list_.empty()) |
| 123 return std::vector<string16>(); |
| 124 |
| 125 std::vector<string16> return_value; |
| 126 for (ExtensionIdList::const_iterator it = extension_list_.begin(); |
| 127 it != extension_list_.end(); ++it) { |
| 128 const Extension* extension = service_->GetInstalledExtension(*it); |
| 129 if (extension) { |
| 130 return_value.push_back(UTF8ToUTF16(extension->name())); |
| 131 } else { |
| 132 return_value.push_back( |
| 133 ASCIIToUTF16(std::string("(unknown name) ") + *it)); |
| 134 // TODO(finnur): Add this as a string to the grd, for next milestone. |
| 135 } |
| 136 } |
| 137 return return_value; |
| 138 } |
| 139 |
| 140 void ExtensionMessageBubbleController::Show(ExtensionMessageBubble* bubble) { |
| 141 // Wire up all the callbacks, to get notified what actions the user took. |
| 142 base::Closure dismiss_button_callback = |
| 143 base::Bind(&ExtensionMessageBubbleController::OnBubbleDismiss, |
| 144 base::Unretained(this)); |
| 145 base::Closure action_button_callback = |
| 146 base::Bind(&ExtensionMessageBubbleController::OnBubbleAction, |
| 147 base::Unretained(this)); |
| 148 base::Closure link_callback = |
| 149 base::Bind(&ExtensionMessageBubbleController::OnLinkClicked, |
| 150 base::Unretained(this)); |
| 151 bubble->OnActionButtonClicked(action_button_callback); |
| 152 bubble->OnDismissButtonClicked(dismiss_button_callback); |
| 153 bubble->OnLinkClicked(link_callback); |
| 154 |
| 155 showing_bubble_ = true; |
| 156 bubble->Show(); |
| 157 } |
| 158 |
| 159 string16 ExtensionMessageBubbleController::GetTitle() const { |
| 160 return l10n_util::GetStringUTF16(kTitleIds[type_]); |
| 161 } |
| 162 |
| 163 string16 ExtensionMessageBubbleController::GetMessageBody() const { |
| 164 if (kBodyInjectIds[type_] == 0) |
| 165 return l10n_util::GetStringUTF16(kBodyIds[type_]); |
| 166 |
| 167 return l10n_util::GetStringFUTF16(kBodyIds[type_], |
| 168 l10n_util::GetStringUTF16(kBodyInjectIds[type_])); |
| 169 } |
| 170 |
| 171 string16 ExtensionMessageBubbleController::GetOverflowText( |
| 172 const string16& overflow_count) const { |
| 173 return l10n_util::GetStringFUTF16( |
| 174 IDS_EXTENSIONS_SUSPICIOUS_DISABLED_AND_N_MORE, |
| 175 overflow_count); |
| 176 } |
| 177 |
| 178 string16 ExtensionMessageBubbleController::GetLearnMoreLabel() const { |
| 179 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); |
| 180 } |
| 181 |
| 182 string16 ExtensionMessageBubbleController::GetActionButtonLabel() const { |
| 183 if (!kAcceptIds[type_]) |
| 184 return string16(); |
| 185 |
| 186 return l10n_util::GetStringUTF16(kAcceptIds[type_]); |
| 187 } |
| 188 |
| 189 string16 ExtensionMessageBubbleController::GetDismissButtonLabel() const { |
| 190 return l10n_util::GetStringUTF16(kDismissIds[type_]); |
| 191 } |
| 192 |
| 193 bool ExtensionMessageBubbleController::ShouldShowExtensionList() const { |
| 194 return kShowExtensionList[type_]; |
| 195 } |
| 196 |
| 197 void ExtensionMessageBubbleController::OnBubbleAction() { |
| 198 DCHECK_EQ(ACTION_BOUNDARY, user_action_); |
| 199 user_action_ = ACTION_EXECUTE; |
| 200 |
| 201 RecordAction(ACTION_EXECUTE); |
| 202 PerformAction(); |
| 203 AcknowledgeExtensions(); |
| 204 } |
| 205 |
| 206 void ExtensionMessageBubbleController::OnBubbleDismiss() { |
| 207 DCHECK_EQ(ACTION_BOUNDARY, user_action_); |
| 208 user_action_ = ACTION_DISMISS; |
| 209 |
| 210 RecordAction(ACTION_DISMISS); |
| 211 AcknowledgeExtensions(); |
| 212 } |
| 213 |
| 214 void ExtensionMessageBubbleController::OnLinkClicked() { |
| 215 DCHECK_EQ(ACTION_BOUNDARY, user_action_); |
| 216 user_action_ = ACTION_LEARN_MORE; |
| 217 |
| 218 RecordAction(ACTION_LEARN_MORE); |
| 219 Browser* browser = |
| 220 chrome::FindBrowserWithProfile(profile_, chrome::GetActiveDesktop()); |
| 221 if (browser) { |
| 222 browser->OpenURL( |
| 223 content::OpenURLParams(GURL(kLearnMoreLikeIds[type_]), |
| 224 content::Referrer(), |
| 225 NEW_FOREGROUND_TAB, |
| 226 content::PAGE_TRANSITION_LINK, |
| 227 false)); |
| 228 } |
| 229 AcknowledgeExtensions(); |
| 230 } |
| 231 |
| 232 void ExtensionMessageBubbleController::AcknowledgeExtensions() { |
| 233 for (ExtensionIdList::const_iterator it = extension_list_.begin(); |
| 234 it != extension_list_.end(); ++it) |
| 235 AcknowledgeExtension(*it); |
| 236 showing_bubble_ = false; |
| 237 } |
| 238 |
| 239 void ExtensionMessageBubbleController::RecordAction( |
| 240 UmaExtensionListHistogramOptions action) { |
| 241 switch (type_) { |
| 242 case SUSPICIOUS_EXTENSIONS: |
| 243 UMA_HISTOGRAM_ENUMERATION("ExtensionWipeoutBubble.UserSelection", |
| 244 action, ACTION_BOUNDARY); |
| 245 break; |
| 246 case DEV_MODE_EXTENSIONS: |
| 247 UMA_HISTOGRAM_ENUMERATION("DevModeExtensionBubble.UserSelection", |
| 248 action, ACTION_BOUNDARY); |
| 249 break; |
| 250 case NUM_BUBBLE_TYPES: |
| 251 NOTREACHED(); |
| 252 break; |
| 253 } |
| 254 } |
| 255 |
| 256 } // namespace extensions |
OLD | NEW |