Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / external_install_error.cc
blobe94fb5b8601e78f0c20401b2b4385e126d43ce2e
1 // Copyright 2014 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.
5 #include "chrome/browser/extensions/external_install_error.h"
7 #include "base/bind.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/external_install_manager.h"
13 #include "chrome/browser/extensions/webstore_data_fetcher.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/global_error/global_error.h"
18 #include "chrome/browser/ui/global_error/global_error_service.h"
19 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/uninstall_reason.h"
25 #include "extensions/common/constants.h"
26 #include "extensions/common/extension.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/gfx/image/image.h"
29 #include "ui/gfx/image/image_skia_operations.h"
31 namespace extensions {
33 namespace {
35 // Return the menu label for a global error.
36 base::string16 GetMenuItemLabel(const Extension* extension) {
37 if (!extension)
38 return base::string16();
40 int id = -1;
41 if (extension->is_app())
42 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
43 else if (extension->is_theme())
44 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
45 else
46 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
48 return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension->name()));
51 // A global error that spawns a dialog when the menu item is clicked.
52 class ExternalInstallMenuAlert : public GlobalError {
53 public:
54 explicit ExternalInstallMenuAlert(ExternalInstallError* error);
55 ~ExternalInstallMenuAlert() override;
57 private:
58 // GlobalError implementation.
59 Severity GetSeverity() override;
60 bool HasMenuItem() override;
61 int MenuItemCommandID() override;
62 base::string16 MenuItemLabel() override;
63 void ExecuteMenuItem(Browser* browser) override;
64 bool HasBubbleView() override;
65 bool HasShownBubbleView() override;
66 void ShowBubbleView(Browser* browser) override;
67 GlobalErrorBubbleViewBase* GetBubbleView() override;
69 // The owning ExternalInstallError.
70 ExternalInstallError* error_;
72 DISALLOW_COPY_AND_ASSIGN(ExternalInstallMenuAlert);
75 // A global error that spawns a bubble when the menu item is clicked.
76 class ExternalInstallBubbleAlert : public GlobalErrorWithStandardBubble {
77 public:
78 explicit ExternalInstallBubbleAlert(ExternalInstallError* error,
79 ExtensionInstallPrompt::Prompt* prompt);
80 ~ExternalInstallBubbleAlert() override;
82 private:
83 // GlobalError implementation.
84 Severity GetSeverity() override;
85 bool HasMenuItem() override;
86 int MenuItemCommandID() override;
87 base::string16 MenuItemLabel() override;
88 void ExecuteMenuItem(Browser* browser) override;
90 // GlobalErrorWithStandardBubble implementation.
91 gfx::Image GetBubbleViewIcon() override;
92 base::string16 GetBubbleViewTitle() override;
93 std::vector<base::string16> GetBubbleViewMessages() override;
94 base::string16 GetBubbleViewAcceptButtonLabel() override;
95 base::string16 GetBubbleViewCancelButtonLabel() override;
96 void OnBubbleViewDidClose(Browser* browser) override;
97 void BubbleViewAcceptButtonPressed(Browser* browser) override;
98 void BubbleViewCancelButtonPressed(Browser* browser) override;
100 // The owning ExternalInstallError.
101 ExternalInstallError* error_;
103 // The Prompt with all information, which we then use to populate the bubble.
104 ExtensionInstallPrompt::Prompt* prompt_;
106 DISALLOW_COPY_AND_ASSIGN(ExternalInstallBubbleAlert);
109 ////////////////////////////////////////////////////////////////////////////////
110 // ExternalInstallMenuAlert
112 ExternalInstallMenuAlert::ExternalInstallMenuAlert(ExternalInstallError* error)
113 : error_(error) {
116 ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
119 GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
120 return SEVERITY_LOW;
123 bool ExternalInstallMenuAlert::HasMenuItem() {
124 return true;
127 int ExternalInstallMenuAlert::MenuItemCommandID() {
128 return IDC_EXTERNAL_EXTENSION_ALERT;
131 base::string16 ExternalInstallMenuAlert::MenuItemLabel() {
132 return GetMenuItemLabel(error_->GetExtension());
135 void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
136 error_->ShowDialog(browser);
139 bool ExternalInstallMenuAlert::HasBubbleView() {
140 return false;
143 bool ExternalInstallMenuAlert::HasShownBubbleView() {
144 NOTREACHED();
145 return true;
148 void ExternalInstallMenuAlert::ShowBubbleView(Browser* browser) {
149 NOTREACHED();
152 GlobalErrorBubbleViewBase* ExternalInstallMenuAlert::GetBubbleView() {
153 return NULL;
156 ////////////////////////////////////////////////////////////////////////////////
157 // ExternalInstallBubbleAlert
159 ExternalInstallBubbleAlert::ExternalInstallBubbleAlert(
160 ExternalInstallError* error,
161 ExtensionInstallPrompt::Prompt* prompt)
162 : error_(error), prompt_(prompt) {
163 DCHECK(error_);
164 DCHECK(prompt_);
167 ExternalInstallBubbleAlert::~ExternalInstallBubbleAlert() {
170 GlobalError::Severity ExternalInstallBubbleAlert::GetSeverity() {
171 return SEVERITY_LOW;
174 bool ExternalInstallBubbleAlert::HasMenuItem() {
175 return true;
178 int ExternalInstallBubbleAlert::MenuItemCommandID() {
179 return IDC_EXTERNAL_EXTENSION_ALERT;
182 base::string16 ExternalInstallBubbleAlert::MenuItemLabel() {
183 return GetMenuItemLabel(error_->GetExtension());
186 void ExternalInstallBubbleAlert::ExecuteMenuItem(Browser* browser) {
187 ShowBubbleView(browser);
190 gfx::Image ExternalInstallBubbleAlert::GetBubbleViewIcon() {
191 if (prompt_->icon().IsEmpty())
192 return GlobalErrorWithStandardBubble::GetBubbleViewIcon();
193 // Scale icon to a reasonable size.
194 return gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
195 *prompt_->icon().ToImageSkia(),
196 skia::ImageOperations::RESIZE_BEST,
197 gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
198 extension_misc::EXTENSION_ICON_SMALL)));
201 base::string16 ExternalInstallBubbleAlert::GetBubbleViewTitle() {
202 return l10n_util::GetStringFUTF16(
203 IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_BUBBLE_TITLE,
204 base::UTF8ToUTF16(prompt_->extension()->name()));
207 std::vector<base::string16>
208 ExternalInstallBubbleAlert::GetBubbleViewMessages() {
209 ExtensionInstallPrompt::PermissionsType regular_permissions =
210 ExtensionInstallPrompt::PermissionsType::REGULAR_PERMISSIONS;
211 ExtensionInstallPrompt::PermissionsType withheld_permissions =
212 ExtensionInstallPrompt::PermissionsType::WITHHELD_PERMISSIONS;
214 std::vector<base::string16> messages;
215 int heading_id =
216 IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_BUBBLE_HEADING_EXTENSION;
217 if (prompt_->extension()->is_app())
218 heading_id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_BUBBLE_HEADING_APP;
219 else if (prompt_->extension()->is_theme())
220 heading_id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_BUBBLE_HEADING_THEME;
221 messages.push_back(l10n_util::GetStringUTF16(heading_id));
223 if (prompt_->GetPermissionCount(regular_permissions)) {
224 messages.push_back(prompt_->GetPermissionsHeading(regular_permissions));
225 for (size_t i = 0; i < prompt_->GetPermissionCount(regular_permissions);
226 ++i) {
227 messages.push_back(l10n_util::GetStringFUTF16(
228 IDS_EXTENSION_PERMISSION_LINE,
229 prompt_->GetPermission(i, regular_permissions)));
232 if (prompt_->GetPermissionCount(withheld_permissions)) {
233 messages.push_back(prompt_->GetPermissionsHeading(withheld_permissions));
234 for (size_t i = 0; i < prompt_->GetPermissionCount(withheld_permissions);
235 ++i) {
236 messages.push_back(l10n_util::GetStringFUTF16(
237 IDS_EXTENSION_PERMISSION_LINE,
238 prompt_->GetPermission(i, withheld_permissions)));
241 // TODO(yoz): OAuth issue advice?
242 return messages;
245 base::string16 ExternalInstallBubbleAlert::GetBubbleViewAcceptButtonLabel() {
246 return prompt_->GetAcceptButtonLabel();
249 base::string16 ExternalInstallBubbleAlert::GetBubbleViewCancelButtonLabel() {
250 return prompt_->GetAbortButtonLabel();
253 void ExternalInstallBubbleAlert::OnBubbleViewDidClose(Browser* browser) {
256 void ExternalInstallBubbleAlert::BubbleViewAcceptButtonPressed(
257 Browser* browser) {
258 error_->InstallUIProceed();
261 void ExternalInstallBubbleAlert::BubbleViewCancelButtonPressed(
262 Browser* browser) {
263 error_->InstallUIAbort(true);
266 } // namespace
268 ////////////////////////////////////////////////////////////////////////////////
269 // ExternalInstallError
271 ExternalInstallError::ExternalInstallError(
272 content::BrowserContext* browser_context,
273 const std::string& extension_id,
274 AlertType alert_type,
275 ExternalInstallManager* manager)
276 : browser_context_(browser_context),
277 extension_id_(extension_id),
278 alert_type_(alert_type),
279 manager_(manager),
280 error_service_(GlobalErrorServiceFactory::GetForProfile(
281 Profile::FromBrowserContext(browser_context_))),
282 weak_factory_(this) {
283 prompt_ = new ExtensionInstallPrompt::Prompt(
284 ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT);
286 webstore_data_fetcher_.reset(new WebstoreDataFetcher(
287 this, browser_context_->GetRequestContext(), GURL(), extension_id_));
288 webstore_data_fetcher_->Start();
291 ExternalInstallError::~ExternalInstallError() {
292 if (global_error_.get())
293 error_service_->RemoveGlobalError(global_error_.get());
296 void ExternalInstallError::InstallUIProceed() {
297 const Extension* extension = GetExtension();
298 if (extension) {
299 ExtensionSystem::Get(browser_context_)
300 ->extension_service()
301 ->GrantPermissionsAndEnableExtension(extension);
302 // Since the manager listens for the extension to be loaded, this will
303 // remove the error...
304 } else {
305 // ... Otherwise we have to do it explicitly.
306 manager_->RemoveExternalInstallError();
310 void ExternalInstallError::InstallUIAbort(bool user_initiated) {
311 if (user_initiated && GetExtension()) {
312 ExtensionSystem::Get(browser_context_)
313 ->extension_service()
314 ->UninstallExtension(extension_id_,
315 extensions::UNINSTALL_REASON_INSTALL_CANCELED,
316 base::Bind(&base::DoNothing),
317 NULL); // Ignore error.
318 // Since the manager listens for the extension to be removed, this will
319 // remove the error...
320 } else {
321 // ... Otherwise we have to do it explicitly.
322 manager_->RemoveExternalInstallError();
326 void ExternalInstallError::ShowDialog(Browser* browser) {
327 DCHECK(install_ui_.get());
328 DCHECK(prompt_.get());
329 DCHECK(browser);
330 content::WebContents* web_contents = NULL;
331 web_contents = browser->tab_strip_model()->GetActiveWebContents();
332 install_ui_show_params_.reset(
333 new ExtensionInstallPromptShowParams(web_contents));
334 ExtensionInstallPrompt::GetDefaultShowDialogCallback().Run(
335 install_ui_show_params_.get(), this, prompt_);
338 const Extension* ExternalInstallError::GetExtension() const {
339 return ExtensionRegistry::Get(browser_context_)
340 ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
343 void ExternalInstallError::OnWebstoreRequestFailure() {
344 OnFetchComplete();
347 void ExternalInstallError::OnWebstoreResponseParseSuccess(
348 scoped_ptr<base::DictionaryValue> webstore_data) {
349 std::string localized_user_count;
350 double average_rating = 0;
351 int rating_count = 0;
352 if (!webstore_data->GetString(kUsersKey, &localized_user_count) ||
353 !webstore_data->GetDouble(kAverageRatingKey, &average_rating) ||
354 !webstore_data->GetInteger(kRatingCountKey, &rating_count)) {
355 // If we don't get a valid webstore response, short circuit, and continue
356 // to show a prompt without webstore data.
357 OnFetchComplete();
358 return;
361 bool show_user_count = true;
362 webstore_data->GetBoolean(kShowUserCountKey, &show_user_count);
364 prompt_->SetWebstoreData(
365 localized_user_count, show_user_count, average_rating, rating_count);
366 OnFetchComplete();
369 void ExternalInstallError::OnWebstoreResponseParseFailure(
370 const std::string& error) {
371 OnFetchComplete();
374 void ExternalInstallError::OnFetchComplete() {
375 // Create a new ExtensionInstallPrompt. We pass in NULL for the UI
376 // components because we display at a later point, and don't want
377 // to pass ones which may be invalidated.
378 install_ui_.reset(
379 new ExtensionInstallPrompt(Profile::FromBrowserContext(browser_context_),
380 NULL)); // NULL native window.
382 install_ui_->ConfirmExternalInstall(
383 this,
384 GetExtension(),
385 base::Bind(&ExternalInstallError::OnDialogReady,
386 weak_factory_.GetWeakPtr()),
387 prompt_);
390 void ExternalInstallError::OnDialogReady(
391 ExtensionInstallPromptShowParams* show_params,
392 ExtensionInstallPrompt::Delegate* prompt_delegate,
393 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt) {
394 DCHECK_EQ(this, prompt_delegate);
395 prompt_ = prompt;
397 if (alert_type_ == BUBBLE_ALERT) {
398 global_error_.reset(new ExternalInstallBubbleAlert(this, prompt_.get()));
399 error_service_->AddGlobalError(global_error_.get());
401 Browser* browser =
402 chrome::FindTabbedBrowser(Profile::FromBrowserContext(browser_context_),
403 true,
404 chrome::GetActiveDesktop());
405 if (browser)
406 global_error_->ShowBubbleView(browser);
407 } else {
408 DCHECK(alert_type_ == MENU_ALERT);
409 global_error_.reset(new ExternalInstallMenuAlert(this));
410 error_service_->AddGlobalError(global_error_.get());
414 } // namespace extensions