Fix uninstall extension dialog has different icon.

This CL sync icon used for extension dialog with default one used to
represent extension based app.
This additionally fixes following issues:
  - base class for uninstall dialog and implementation has own
  expectations for icon size. Now use only one source to define icon
  size.
  - Provide correct loading of icons for non-standard device scale
  factors.

For mechanical change in extension_uninstall_dialog_cocoa.mm
[email protected]

      desktop.

Bug: 730853
Test: Manually on Cave (1.25 scale factor), Linux Chrome OS + Linux
Change-Id: Ib3d1c80d6883a079728b917efc726e9458b6bacb
Reviewed-on: https://chromium-review.googlesource.com/527527
Commit-Queue: Yury Khmel <[email protected]>
Reviewed-by: Devlin <[email protected]>
Reviewed-by: Xiyuan Xia <[email protected]>
Cr-Commit-Position: refs/heads/master@{#481802}
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc
index 5862abf..11405b7 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.cc
+++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -9,11 +9,13 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/chrome_app_icon_service.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/native_window_tracker.h"
 #include "chrome/grit/generated_resources.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_registry.h"
@@ -21,14 +23,15 @@
 #include "extensions/browser/image_loader.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
-#include "extensions/common/extension_icon_set.h"
-#include "extensions/common/extension_resource.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
 #include "extensions/common/manifest_url_handlers.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/layout.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 
@@ -36,28 +39,34 @@
 
 namespace {
 
-const char kExtensionRemovedError[] =
+constexpr int kIconSize = 64;
+
+constexpr char kExtensionRemovedError[] =
     "Extension was removed before dialog closed.";
 
-const char kReferrerId[] = "chrome-remove-extension-dialog";
+constexpr char kReferrerId[] = "chrome-remove-extension-dialog";
 
-// Returns gfx::ImageSkia for the default icon.
-gfx::ImageSkia GetDefaultIconImage(bool is_app) {
-  return  is_app ? util::GetDefaultAppIcon() : util::GetDefaultExtensionIcon();
+float GetScaleFactor(gfx::NativeWindow window) {
+  const display::Screen* screen = display::Screen::GetScreen();
+  if (!screen)
+    return 1.0;  // Happens in unit_tests.
+  if (window)
+    return screen->GetDisplayNearestWindow(window).device_scale_factor();
+  return screen->GetPrimaryDisplay().device_scale_factor();
 }
 
 }  // namespace
 
 ExtensionUninstallDialog::ExtensionUninstallDialog(
     Profile* profile,
+    gfx::NativeWindow parent,
     ExtensionUninstallDialog::Delegate* delegate)
-    : profile_(profile),
-      delegate_(delegate),
-      uninstall_reason_(UNINSTALL_REASON_FOR_TESTING) {
+    : profile_(profile), parent_(parent), delegate_(delegate), observer_(this) {
+  if (parent)
+    parent_window_tracker_ = NativeWindowTracker::Create(parent);
 }
 
-ExtensionUninstallDialog::~ExtensionUninstallDialog() {
-}
+ExtensionUninstallDialog::~ExtensionUninstallDialog() = default;
 
 void ExtensionUninstallDialog::ConfirmUninstallByExtension(
     const scoped_refptr<const Extension>& extension,
@@ -79,48 +88,36 @@
 
   extension_ = extension;
   uninstall_reason_ = reason;
-  // Bookmark apps may not have 128x128 icons so accept 64x64 icons.
-  const int icon_size = extension_->from_bookmark()
-                            ? extension_misc::EXTENSION_ICON_SMALL * 2
-                            : extension_misc::EXTENSION_ICON_LARGE;
-  ExtensionResource image = IconsInfo::GetIconResource(
-      extension_.get(), icon_size, ExtensionIconSet::MATCH_BIGGER);
 
-  // Load the image asynchronously. The response will be sent to OnImageLoaded.
-  ImageLoader* loader = ImageLoader::Get(profile_);
-
-  SetIcon(gfx::Image());
-  std::vector<ImageLoader::ImageRepresentation> images_list;
-  images_list.push_back(ImageLoader::ImageRepresentation(
-      image,
-      ImageLoader::ImageRepresentation::NEVER_RESIZE,
-      gfx::Size(),
-      ui::SCALE_FACTOR_100P));
-  loader->LoadImagesAsync(extension_.get(), images_list,
-                          base::Bind(&ExtensionUninstallDialog::OnImageLoaded,
-                                     AsWeakPtr(), extension_->id()));
-}
-
-void ExtensionUninstallDialog::SetIcon(const gfx::Image& image) {
-  if (image.IsEmpty()) {
-    icon_ = GetDefaultIconImage(extension_->is_app());
-  } else {
-    icon_ = *image.ToImageSkia();
-  }
-}
-
-void ExtensionUninstallDialog::OnImageLoaded(const std::string& extension_id,
-                                             const gfx::Image& image) {
-  const Extension* target_extension =
-      ExtensionRegistry::Get(profile_)
-          ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
-  if (!target_extension) {
-    delegate_->OnExtensionUninstallDialogClosed(
-        false, base::ASCIIToUTF16(kExtensionRemovedError));
+  if (parent() && parent_window_tracker_->WasNativeWindowClosed()) {
+    OnDialogClosed(CLOSE_ACTION_CANCELED);
     return;
   }
 
-  SetIcon(image);
+  // Track that extension uninstalled externally.
+  DCHECK(!observer_.IsObserving(ExtensionRegistry::Get(profile_)));
+  observer_.Add(ExtensionRegistry::Get(profile_));
+
+  // Dialog will be shown once icon is loaded.
+  DCHECK(!dialog_shown_);
+  icon_ = ChromeAppIconService::Get(profile_)->CreateIcon(this, extension->id(),
+                                                          kIconSize);
+  icon_->image_skia().GetRepresentation(GetScaleFactor(parent_));
+}
+
+void ExtensionUninstallDialog::OnIconUpdated(ChromeAppIcon* icon) {
+  // Ignore initial update.
+  if (!icon_ || dialog_shown_)
+    return;
+
+  DCHECK_EQ(icon, icon_.get());
+
+  dialog_shown_ = true;
+
+  if (parent() && parent_window_tracker_->WasNativeWindowClosed()) {
+    OnDialogClosed(CLOSE_ACTION_CANCELED);
+    return;
+  }
 
   switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
     case ScopedTestDialogAutoConfirm::NONE:
@@ -138,6 +135,19 @@
   }
 }
 
+void ExtensionUninstallDialog::OnExtensionUninstalled(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    UninstallReason reason) {
+  // Handle the case when extension was uninstalled externally and we have to
+  // close current dialog.
+  if (extension != extension_)
+    return;
+
+  delegate_->OnExtensionUninstallDialogClosed(
+      false, base::ASCIIToUTF16(kExtensionRemovedError));
+}
+
 std::string ExtensionUninstallDialog::GetHeadingText() {
   if (triggering_extension_) {
     return l10n_util::GetStringFUTF8(
@@ -191,6 +201,8 @@
       ExtensionRegistry::Get(profile_)->GetExtensionById(
           extension_->id(), ExtensionRegistry::EVERYTHING);
   if (current_extension) {
+    // Prevent notifications triggered by our request.
+    observer_.RemoveAll();
     return ExtensionSystem::Get(profile_)
         ->extension_service()
         ->UninstallExtension(extension_->id(), uninstall_reason_,