Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / search / webstore / webstore_result.cc
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/memory/ref_counted.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/apps/ephemeral_app_launcher.h"
13 #include "chrome/browser/extensions/extension_service.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/search_util.h"
20 #include "chrome/browser/ui/app_list/search/webstore/webstore_installer.h"
21 #include "chrome/browser/ui/extensions/application_launch.h"
22 #include "chrome/grit/chromium_strings.h"
23 #include "chrome/grit/generated_resources.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/browser/extension_system.h"
26 #include "extensions/browser/extension_util.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/extension_urls.h"
29 #include "grit/theme_resources.h"
30 #include "net/base/url_util.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/base/resource/resource_bundle.h"
33 #include "ui/gfx/canvas.h"
34 #include "ui/gfx/image/canvas_image_source.h"
35
36 namespace {
37
38 const int kLaunchEphemeralAppAction = 1;
39
40 // BadgedImageSource adds a webstore badge to a webstore app icon.
41 class BadgedIconSource : public gfx::CanvasImageSource {
42  public:
43   BadgedIconSource(const gfx::ImageSkia& icon, const gfx::Size& icon_size)
44       : CanvasImageSource(icon_size, false), icon_(icon) {}
45
46   void Draw(gfx::Canvas* canvas) override {
47     canvas->DrawImageInt(icon_, 0, 0);
48     const gfx::ImageSkia& badge = *ui::ResourceBundle::GetSharedInstance().
49          GetImageSkiaNamed(IDR_WEBSTORE_ICON_16);
50     canvas->DrawImageInt(
51         badge, icon_.width() - badge.width(), icon_.height() - badge.height());
52   }
53
54  private:
55   gfx::ImageSkia icon_;
56
57   DISALLOW_COPY_AND_ASSIGN(BadgedIconSource);
58 };
59
60 }  // namespace
61
62 namespace app_list {
63
64 WebstoreResult::WebstoreResult(Profile* profile,
65                                const std::string& app_id,
66                                const std::string& localized_name,
67                                const GURL& icon_url,
68                                bool is_paid,
69                                extensions::Manifest::Type item_type,
70                                AppListControllerDelegate* controller)
71     : profile_(profile),
72       app_id_(app_id),
73       localized_name_(localized_name),
74       icon_url_(icon_url),
75       is_paid_(is_paid),
76       item_type_(item_type),
77       controller_(controller),
78       install_tracker_(NULL),
79       extension_registry_(NULL),
80       weak_factory_(this) {
81   set_id(extensions::Extension::GetBaseURLFromExtensionId(app_id_).spec());
82   set_relevance(0.0);  // What is the right value to use?
83
84   set_title(base::UTF8ToUTF16(localized_name_));
85   SetDefaultDetails();
86
87   InitAndStartObserving();
88   UpdateActions();
89
90   int icon_dimension = GetPreferredIconDimension();
91   icon_ = gfx::ImageSkia(
92       new UrlIconSource(
93           base::Bind(&WebstoreResult::OnIconLoaded, weak_factory_.GetWeakPtr()),
94           profile_->GetRequestContext(),
95           icon_url_,
96           icon_dimension,
97           IDR_WEBSTORE_ICON_32),
98       gfx::Size(icon_dimension, icon_dimension));
99   SetIcon(icon_);
100 }
101
102 WebstoreResult::~WebstoreResult() {
103   StopObservingInstall();
104   StopObservingRegistry();
105 }
106
107 void WebstoreResult::Open(int event_flags) {
108   RecordHistogram(SEARCH_WEBSTORE_SEARCH_RESULT);
109   const GURL store_url = net::AppendQueryParameter(
110       GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + app_id_),
111       extension_urls::kWebstoreSourceField,
112       extension_urls::kLaunchSourceAppListSearch);
113
114   controller_->OpenURL(profile_,
115                        store_url,
116                        ui::PAGE_TRANSITION_LINK,
117                        ui::DispositionFromEventFlags(event_flags));
118 }
119
120 void WebstoreResult::InvokeAction(int action_index, int event_flags) {
121   if (is_paid_) {
122     // Paid apps cannot be installed directly from the launcher. Instead, open
123     // the webstore page for the app.
124     Open(event_flags);
125     return;
126   }
127
128   StartInstall(action_index == kLaunchEphemeralAppAction);
129 }
130
131 scoped_ptr<SearchResult> WebstoreResult::Duplicate() {
132   return scoped_ptr<SearchResult>(new WebstoreResult(profile_,
133                                                      app_id_,
134                                                      localized_name_,
135                                                      icon_url_,
136                                                      is_paid_,
137                                                      item_type_,
138                                                      controller_));
139 }
140
141 void WebstoreResult::InitAndStartObserving() {
142   DCHECK(!install_tracker_ && !extension_registry_);
143
144   install_tracker_ =
145       extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
146   extension_registry_ = extensions::ExtensionRegistry::Get(profile_);
147
148   const extensions::ActiveInstallData* install_data =
149       install_tracker_->GetActiveInstall(app_id_);
150   if (install_data) {
151     SetPercentDownloaded(install_data->percent_downloaded);
152     SetIsInstalling(true);
153   }
154
155   install_tracker_->AddObserver(this);
156   extension_registry_->AddObserver(this);
157 }
158
159 void WebstoreResult::UpdateActions() {
160   Actions actions;
161
162   const bool is_otr = profile_->IsOffTheRecord();
163   const bool is_installed =
164       extensions::util::IsExtensionInstalledPermanently(app_id_, profile_);
165
166   if (!is_otr && !is_installed && !is_installing()) {
167     if (EphemeralAppLauncher::IsFeatureEnabled()) {
168       actions.push_back(Action(
169           l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_INSTALL),
170           l10n_util::GetStringUTF16(
171               IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE)));
172       if ((item_type_ == extensions::Manifest::TYPE_PLATFORM_APP ||
173            item_type_ == extensions::Manifest::TYPE_HOSTED_APP) &&
174           !is_paid_) {
175         actions.push_back(Action(
176             l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_LAUNCH),
177             l10n_util::GetStringUTF16(IDS_WEBSTORE_RESULT_LAUNCH_APP_TOOLTIP)));
178       }
179     } else {
180       actions.push_back(Action(
181           l10n_util::GetStringUTF16(IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE),
182           base::string16()));
183     }
184   }
185
186   SetActions(actions);
187 }
188
189 void WebstoreResult::SetDefaultDetails() {
190   const base::string16 details =
191       l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE);
192   Tags details_tags;
193   details_tags.push_back(Tag(SearchResult::Tag::DIM, 0, details.length()));
194
195   set_details(details);
196   set_details_tags(details_tags);
197 }
198
199 void WebstoreResult::OnIconLoaded() {
200   // Remove the existing image reps since the icon data is loaded and they
201   // need to be re-created.
202   const std::vector<gfx::ImageSkiaRep>& image_reps = icon_.image_reps();
203   for (size_t i = 0; i < image_reps.size(); ++i)
204     icon_.RemoveRepresentation(image_reps[i].scale());
205   int icon_dimension = GetPreferredIconDimension();
206   gfx::Size icon_size(icon_dimension, icon_dimension);
207   icon_ = gfx::ImageSkia(new BadgedIconSource(icon_, icon_size), icon_size);
208
209   SetIcon(icon_);
210 }
211
212 void WebstoreResult::StartInstall(bool launch_ephemeral_app) {
213   SetPercentDownloaded(0);
214   SetIsInstalling(true);
215
216   if (launch_ephemeral_app) {
217     scoped_refptr<EphemeralAppLauncher> installer =
218         EphemeralAppLauncher::CreateForLauncher(
219             app_id_,
220             profile_,
221             controller_->GetAppListWindow(),
222             base::Bind(&WebstoreResult::LaunchCallback,
223                        weak_factory_.GetWeakPtr()));
224     installer->Start();
225     return;
226   }
227
228   scoped_refptr<WebstoreInstaller> installer =
229       new WebstoreInstaller(
230           app_id_,
231           profile_,
232           controller_->GetAppListWindow(),
233           base::Bind(&WebstoreResult::InstallCallback,
234                      weak_factory_.GetWeakPtr()));
235   installer->BeginInstall();
236 }
237
238 void WebstoreResult::InstallCallback(
239     bool success,
240     const std::string& error,
241     extensions::webstore_install::Result result) {
242   if (!success) {
243     LOG(ERROR) << "Failed to install app, error=" << error;
244     SetIsInstalling(false);
245     return;
246   }
247
248   // Success handling is continued in OnExtensionInstalled.
249   SetPercentDownloaded(100);
250 }
251
252 void WebstoreResult::LaunchCallback(extensions::webstore_install::Result result,
253                                     const std::string& error) {
254   if (result != extensions::webstore_install::SUCCESS)
255     LOG(ERROR) << "Failed to launch app, error=" << error;
256
257   SetIsInstalling(false);
258 }
259
260 void WebstoreResult::StopObservingInstall() {
261   if (install_tracker_)
262     install_tracker_->RemoveObserver(this);
263   install_tracker_ = NULL;
264 }
265
266 void WebstoreResult::StopObservingRegistry() {
267   if (extension_registry_)
268     extension_registry_->RemoveObserver(this);
269   extension_registry_ = NULL;
270 }
271
272 void WebstoreResult::OnDownloadProgress(const std::string& extension_id,
273                                         int percent_downloaded) {
274   if (extension_id != app_id_ || percent_downloaded < 0)
275     return;
276
277   SetPercentDownloaded(percent_downloaded);
278 }
279
280 void WebstoreResult::OnExtensionInstalled(
281     content::BrowserContext* browser_context,
282     const extensions::Extension* extension,
283     bool is_update) {
284   if (extension->id() != app_id_)
285     return;
286
287   SetIsInstalling(false);
288   UpdateActions();
289
290   if (extensions::util::IsExtensionInstalledPermanently(extension->id(),
291                                                         profile_)) {
292     NotifyItemInstalled();
293   }
294 }
295
296 void WebstoreResult::OnShutdown() {
297   StopObservingInstall();
298 }
299
300 void WebstoreResult::OnShutdown(extensions::ExtensionRegistry* registry) {
301   StopObservingRegistry();
302 }
303
304 }  // namespace app_list