Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / app_list / search / app_search_provider.cc
blob5009b3aaad9aaff9d2cb7af5a3bf7561dde5f12c
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_search_provider.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/clock.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/extension_ui_util.h"
15 #include "chrome/browser/extensions/extension_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
18 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
19 #include "chrome/browser/ui/app_list/search/app_result.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "ui/app_list/app_list_item.h"
26 #include "ui/app_list/app_list_model.h"
27 #include "ui/app_list/search/tokenized_string.h"
28 #include "ui/app_list/search/tokenized_string_match.h"
30 using extensions::ExtensionRegistry;
32 namespace {
34 // The size of each step unlaunched apps should increase their relevance by.
35 const double kUnlaunchedAppRelevanceStepSize = 0.0001;
38 namespace app_list {
40 class AppSearchProvider::App {
41 public:
42 explicit App(const extensions::Extension* extension,
43 const base::Time& last_launch_time)
44 : app_id_(extension->id()),
45 indexed_name_(base::UTF8ToUTF16(extension->short_name())),
46 last_launch_time_(last_launch_time) {}
47 ~App() {}
49 const std::string& app_id() const { return app_id_; }
50 const TokenizedString& indexed_name() const { return indexed_name_; }
51 const base::Time& last_launch_time() const { return last_launch_time_; }
53 private:
54 const std::string app_id_;
55 TokenizedString indexed_name_;
56 base::Time last_launch_time_;
58 DISALLOW_COPY_AND_ASSIGN(App);
61 AppSearchProvider::AppSearchProvider(Profile* profile,
62 AppListControllerDelegate* list_controller,
63 scoped_ptr<base::Clock> clock,
64 AppListItemList* top_level_item_list)
65 : profile_(profile),
66 list_controller_(list_controller),
67 extension_registry_observer_(this),
68 top_level_item_list_(top_level_item_list),
69 clock_(clock.Pass()),
70 update_results_factory_(this) {
71 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
72 RefreshApps();
75 AppSearchProvider::~AppSearchProvider() {}
77 void AppSearchProvider::Start(bool /*is_voice_query*/,
78 const base::string16& query) {
79 query_ = query;
80 const TokenizedString query_terms(query);
82 ClearResults();
84 bool show_recommendations = query.empty();
85 // Refresh list of apps to ensure we have the latest launch time information.
86 // This will also cause the results to update.
87 if (show_recommendations)
88 RefreshApps();
90 UpdateResults();
93 void AppSearchProvider::Stop() {
96 void AppSearchProvider::UpdateResults() {
97 const TokenizedString query_terms(query_);
98 bool show_recommendations = query_.empty();
99 ClearResults();
101 if (show_recommendations) {
102 // Build a map of app ids to their position in the app list.
103 std::map<std::string, size_t> id_to_app_list_index;
104 for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) {
105 id_to_app_list_index[top_level_item_list_->item_at(i)->id()] = i;
108 for (const App* app : apps_) {
109 scoped_ptr<AppResult> result(
110 new AppResult(profile_, app->app_id(), list_controller_, true));
111 result->set_title(app->indexed_name().text());
113 // Use the app list order to tiebreak apps that have never been launched.
114 if (app->last_launch_time().is_null()) {
115 auto it = id_to_app_list_index.find(app->app_id());
116 // If it's in a folder, it won't be in |id_to_app_list_index|. Rank
117 // those as if they are at the end of the list.
118 size_t app_list_index =
119 it == id_to_app_list_index.end() ? apps_.size() : (*it).second;
120 if (app_list_index > apps_.size())
121 app_list_index = apps_.size();
123 result->set_relevance(kUnlaunchedAppRelevanceStepSize *
124 (apps_.size() - app_list_index));
125 } else {
126 result->UpdateFromLastLaunched(clock_->Now(), app->last_launch_time());
128 Add(result.Pass());
130 } else {
131 for (const App* app : apps_) {
132 scoped_ptr<AppResult> result(
133 new AppResult(profile_, app->app_id(), list_controller_, false));
134 TokenizedStringMatch match;
135 if (!match.Calculate(query_terms, app->indexed_name()))
136 continue;
138 result->UpdateFromMatch(app->indexed_name(), match);
139 Add(result.Pass());
143 update_results_factory_.InvalidateWeakPtrs();
146 void AppSearchProvider::AddApps(const extensions::ExtensionSet& extensions) {
147 extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
148 for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
149 iter != extensions.end(); ++iter) {
150 const extensions::Extension* app = iter->get();
152 if (!extensions::ui_util::ShouldDisplayInAppLauncher(app, profile_))
153 continue;
155 if (profile_->IsOffTheRecord() &&
156 !extensions::util::CanLoadInIncognito(app, profile_))
157 continue;
159 apps_.push_back(new App(app, prefs->GetLastLaunchTime(app->id())));
163 void AppSearchProvider::RefreshApps() {
164 apps_.clear();
165 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
166 AddApps(registry->enabled_extensions());
167 AddApps(registry->disabled_extensions());
168 AddApps(registry->terminated_extensions());
171 void AppSearchProvider::OnExtensionLoaded(
172 content::BrowserContext* browser_context,
173 const extensions::Extension* extension) {
174 RefreshApps();
175 if (!update_results_factory_.HasWeakPtrs()) {
176 base::MessageLoop::current()->PostTask(
177 FROM_HERE,
178 base::Bind(&AppSearchProvider::UpdateResults,
179 update_results_factory_.GetWeakPtr()));
183 void AppSearchProvider::OnExtensionUninstalled(
184 content::BrowserContext* browser_context,
185 const extensions::Extension* extension,
186 extensions::UninstallReason reason) {
187 RefreshApps();
188 if (!update_results_factory_.HasWeakPtrs()) {
189 base::MessageLoop::current()->PostTask(
190 FROM_HERE,
191 base::Bind(&AppSearchProvider::UpdateResults,
192 update_results_factory_.GetWeakPtr()));
196 } // namespace app_list