app_result.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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 "chrome/browser/extensions/extension_service.h"
8#include "chrome/browser/extensions/extension_util.h"
9#include "chrome/browser/extensions/install_tracker.h"
10#include "chrome/browser/extensions/install_tracker_factory.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/ui/app_list/app_context_menu.h"
13#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
14#include "chrome/browser/ui/app_list/search/tokenized_string.h"
15#include "chrome/browser/ui/app_list/search/tokenized_string_match.h"
16#include "chrome/browser/ui/extensions/extension_enable_flow.h"
17#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
18#include "content/public/browser/user_metrics.h"
19#include "extensions/browser/extension_system.h"
20#include "extensions/browser/extension_system_provider.h"
21#include "extensions/browser/extensions_browser_client.h"
22#include "extensions/common/extension.h"
23#include "extensions/common/extension_icon_set.h"
24#include "extensions/common/manifest_handlers/icons_handler.h"
25#include "ui/gfx/color_utils.h"
26#include "ui/gfx/image/image_skia_operations.h"
27
28namespace app_list {
29
30AppResult::AppResult(Profile* profile,
31                     const std::string& app_id,
32                     AppListControllerDelegate* controller)
33    : profile_(profile),
34      app_id_(app_id),
35      controller_(controller),
36      install_tracker_(NULL) {
37  set_id(extensions::Extension::GetBaseURLFromExtensionId(app_id_).spec());
38
39  const extensions::Extension* extension =
40      extensions::ExtensionSystem::Get(profile_)->extension_service()
41          ->GetInstalledExtension(app_id_);
42  DCHECK(extension);
43
44  is_platform_app_ = extension->is_platform_app();
45
46  icon_.reset(new extensions::IconImage(
47      profile_,
48      extension,
49      extensions::IconsInfo::GetIcons(extension),
50      extension_misc::EXTENSION_ICON_SMALL,
51      extensions::IconsInfo::GetDefaultAppIcon(),
52      this));
53  UpdateIcon();
54  StartObservingInstall();
55}
56
57AppResult::~AppResult() {
58  StopObservingInstall();
59}
60
61void AppResult::UpdateFromMatch(const TokenizedString& title,
62                                const TokenizedStringMatch& match) {
63  const TokenizedStringMatch::Hits& hits = match.hits();
64
65  Tags tags;
66  tags.reserve(hits.size());
67  for (size_t i = 0; i < hits.size(); ++i)
68    tags.push_back(Tag(Tag::MATCH, hits[i].start(), hits[i].end()));
69
70  set_title(title.text());
71  set_title_tags(tags);
72  set_relevance(match.relevance());
73}
74
75void AppResult::Open(int event_flags) {
76  const extensions::Extension* extension =
77      extensions::ExtensionSystem::Get(profile_)->extension_service()
78          ->GetInstalledExtension(app_id_);
79  if (!extension)
80    return;
81
82  // Check if enable flow is already running or should be started
83  if (RunExtensionEnableFlow())
84    return;
85
86  CoreAppLauncherHandler::RecordAppListSearchLaunch(extension);
87  content::RecordAction(
88      base::UserMetricsAction("AppList_ClickOnAppFromSearch"));
89
90  controller_->ActivateApp(
91      profile_,
92      extension,
93      AppListControllerDelegate::LAUNCH_FROM_APP_LIST_SEARCH,
94      event_flags);
95}
96
97void AppResult::InvokeAction(int action_index, int event_flags) {}
98
99scoped_ptr<ChromeSearchResult> AppResult::Duplicate() {
100  scoped_ptr<ChromeSearchResult> copy(
101      new AppResult(profile_, app_id_, controller_));
102  copy->set_title(title());
103  copy->set_title_tags(title_tags());
104
105  return copy.Pass();
106}
107
108ChromeSearchResultType AppResult::GetType() {
109  return APP_SEARCH_RESULT;
110}
111
112ui::MenuModel* AppResult::GetContextMenuModel() {
113  if (!context_menu_) {
114    context_menu_.reset(new AppContextMenu(
115        this, profile_, app_id_, controller_));
116    context_menu_->set_is_platform_app(is_platform_app_);
117    context_menu_->set_is_search_result(true);
118  }
119
120  return context_menu_->GetMenuModel();
121}
122
123void AppResult::StartObservingInstall() {
124  DCHECK(!install_tracker_);
125
126  install_tracker_ = extensions::InstallTrackerFactory::GetForProfile(profile_);
127  install_tracker_->AddObserver(this);
128}
129
130void AppResult::StopObservingInstall() {
131  if (install_tracker_)
132    install_tracker_->RemoveObserver(this);
133
134  install_tracker_ = NULL;
135}
136
137bool AppResult::RunExtensionEnableFlow() {
138  if (extensions::util::IsAppLaunchableWithoutEnabling(app_id_, profile_))
139    return false;
140
141  if (!extension_enable_flow_) {
142    controller_->OnShowExtensionPrompt();
143
144    extension_enable_flow_.reset(new ExtensionEnableFlow(
145        profile_, app_id_, this));
146    extension_enable_flow_->StartForNativeWindow(
147        controller_->GetAppListWindow());
148  }
149  return true;
150}
151
152void AppResult::UpdateIcon() {
153  gfx::ImageSkia icon = icon_->image_skia();
154
155  if (!extensions::util::IsAppLaunchable(app_id_, profile_)) {
156    const color_utils::HSL shift = {-1, 0, 0.6};
157    icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
158  }
159
160  SetIcon(icon);
161}
162
163void AppResult::OnExtensionIconImageChanged(extensions::IconImage* image) {
164  DCHECK_EQ(icon_.get(), image);
165  UpdateIcon();
166}
167
168void AppResult::ExecuteLaunchCommand(int event_flags) {
169  Open(event_flags);
170}
171
172void AppResult::ExtensionEnableFlowFinished() {
173  extension_enable_flow_.reset();
174  controller_->OnCloseExtensionPrompt();
175
176  // Automatically open app after enabling.
177  Open(ui::EF_NONE);
178}
179
180void AppResult::ExtensionEnableFlowAborted(bool user_initiated) {
181  extension_enable_flow_.reset();
182  controller_->OnCloseExtensionPrompt();
183}
184
185void AppResult::OnExtensionLoaded(const extensions::Extension* extension) {
186  UpdateIcon();
187}
188
189void AppResult::OnExtensionUninstalled(const extensions::Extension* extension) {
190  if (extension->id() != app_id_)
191    return;
192
193  NotifyItemUninstalled();
194}
195
196void AppResult::OnShutdown() { StopObservingInstall(); }
197
198}  // namespace app_list
199