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/recommended_apps.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/bind.h"
11#include "chrome/browser/extensions/extension_ui_util.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/app_list/recommended_apps_observer.h"
14#include "chrome/common/pref_names.h"
15#include "extensions/browser/extension_prefs.h"
16#include "extensions/browser/extension_registry.h"
17#include "extensions/browser/pref_names.h"
18#include "extensions/common/extension.h"
19#include "extensions/common/extension_set.h"
20
21namespace app_list {
22
23namespace {
24
25struct AppSortInfo {
26  AppSortInfo() : app(NULL) {}
27  AppSortInfo(const extensions::Extension* app,
28              const base::Time& last_launch_time)
29      : app(app), last_launch_time(last_launch_time) {}
30
31  const extensions::Extension* app;
32  base::Time last_launch_time;
33};
34
35bool AppLaunchedMoreRecent(const AppSortInfo& app1, const AppSortInfo& app2) {
36  return app1.last_launch_time > app2.last_launch_time;
37}
38
39}  // namespace
40
41RecommendedApps::RecommendedApps(Profile* profile)
42    : profile_(profile), extension_registry_observer_(this) {
43  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
44  pref_change_registrar_.Init(prefs->pref_service());
45  pref_change_registrar_.Add(extensions::pref_names::kExtensions,
46                             base::Bind(&RecommendedApps::Update,
47                                        base::Unretained(this)));
48  extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(profile));
49  Update();
50}
51
52RecommendedApps::~RecommendedApps() {
53}
54
55void RecommendedApps::AddObserver(RecommendedAppsObserver* observer) {
56  observers_.AddObserver(observer);
57}
58
59void RecommendedApps::RemoveObserver(RecommendedAppsObserver* observer) {
60  observers_.RemoveObserver(observer);
61}
62
63void RecommendedApps::Update() {
64  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
65
66  std::vector<AppSortInfo> sorted_apps;
67  const extensions::ExtensionSet& extensions =
68      extensions::ExtensionRegistry::Get(profile_)->enabled_extensions();
69  for (extensions::ExtensionSet::const_iterator app = extensions.begin();
70       app != extensions.end();
71       ++app) {
72    if (!extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile_))
73      continue;
74
75    sorted_apps.push_back(
76        AppSortInfo(app->get(), prefs->GetLastLaunchTime((*app)->id())));
77  }
78
79  std::sort(sorted_apps.begin(), sorted_apps.end(), &AppLaunchedMoreRecent);
80
81  const size_t kMaxRecommendedApps = 4;
82  sorted_apps.resize(std::min(kMaxRecommendedApps, sorted_apps.size()));
83
84  Apps new_recommends;
85  for (size_t i = 0; i < sorted_apps.size(); ++i)
86    new_recommends.push_back(sorted_apps[i].app);
87
88  const bool changed = apps_.size() != new_recommends.size() ||
89      !std::equal(apps_.begin(), apps_.end(), new_recommends.begin());
90  if (changed) {
91    apps_.swap(new_recommends);
92    FOR_EACH_OBSERVER(
93        RecommendedAppsObserver, observers_, OnRecommendedAppsChanged());
94  }
95}
96
97void RecommendedApps::OnExtensionWillBeInstalled(
98    content::BrowserContext* browser_context,
99    const extensions::Extension* extension,
100    bool is_update,
101    bool from_ephemeral,
102    const std::string& old_name) {
103  Update();
104}
105
106void RecommendedApps::OnExtensionLoaded(
107    content::BrowserContext* browser_context,
108    const extensions::Extension* extension) {
109  Update();
110}
111
112void RecommendedApps::OnExtensionUnloaded(
113    content::BrowserContext* browser_context,
114    const extensions::Extension* extension,
115    extensions::UnloadedExtensionInfo::Reason reason) {
116  Update();
117}
118
119void RecommendedApps::OnExtensionUninstalled(
120    content::BrowserContext* browser_context,
121    const extensions::Extension* extension,
122    extensions::UninstallReason reason) {
123  Update();
124}
125
126}  // namespace app_list
127