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.
5 #include "chrome/browser/ui/app_list/search/app_result.h"
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"
32 AppResult::AppResult(Profile* profile,
33 const std::string& app_id,
34 AppListControllerDelegate* controller)
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);
43 const extensions::Extension* extension =
44 extensions::ExtensionSystem::Get(profile_)->extension_service()
45 ->GetInstalledExtension(app_id_);
48 is_platform_app_ = extension->is_platform_app();
51 new extensions::IconImage(profile_,
53 extensions::IconsInfo::GetIcons(extension),
54 GetPreferredIconDimension(),
55 extensions::util::GetDefaultAppIcon(),
59 StartObservingExtensionRegistry();
62 AppResult::~AppResult() {
63 StopObservingExtensionRegistry();
66 void AppResult::UpdateFromMatch(const TokenizedString& title,
67 const TokenizedStringMatch& match) {
68 const TokenizedStringMatch::Hits& hits = match.hits();
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()));
75 set_title(title.text());
77 set_relevance(match.relevance());
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;
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));
91 void AppResult::Open(int event_flags) {
92 const extensions::Extension* extension =
93 extensions::ExtensionSystem::Get(profile_)->extension_service()
94 ->GetInstalledExtension(app_id_);
98 // Don't auto-enable apps that cannot be launched.
99 if (!extensions::util::IsAppLaunchable(app_id_, profile_))
102 // Check if enable flow is already running or should be started
103 if (RunExtensionEnableFlow())
106 CoreAppLauncherHandler::RecordAppListSearchLaunch(extension);
107 content::RecordAction(
108 base::UserMetricsAction("AppList_ClickOnAppFromSearch"));
110 controller_->ActivateApp(
113 AppListControllerDelegate::LAUNCH_FROM_APP_LIST_SEARCH,
117 void AppResult::InvokeAction(int action_index, int event_flags) {}
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());
128 ChromeSearchResultType AppResult::GetType() {
129 return APP_SEARCH_RESULT;
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);
140 return context_menu_->GetMenuModel();
143 void AppResult::StartObservingExtensionRegistry() {
144 DCHECK(!extension_registry_);
146 extension_registry_ = extensions::ExtensionRegistry::Get(profile_);
147 extension_registry_->AddObserver(this);
150 void AppResult::StopObservingExtensionRegistry() {
151 if (extension_registry_)
152 extension_registry_->RemoveObserver(this);
153 extension_registry_ = NULL;
156 bool AppResult::RunExtensionEnableFlow() {
157 if (extensions::util::IsAppLaunchableWithoutEnabling(app_id_, profile_))
160 if (!extension_enable_flow_) {
161 controller_->OnShowChildDialog();
163 extension_enable_flow_.reset(new ExtensionEnableFlow(
164 profile_, app_id_, this));
165 extension_enable_flow_->StartForNativeWindow(
166 controller_->GetAppListWindow());
171 void AppResult::UpdateIcon() {
172 gfx::ImageSkia icon = icon_->image_skia();
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);
182 void AppResult::OnExtensionIconImageChanged(extensions::IconImage* image) {
183 DCHECK_EQ(icon_.get(), image);
187 void AppResult::ExecuteLaunchCommand(int event_flags) {
191 void AppResult::ExtensionEnableFlowFinished() {
192 extension_enable_flow_.reset();
193 controller_->OnCloseChildDialog();
195 // Automatically open app after enabling.
199 void AppResult::ExtensionEnableFlowAborted(bool user_initiated) {
200 extension_enable_flow_.reset();
201 controller_->OnCloseChildDialog();
204 void AppResult::OnExtensionLoaded(content::BrowserContext* browser_context,
205 const extensions::Extension* extension) {
209 void AppResult::OnExtensionUninstalled(content::BrowserContext* browser_context,
210 const extensions::Extension* extension,
211 extensions::UninstallReason reason) {
212 if (extension->id() != app_id_)
215 NotifyItemUninstalled();
218 void AppResult::OnShutdown(extensions::ExtensionRegistry* registry) {
219 DCHECK_EQ(extension_registry_, registry);
220 StopObservingExtensionRegistry();
223 } // namespace app_list