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