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