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