14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file. 44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/recommended_apps.h" 64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <algorithm> 84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <vector> 94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/bind.h" 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_ui_util.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/recommended_apps_observer.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/pref_names.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_registry.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h" 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h" 204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace app_list { 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace { 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)struct AppSortInfo { 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) AppSortInfo() : app(NULL) {} 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) AppSortInfo(const extensions::Extension* app, 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const base::Time& last_launch_time) 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : app(app), last_launch_time(last_launch_time) {} 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const extensions::Extension* app; 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Time last_launch_time; 334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool AppLaunchedMoreRecent(const AppSortInfo& app1, const AppSortInfo& app2) { 364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return app1.last_launch_time > app2.last_launch_time; 374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace 404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)RecommendedApps::RecommendedApps(Profile* profile) 4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) : profile_(profile), extension_registry_observer_(this) { 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_); 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pref_change_registrar_.Init(prefs->pref_service()); 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pref_change_registrar_.Add(extensions::pref_names::kExtensions, 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&RecommendedApps::Update, 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Unretained(this))); 4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(profile)); 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Update(); 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)RecommendedApps::~RecommendedApps() { 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void RecommendedApps::AddObserver(RecommendedAppsObserver* observer) { 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) observers_.AddObserver(observer); 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void RecommendedApps::RemoveObserver(RecommendedAppsObserver* observer) { 604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) observers_.RemoveObserver(observer); 614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void RecommendedApps::Update() { 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_); 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::vector<AppSortInfo> sorted_apps; 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const extensions::ExtensionSet& extensions = 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) extensions::ExtensionRegistry::Get(profile_)->enabled_extensions(); 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (extensions::ExtensionSet::const_iterator app = extensions.begin(); 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) app != extensions.end(); 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++app) { 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!extensions::ui_util::ShouldDisplayInAppLauncher(app->get(), profile_)) 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) continue; 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) sorted_apps.push_back( 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) AppSortInfo(app->get(), prefs->GetLastLaunchTime((*app)->id()))); 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::sort(sorted_apps.begin(), sorted_apps.end(), &AppLaunchedMoreRecent); 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const size_t kMaxRecommendedApps = 4; 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) sorted_apps.resize(std::min(kMaxRecommendedApps, sorted_apps.size())); 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Apps new_recommends; 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (size_t i = 0; i < sorted_apps.size(); ++i) 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) new_recommends.push_back(sorted_apps[i].app); 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const bool changed = apps_.size() != new_recommends.size() || 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) !std::equal(apps_.begin(), apps_.end(), new_recommends.begin()); 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (changed) { 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) apps_.swap(new_recommends); 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FOR_EACH_OBSERVER( 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) RecommendedAppsObserver, observers_, OnRecommendedAppsChanged()); 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void RecommendedApps::OnExtensionWillBeInstalled( 9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserContext* browser_context, 9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const extensions::Extension* extension, 10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) bool is_update, 10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) bool from_ephemeral, 10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const std::string& old_name) { 1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Update(); 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void RecommendedApps::OnExtensionLoaded( 10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserContext* browser_context, 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const extensions::Extension* extension) { 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Update(); 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void RecommendedApps::OnExtensionUnloaded( 11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserContext* browser_context, 11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const extensions::Extension* extension, 11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) extensions::UnloadedExtensionInfo::Reason reason) { 1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Update(); 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void RecommendedApps::OnExtensionUninstalled( 12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserContext* browser_context, 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const extensions::Extension* extension, 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::UninstallReason reason) { 1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Update(); 1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // namespace app_list 127