| OLD | NEW |
| (Empty) |
| 1 // Copyright 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/ui/app_list/search/webstore_result.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/memory/ref_counted.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "chrome/browser/extensions/extension_service.h" | |
| 13 #include "chrome/browser/extensions/extension_system.h" | |
| 14 #include "chrome/browser/extensions/install_tracker.h" | |
| 15 #include "chrome/browser/extensions/install_tracker_factory.h" | |
| 16 #include "chrome/browser/profiles/profile.h" | |
| 17 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" | |
| 18 #include "chrome/browser/ui/app_list/search/common/url_icon_source.h" | |
| 19 #include "chrome/browser/ui/app_list/search/webstore_installer.h" | |
| 20 #include "chrome/browser/ui/browser_navigator.h" | |
| 21 #include "chrome/browser/ui/extensions/application_launch.h" | |
| 22 #include "chrome/common/extensions/extension.h" | |
| 23 #include "grit/chromium_strings.h" | |
| 24 #include "grit/generated_resources.h" | |
| 25 #include "grit/theme_resources.h" | |
| 26 #include "ui/base/l10n/l10n_util.h" | |
| 27 #include "ui/base/resource/resource_bundle.h" | |
| 28 #include "ui/gfx/canvas.h" | |
| 29 #include "ui/gfx/image/canvas_image_source.h" | |
| 30 | |
| 31 | |
| 32 namespace { | |
| 33 | |
| 34 const int kIconSize = 32; | |
| 35 | |
| 36 // BadgedImageSource adds a webstore badge to a webstore app icon. | |
| 37 class BadgedIconSource : public gfx::CanvasImageSource { | |
| 38 public: | |
| 39 explicit BadgedIconSource(const gfx::ImageSkia& icon) | |
| 40 : CanvasImageSource(gfx::Size(kIconSize, kIconSize), false), | |
| 41 icon_(icon) { | |
| 42 } | |
| 43 | |
| 44 virtual void Draw(gfx::Canvas* canvas) OVERRIDE { | |
| 45 canvas->DrawImageInt(icon_, 0, 0); | |
| 46 const gfx::ImageSkia& badge = *ui::ResourceBundle::GetSharedInstance(). | |
| 47 GetImageSkiaNamed(IDR_WEBSTORE_ICON_16); | |
| 48 canvas->DrawImageInt( | |
| 49 badge, icon_.width() - badge.width(), icon_.height() - badge.height()); | |
| 50 } | |
| 51 | |
| 52 private: | |
| 53 gfx::ImageSkia icon_; | |
| 54 | |
| 55 DISALLOW_COPY_AND_ASSIGN(BadgedIconSource); | |
| 56 }; | |
| 57 | |
| 58 } // namespace | |
| 59 | |
| 60 namespace app_list { | |
| 61 | |
| 62 WebstoreResult::WebstoreResult(Profile* profile, | |
| 63 const std::string& app_id, | |
| 64 const std::string& localized_name, | |
| 65 const GURL& icon_url, | |
| 66 AppListControllerDelegate* controller) | |
| 67 : profile_(profile), | |
| 68 app_id_(app_id), | |
| 69 localized_name_(localized_name), | |
| 70 icon_url_(icon_url), | |
| 71 weak_factory_(this), | |
| 72 controller_(controller), | |
| 73 install_tracker_(NULL) { | |
| 74 set_id(extensions::Extension::GetBaseURLFromExtensionId(app_id_).spec()); | |
| 75 set_relevance(0.0); // What is the right value to use? | |
| 76 | |
| 77 set_title(UTF8ToUTF16(localized_name_)); | |
| 78 SetDefaultDetails(); | |
| 79 | |
| 80 UpdateActions(); | |
| 81 | |
| 82 icon_ = gfx::ImageSkia( | |
| 83 new UrlIconSource(base::Bind(&WebstoreResult::OnIconLoaded, | |
| 84 weak_factory_.GetWeakPtr()), | |
| 85 profile_->GetRequestContext(), | |
| 86 icon_url_, | |
| 87 kIconSize, | |
| 88 IDR_WEBSTORE_ICON_32), | |
| 89 gfx::Size(kIconSize, kIconSize)); | |
| 90 SetIcon(icon_); | |
| 91 | |
| 92 StartObservingInstall(); | |
| 93 } | |
| 94 | |
| 95 WebstoreResult::~WebstoreResult() { | |
| 96 StopObservingInstall(); | |
| 97 } | |
| 98 | |
| 99 void WebstoreResult::Open(int event_flags) { | |
| 100 const GURL store_url(extension_urls::GetWebstoreItemDetailURLPrefix() + | |
| 101 app_id_); | |
| 102 chrome::NavigateParams params(profile_, | |
| 103 store_url, | |
| 104 content::PAGE_TRANSITION_LINK); | |
| 105 params.disposition = ui::DispositionFromEventFlags(event_flags); | |
| 106 chrome::Navigate(¶ms); | |
| 107 } | |
| 108 | |
| 109 void WebstoreResult::InvokeAction(int action_index, int event_flags) { | |
| 110 DCHECK_EQ(0, action_index); | |
| 111 StartInstall(); | |
| 112 } | |
| 113 | |
| 114 scoped_ptr<ChromeSearchResult> WebstoreResult::Duplicate() { | |
| 115 return scoped_ptr<ChromeSearchResult>(new WebstoreResult( | |
| 116 profile_, app_id_, localized_name_, icon_url_, controller_)).Pass(); | |
| 117 } | |
| 118 | |
| 119 void WebstoreResult::UpdateActions() { | |
| 120 Actions actions; | |
| 121 | |
| 122 const bool is_otr = profile_->IsOffTheRecord(); | |
| 123 const bool is_installed = !!extensions::ExtensionSystem::Get(profile_)-> | |
| 124 extension_service()->GetInstalledExtension(app_id_); | |
| 125 | |
| 126 if (!is_otr && !is_installed && !is_installing()) { | |
| 127 actions.push_back(Action( | |
| 128 l10n_util::GetStringUTF16(IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE), | |
| 129 base::string16())); | |
| 130 } | |
| 131 | |
| 132 SetActions(actions); | |
| 133 } | |
| 134 | |
| 135 void WebstoreResult::SetDefaultDetails() { | |
| 136 const base::string16 details = | |
| 137 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE); | |
| 138 Tags details_tags; | |
| 139 details_tags.push_back(Tag(SearchResult::Tag::DIM, 0, details.length())); | |
| 140 | |
| 141 set_details(details); | |
| 142 set_details_tags(details_tags); | |
| 143 } | |
| 144 | |
| 145 void WebstoreResult::OnIconLoaded() { | |
| 146 // Remove the existing image reps since the icon data is loaded and they | |
| 147 // need to be re-created. | |
| 148 const std::vector<gfx::ImageSkiaRep>& image_reps = icon_.image_reps(); | |
| 149 for (size_t i = 0; i < image_reps.size(); ++i) | |
| 150 icon_.RemoveRepresentation(image_reps[i].scale_factor()); | |
| 151 | |
| 152 icon_ = gfx::ImageSkia(new BadgedIconSource(icon_), | |
| 153 gfx::Size(kIconSize, kIconSize)); | |
| 154 | |
| 155 SetIcon(icon_); | |
| 156 } | |
| 157 | |
| 158 void WebstoreResult::StartInstall() { | |
| 159 SetPercentDownloaded(0); | |
| 160 SetIsInstalling(true); | |
| 161 | |
| 162 scoped_refptr<WebstoreInstaller> installer = | |
| 163 new WebstoreInstaller( | |
| 164 app_id_, | |
| 165 profile_, | |
| 166 controller_->GetAppListWindow(), | |
| 167 base::Bind(&WebstoreResult::InstallCallback, | |
| 168 weak_factory_.GetWeakPtr())); | |
| 169 installer->BeginInstall(); | |
| 170 } | |
| 171 | |
| 172 void WebstoreResult::InstallCallback(bool success, const std::string& error) { | |
| 173 if (!success) { | |
| 174 LOG(ERROR) << "Failed to install app, error=" << error; | |
| 175 SetIsInstalling(false); | |
| 176 return; | |
| 177 } | |
| 178 | |
| 179 // Success handling is continued in OnExtensionInstalled. | |
| 180 SetPercentDownloaded(100); | |
| 181 } | |
| 182 | |
| 183 void WebstoreResult::StartObservingInstall() { | |
| 184 DCHECK(!install_tracker_); | |
| 185 | |
| 186 install_tracker_ = extensions::InstallTrackerFactory::GetForProfile(profile_); | |
| 187 install_tracker_->AddObserver(this); | |
| 188 } | |
| 189 | |
| 190 void WebstoreResult::StopObservingInstall() { | |
| 191 if (install_tracker_) | |
| 192 install_tracker_->RemoveObserver(this); | |
| 193 | |
| 194 install_tracker_ = NULL; | |
| 195 } | |
| 196 | |
| 197 void WebstoreResult::OnBeginExtensionInstall( | |
| 198 const std::string& extension_id, | |
| 199 const std::string& extension_name, | |
| 200 const gfx::ImageSkia& installing_icon, | |
| 201 bool is_app, | |
| 202 bool is_platform_app) {} | |
| 203 | |
| 204 void WebstoreResult::OnDownloadProgress(const std::string& extension_id, | |
| 205 int percent_downloaded) { | |
| 206 if (extension_id != app_id_ || percent_downloaded < 0) | |
| 207 return; | |
| 208 | |
| 209 SetPercentDownloaded(percent_downloaded); | |
| 210 } | |
| 211 | |
| 212 void WebstoreResult::OnInstallFailure(const std::string& extension_id) {} | |
| 213 | |
| 214 void WebstoreResult::OnExtensionInstalled( | |
| 215 const extensions::Extension* extension) { | |
| 216 if (extension->id() != app_id_) | |
| 217 return; | |
| 218 | |
| 219 SetIsInstalling(false); | |
| 220 UpdateActions(); | |
| 221 NotifyItemInstalled(); | |
| 222 } | |
| 223 | |
| 224 void WebstoreResult::OnExtensionLoaded( | |
| 225 const extensions::Extension* extension) {} | |
| 226 | |
| 227 void WebstoreResult::OnExtensionUnloaded( | |
| 228 const extensions::Extension* extension) {} | |
| 229 | |
| 230 void WebstoreResult::OnExtensionUninstalled( | |
| 231 const extensions::Extension* extension) {} | |
| 232 | |
| 233 void WebstoreResult::OnAppsReordered() {} | |
| 234 | |
| 235 void WebstoreResult::OnAppInstalledToAppList(const std::string& extension_id) {} | |
| 236 | |
| 237 void WebstoreResult::OnShutdown() { | |
| 238 StopObservingInstall(); | |
| 239 } | |
| 240 | |
| 241 ChromeSearchResultType WebstoreResult::GetType() { | |
| 242 return SEARCH_WEBSTORE_SEARCH_RESULT; | |
| 243 } | |
| 244 | |
| 245 } // namespace app_list | |
| OLD | NEW |