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_search_provider.h"
6
7#include <string>
8
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/extensions/extension_service.h"
11#include "chrome/browser/extensions/extension_ui_util.h"
12#include "chrome/browser/extensions/extension_util.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/ui/app_list/search/app_result.h"
15#include "extensions/browser/extension_prefs.h"
16#include "extensions/browser/extension_registry.h"
17#include "extensions/browser/extension_system.h"
18#include "extensions/common/extension.h"
19#include "extensions/common/extension_set.h"
20#include "ui/app_list/search/tokenized_string.h"
21#include "ui/app_list/search/tokenized_string_match.h"
22
23using extensions::ExtensionRegistry;
24
25namespace app_list {
26
27class AppSearchProvider::App {
28 public:
29  explicit App(const extensions::Extension* extension,
30               const base::Time& last_launch_time)
31      : app_id_(extension->id()),
32        indexed_name_(base::UTF8ToUTF16(extension->name())),
33        last_launch_time_(last_launch_time) {}
34  ~App() {}
35
36  const std::string& app_id() const { return app_id_; }
37  const TokenizedString& indexed_name() const { return indexed_name_; }
38  const base::Time& last_launch_time() const { return last_launch_time_; }
39
40 private:
41  const std::string app_id_;
42  TokenizedString indexed_name_;
43  base::Time last_launch_time_;
44
45  DISALLOW_COPY_AND_ASSIGN(App);
46};
47
48AppSearchProvider::AppSearchProvider(Profile* profile,
49                                     AppListControllerDelegate* list_controller)
50    : profile_(profile),
51      list_controller_(list_controller),
52      extension_registry_observer_(this) {
53  extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
54  RefreshApps();
55}
56
57AppSearchProvider::~AppSearchProvider() {}
58
59void AppSearchProvider::Start(const base::string16& query) {
60  StartImpl(base::Time::Now(), query);
61}
62
63void AppSearchProvider::Stop() {
64}
65
66void AppSearchProvider::StartImpl(const base::Time& current_time,
67                                  const base::string16& query) {
68  const TokenizedString query_terms(query);
69
70  ClearResults();
71
72  bool show_recommendations = query.empty();
73  // Refresh list of apps to ensure we have the latest launch time information.
74  if (show_recommendations)
75    RefreshApps();
76
77  for (Apps::const_iterator app_it = apps_.begin();
78       app_it != apps_.end();
79       ++app_it) {
80    scoped_ptr<AppResult> result(
81        new AppResult(profile_, (*app_it)->app_id(), list_controller_));
82    if (show_recommendations) {
83      result->set_title((*app_it)->indexed_name().text());
84      result->UpdateFromLastLaunched(current_time,
85                                     (*app_it)->last_launch_time());
86    } else {
87      TokenizedStringMatch match;
88      if (!match.Calculate(query_terms, (*app_it)->indexed_name()))
89        continue;
90
91      result->UpdateFromMatch((*app_it)->indexed_name(), match);
92    }
93    Add(result.PassAs<SearchResult>());
94  }
95}
96
97void AppSearchProvider::AddApps(const extensions::ExtensionSet& extensions) {
98  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
99  for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
100       iter != extensions.end(); ++iter) {
101    const extensions::Extension* app = iter->get();
102
103    if (!extensions::ui_util::ShouldDisplayInAppLauncher(app, profile_))
104      continue;
105
106    if (profile_->IsOffTheRecord() &&
107        !extensions::util::CanLoadInIncognito(app, profile_))
108      continue;
109
110    apps_.push_back(new App(app, prefs->GetLastLaunchTime(app->id())));
111  }
112}
113
114void AppSearchProvider::RefreshApps() {
115  apps_.clear();
116  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
117  AddApps(registry->enabled_extensions());
118  AddApps(registry->disabled_extensions());
119  AddApps(registry->terminated_extensions());
120}
121
122void AppSearchProvider::OnExtensionLoaded(
123    content::BrowserContext* browser_context,
124    const extensions::Extension* extension) {
125  RefreshApps();
126}
127
128void AppSearchProvider::OnExtensionUninstalled(
129    content::BrowserContext* browser_context,
130    const extensions::Extension* extension,
131    extensions::UninstallReason reason) {
132  RefreshApps();
133}
134
135}  // namespace app_list
136