Resubmit: Refactor external_install_ui
[chromium-blink-merge.git] / chrome / browser / extensions / external_install_error.cc
blob6b35e5454bfb0e917947cfd0f89379506902db93
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_service.h"
11 #include "chrome/browser/extensions/external_install_manager.h"
12 #include "chrome/browser/extensions/webstore_data_fetcher.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_finder.h"
16 #include "chrome/browser/ui/global_error/global_error.h"
17 #include "chrome/browser/ui/global_error/global_error_service.h"
18 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/common/constants.h"
23 #include "extensions/common/extension.h"
24 #include "grit/generated_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/gfx/image/image.h"
27 #include "ui/gfx/image/image_skia_operations.h"
29 namespace extensions {
31 namespace {
33 // Return the menu label for a global error.
34 base::string16 GetMenuItemLabel(const Extension* extension) {
35 if (!extension)
36 return base::string16();
38 int id = -1;
39 if (extension->is_app())
40 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
41 else if (extension->is_theme())
42 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
43 else
44 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
46 return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension->name()));
49 // A global error that spawns a dialog when the menu item is clicked.
50 class ExternalInstallMenuAlert : public GlobalError {
51 public:
52 explicit ExternalInstallMenuAlert(ExternalInstallError* error);
53 virtual ~ExternalInstallMenuAlert();
55 private:
56 // GlobalError implementation.
57 virtual Severity GetSeverity() OVERRIDE;
58 virtual bool HasMenuItem() OVERRIDE;
59 virtual int MenuItemCommandID() OVERRIDE;
60 virtual base::string16 MenuItemLabel() OVERRIDE;
61 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
62 virtual bool HasBubbleView() OVERRIDE;
63 virtual bool HasShownBubbleView() OVERRIDE;
64 virtual void ShowBubbleView(Browser* browser) OVERRIDE;
65 virtual GlobalErrorBubbleViewBase* GetBubbleView() OVERRIDE;
67 // The owning ExternalInstallError.
68 ExternalInstallError* error_;
70 DISALLOW_COPY_AND_ASSIGN(ExternalInstallMenuAlert);
73 // A global error that spawns a bubble when the menu item is clicked.
74 class ExternalInstallBubbleAlert : public GlobalErrorWithStandardBubble {
75 public:
76 explicit ExternalInstallBubbleAlert(ExternalInstallError* error,
77 ExtensionInstallPrompt::Prompt* prompt);
78 virtual ~ExternalInstallBubbleAlert();
80 private:
81 // GlobalError implementation.
82 virtual Severity GetSeverity() OVERRIDE;
83 virtual bool HasMenuItem() OVERRIDE;
84 virtual int MenuItemCommandID() OVERRIDE;
85 virtual base::string16 MenuItemLabel() OVERRIDE;
86 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
88 // GlobalErrorWithStandardBubble implementation.
89 virtual gfx::Image GetBubbleViewIcon() OVERRIDE;
90 virtual base::string16 GetBubbleViewTitle() OVERRIDE;
91 virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
92 virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
93 virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
94 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
95 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
96 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
98 // The owning ExternalInstallError.
99 ExternalInstallError* error_;
101 // The Prompt with all information, which we then use to populate the bubble.
102 ExtensionInstallPrompt::Prompt* prompt_;
104 DISALLOW_COPY_AND_ASSIGN(ExternalInstallBubbleAlert);
107 ////////////////////////////////////////////////////////////////////////////////
108 // ExternalInstallMenuAlert
110 ExternalInstallMenuAlert::ExternalInstallMenuAlert(ExternalInstallError* error)
111 : error_(error) {
114 ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
117 GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
118 return SEVERITY_LOW;
121 bool ExternalInstallMenuAlert::HasMenuItem() {
122 return true;
125 int ExternalInstallMenuAlert::MenuItemCommandID() {
126 return IDC_EXTERNAL_EXTENSION_ALERT;
129 base::string16 ExternalInstallMenuAlert::MenuItemLabel() {
130 return GetMenuItemLabel(error_->GetExtension());
133 void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
134 error_->ShowDialog(browser);
137 bool ExternalInstallMenuAlert::HasBubbleView() {
138 return false;
141 bool ExternalInstallMenuAlert::HasShownBubbleView() {
142 NOTREACHED();
143 return true;
146 void ExternalInstallMenuAlert::ShowBubbleView(Browser* browser) {
147 NOTREACHED();
150 GlobalErrorBubbleViewBase* ExternalInstallMenuAlert::GetBubbleView() {
151 return NULL;
154 ////////////////////////////////////////////////////////////////////////////////
155 // ExternalInstallBubbleAlert
157 ExternalInstallBubbleAlert::ExternalInstallBubbleAlert(
158 ExternalInstallError* error,
159 ExtensionInstallPrompt::Prompt* prompt)
160 : error_(error), prompt_(prompt) {
161 DCHECK(error_);
162 DCHECK(prompt_);
165 ExternalInstallBubbleAlert::~ExternalInstallBubbleAlert() {
168 GlobalError::Severity ExternalInstallBubbleAlert::GetSeverity() {
169 return SEVERITY_LOW;
172 bool ExternalInstallBubbleAlert::HasMenuItem() {
173 return true;
176 int ExternalInstallBubbleAlert::MenuItemCommandID() {
177 return IDC_EXTERNAL_EXTENSION_ALERT;
180 base::string16 ExternalInstallBubbleAlert::MenuItemLabel() {
181 return GetMenuItemLabel(error_->GetExtension());
184 void ExternalInstallBubbleAlert::ExecuteMenuItem(Browser* browser) {
185 ShowBubbleView(browser);
188 gfx::Image ExternalInstallBubbleAlert::GetBubbleViewIcon() {
189 if (prompt_->icon().IsEmpty())
190 return GlobalErrorWithStandardBubble::GetBubbleViewIcon();
191 // Scale icon to a reasonable size.
192 return gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
193 *prompt_->icon().ToImageSkia(),
194 skia::ImageOperations::RESIZE_BEST,
195 gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
196 extension_misc::EXTENSION_ICON_SMALL)));
199 base::string16 ExternalInstallBubbleAlert::GetBubbleViewTitle() {
200 return prompt_->GetDialogTitle();
203 std::vector<base::string16>
204 ExternalInstallBubbleAlert::GetBubbleViewMessages() {
205 std::vector<base::string16> messages;
206 messages.push_back(prompt_->GetHeading());
207 if (prompt_->GetPermissionCount()) {
208 messages.push_back(prompt_->GetPermissionsHeading());
209 for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) {
210 messages.push_back(l10n_util::GetStringFUTF16(
211 IDS_EXTENSION_PERMISSION_LINE, prompt_->GetPermission(i)));
214 // TODO(yoz): OAuth issue advice?
215 return messages;
218 base::string16 ExternalInstallBubbleAlert::GetBubbleViewAcceptButtonLabel() {
219 return prompt_->GetAcceptButtonLabel();
222 base::string16 ExternalInstallBubbleAlert::GetBubbleViewCancelButtonLabel() {
223 return prompt_->GetAbortButtonLabel();
226 void ExternalInstallBubbleAlert::OnBubbleViewDidClose(Browser* browser) {
229 void ExternalInstallBubbleAlert::BubbleViewAcceptButtonPressed(
230 Browser* browser) {
231 error_->InstallUIProceed();
234 void ExternalInstallBubbleAlert::BubbleViewCancelButtonPressed(
235 Browser* browser) {
236 error_->InstallUIAbort(true);
239 } // namespace
241 ////////////////////////////////////////////////////////////////////////////////
242 // ExternalInstallError
244 ExternalInstallError::ExternalInstallError(
245 content::BrowserContext* browser_context,
246 const std::string& extension_id,
247 AlertType alert_type,
248 ExternalInstallManager* manager)
249 : browser_context_(browser_context),
250 extension_id_(extension_id),
251 alert_type_(alert_type),
252 manager_(manager),
253 error_service_(GlobalErrorServiceFactory::GetForProfile(
254 Profile::FromBrowserContext(browser_context_))),
255 weak_factory_(this) {
256 prompt_ = new ExtensionInstallPrompt::Prompt(
257 ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT);
259 webstore_data_fetcher_.reset(new WebstoreDataFetcher(
260 this, browser_context_->GetRequestContext(), GURL(), extension_id_));
261 webstore_data_fetcher_->Start();
264 ExternalInstallError::~ExternalInstallError() {
265 if (global_error_.get())
266 error_service_->RemoveGlobalError(global_error_.get());
269 void ExternalInstallError::InstallUIProceed() {
270 const Extension* extension = GetExtension();
271 if (extension) {
272 ExtensionSystem::Get(browser_context_)
273 ->extension_service()
274 ->GrantPermissionsAndEnableExtension(extension);
275 // Since the manager listens for the extension to be loaded, this will
276 // remove the error...
277 } else {
278 // ... Otherwise we have to do it explicitly.
279 manager_->RemoveExternalInstallError();
283 void ExternalInstallError::InstallUIAbort(bool user_initiated) {
284 if (user_initiated && GetExtension()) {
285 ExtensionSystem::Get(browser_context_)
286 ->extension_service()
287 ->UninstallExtension(extension_id_,
288 false, // Not externally uninstalled.
289 NULL); // Ignore error.
290 // Since the manager listens for the extension to be removed, this will
291 // remove the error...
292 } else {
293 // ... Otherwise we have to do it explicitly.
294 manager_->RemoveExternalInstallError();
298 void ExternalInstallError::AcknowledgeExtension() {
299 const Extension* extension = GetExtension();
300 if (extension) {
301 ExtensionSystem::Get(browser_context_)
302 ->extension_service()
303 ->AcknowledgeExternalExtension(extension->id());
307 void ExternalInstallError::ShowDialog(Browser* browser) {
308 DCHECK(install_ui_.get());
309 DCHECK(prompt_.get());
310 DCHECK(browser);
311 content::WebContents* web_contents = NULL;
312 #if !defined(OS_ANDROID)
313 web_contents = browser->tab_strip_model()->GetActiveWebContents();
314 #endif
315 ExtensionInstallPrompt::ShowParams params(web_contents);
316 ExtensionInstallPrompt::GetDefaultShowDialogCallback().Run(
317 params, this, prompt_);
320 const Extension* ExternalInstallError::GetExtension() const {
321 return ExtensionRegistry::Get(browser_context_)
322 ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
325 void ExternalInstallError::OnWebstoreRequestFailure() {
326 OnFetchComplete();
329 void ExternalInstallError::OnWebstoreResponseParseSuccess(
330 scoped_ptr<base::DictionaryValue> webstore_data) {
331 std::string localized_user_count;
332 double average_rating;
333 int rating_count;
334 if (!webstore_data->GetString(kUsersKey, &localized_user_count) ||
335 !webstore_data->GetDouble(kAverageRatingKey, &average_rating) ||
336 !webstore_data->GetInteger(kRatingCountKey, &rating_count)) {
337 // If we don't get a valid webstore response, short circuit, and continue
338 // to show a prompt without webstore data.
339 OnFetchComplete();
340 return;
343 bool show_user_count = true;
344 webstore_data->GetBoolean(kShowUserCountKey, &show_user_count);
346 prompt_->SetWebstoreData(
347 localized_user_count, show_user_count, average_rating, rating_count);
348 OnFetchComplete();
351 void ExternalInstallError::OnWebstoreResponseParseFailure(
352 const std::string& error) {
353 OnFetchComplete();
356 void ExternalInstallError::OnFetchComplete() {
357 // Create a new ExtensionInstallPrompt. We pass in NULL for the UI
358 // components because we display at a later point, and don't want
359 // to pass ones which may be invalidated.
360 install_ui_.reset(
361 new ExtensionInstallPrompt(Profile::FromBrowserContext(browser_context_),
362 NULL, // NULL native window.
363 NULL)); // NULL navigator.
365 install_ui_->ConfirmExternalInstall(
366 this,
367 GetExtension(),
368 base::Bind(&ExternalInstallError::OnDialogReady,
369 weak_factory_.GetWeakPtr()),
370 prompt_);
373 void ExternalInstallError::OnDialogReady(
374 const ExtensionInstallPrompt::ShowParams& show_params,
375 ExtensionInstallPrompt::Delegate* prompt_delegate,
376 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt) {
377 DCHECK_EQ(this, prompt_delegate);
378 prompt_ = prompt;
380 if (alert_type_ == BUBBLE_ALERT) {
381 global_error_.reset(new ExternalInstallBubbleAlert(this, prompt_));
382 error_service_->AddGlobalError(global_error_.get());
384 Browser* browser = NULL;
385 #if !defined(OS_ANDROID)
386 browser =
387 chrome::FindTabbedBrowser(Profile::FromBrowserContext(browser_context_),
388 true,
389 chrome::GetActiveDesktop());
390 #endif // !defined(OS_ANDROID)
391 if (browser)
392 global_error_->ShowBubbleView(browser);
393 } else {
394 DCHECK(alert_type_ == MENU_ALERT);
395 global_error_.reset(new ExternalInstallMenuAlert(this));
396 error_service_->AddGlobalError(global_error_.get());
400 } // namespace extensions