Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / search / app_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/app_result.h"
6
7 #include "base/time/time.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_util.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/app_list/app_context_menu.h"
12 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
13 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
14 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
15 #include "content/public/browser/user_metrics.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/extension_system.h"
18 #include "extensions/browser/extension_system_provider.h"
19 #include "extensions/browser/extensions_browser_client.h"
20 #include "extensions/common/constants.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_icon_set.h"
23 #include "extensions/common/manifest_handlers/icons_handler.h"
24 #include "ui/app_list/app_list_switches.h"
25 #include "ui/app_list/search/tokenized_string.h"
26 #include "ui/app_list/search/tokenized_string_match.h"
27 #include "ui/gfx/color_utils.h"
28 #include "ui/gfx/image/image_skia_operations.h"
29
30 namespace app_list {
31
32 AppResult::AppResult(Profile* profile,
33                      const std::string& app_id,
34                      AppListControllerDelegate* controller)
35     : profile_(profile),
36       app_id_(app_id),
37       controller_(controller),
38       extension_registry_(NULL) {
39   set_id(extensions::Extension::GetBaseURLFromExtensionId(app_id_).spec());
40   if (app_list::switches::IsExperimentalAppListEnabled())
41     set_display_type(DISPLAY_TILE);
42
43   const extensions::Extension* extension =
44       extensions::ExtensionSystem::Get(profile_)->extension_service()
45           ->GetInstalledExtension(app_id_);
46   DCHECK(extension);
47
48   is_platform_app_ = extension->is_platform_app();
49
50   icon_.reset(
51       new extensions::IconImage(profile_,
52                                 extension,
53                                 extensions::IconsInfo::GetIcons(extension),
54                                 GetPreferredIconDimension(),
55                                 extensions::util::GetDefaultAppIcon(),
56                                 this));
57   UpdateIcon();
58
59   StartObservingExtensionRegistry();
60 }
61
62 AppResult::~AppResult() {
63   StopObservingExtensionRegistry();
64 }
65
66 void AppResult::UpdateFromMatch(const TokenizedString& title,
67                                 const TokenizedStringMatch& match) {
68   const TokenizedStringMatch::Hits& hits = match.hits();
69
70   Tags tags;
71   tags.reserve(hits.size());
72   for (size_t i = 0; i < hits.size(); ++i)
73     tags.push_back(Tag(Tag::MATCH, hits[i].start(), hits[i].end()));
74
75   set_title(title.text());
76   set_title_tags(tags);
77   set_relevance(match.relevance());
78 }
79
80 void AppResult::UpdateFromLastLaunched(const base::Time& current_time,
81                                        const base::Time& last_launched) {
82   base::TimeDelta delta = current_time - last_launched;
83   DCHECK_LE(0, delta.InSeconds());
84   const int kSecondsInWeek = 60 * 60 * 24 * 7;
85
86   // Set the relevance to a value between 0 and 1. This function decays as the
87   // time delta increases and reaches a value of 0.5 at 1 week.
88   set_relevance(1 / (1 + delta.InSecondsF() / kSecondsInWeek));
89 }
90
91 void AppResult::Open(int event_flags) {
92   const extensions::Extension* extension =
93       extensions::ExtensionSystem::Get(profile_)->extension_service()
94           ->GetInstalledExtension(app_id_);
95   if (!extension)
96     return;
97
98   // Don't auto-enable apps that cannot be launched.
99   if (!extensions::util::IsAppLaunchable(app_id_, profile_))
100     return;
101
102   // Check if enable flow is already running or should be started
103   if (RunExtensionEnableFlow())
104     return;
105
106   CoreAppLauncherHandler::RecordAppListSearchLaunch(extension);
107   content::RecordAction(
108       base::UserMetricsAction("AppList_ClickOnAppFromSearch"));
109
110   controller_->ActivateApp(
111       profile_,
112       extension,
113       AppListControllerDelegate::LAUNCH_FROM_APP_LIST_SEARCH,
114       event_flags);
115 }
116
117 void AppResult::InvokeAction(int action_index, int event_flags) {}
118
119 scoped_ptr<ChromeSearchResult> AppResult::Duplicate() {
120   scoped_ptr<ChromeSearchResult> copy(
121       new AppResult(profile_, app_id_, controller_));
122   copy->set_title(title());
123   copy->set_title_tags(title_tags());
124
125   return copy.Pass();
126 }
127
128 ChromeSearchResultType AppResult::GetType() {
129   return APP_SEARCH_RESULT;
130 }
131
132 ui::MenuModel* AppResult::GetContextMenuModel() {
133   if (!context_menu_) {
134     context_menu_.reset(new AppContextMenu(
135         this, profile_, app_id_, controller_));
136     context_menu_->set_is_platform_app(is_platform_app_);
137     context_menu_->set_is_search_result(true);
138   }
139
140   return context_menu_->GetMenuModel();
141 }
142
143 void AppResult::StartObservingExtensionRegistry() {
144   DCHECK(!extension_registry_);
145
146   extension_registry_ = extensions::ExtensionRegistry::Get(profile_);
147   extension_registry_->AddObserver(this);
148 }
149
150 void AppResult::StopObservingExtensionRegistry() {
151   if (extension_registry_)
152     extension_registry_->RemoveObserver(this);
153   extension_registry_ = NULL;
154 }
155
156 bool AppResult::RunExtensionEnableFlow() {
157   if (extensions::util::IsAppLaunchableWithoutEnabling(app_id_, profile_))
158     return false;
159
160   if (!extension_enable_flow_) {
161     controller_->OnShowChildDialog();
162
163     extension_enable_flow_.reset(new ExtensionEnableFlow(
164         profile_, app_id_, this));
165     extension_enable_flow_->StartForNativeWindow(
166         controller_->GetAppListWindow());
167   }
168   return true;
169 }
170
171 void AppResult::UpdateIcon() {
172   gfx::ImageSkia icon = icon_->image_skia();
173
174   if (!extensions::util::IsAppLaunchable(app_id_, profile_)) {
175     const color_utils::HSL shift = {-1, 0, 0.6};
176     icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
177   }
178
179   SetIcon(icon);
180 }
181
182 void AppResult::OnExtensionIconImageChanged(extensions::IconImage* image) {
183   DCHECK_EQ(icon_.get(), image);
184   UpdateIcon();
185 }
186
187 void AppResult::ExecuteLaunchCommand(int event_flags) {
188   Open(event_flags);
189 }
190
191 void AppResult::ExtensionEnableFlowFinished() {
192   extension_enable_flow_.reset();
193   controller_->OnCloseChildDialog();
194
195   // Automatically open app after enabling.
196   Open(ui::EF_NONE);
197 }
198
199 void AppResult::ExtensionEnableFlowAborted(bool user_initiated) {
200   extension_enable_flow_.reset();
201   controller_->OnCloseChildDialog();
202 }
203
204 void AppResult::OnExtensionLoaded(content::BrowserContext* browser_context,
205                                   const extensions::Extension* extension) {
206   UpdateIcon();
207 }
208
209 void AppResult::OnExtensionUninstalled(content::BrowserContext* browser_context,
210                                        const extensions::Extension* extension,
211                                        extensions::UninstallReason reason) {
212   if (extension->id() != app_id_)
213     return;
214
215   NotifyItemUninstalled();
216 }
217
218 void AppResult::OnShutdown(extensions::ExtensionRegistry* registry) {
219   DCHECK_EQ(extension_registry_, registry);
220   StopObservingExtensionRegistry();
221 }
222
223 }  // namespace app_list