blob: 97acf8a512f13d33c44b7691481ef8f42319b26a [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/app_list/app_list_service_impl.h"
#include <string>
#include "apps/pref_names.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "chrome/browser/apps/shortcut_manager.h"
#include "chrome/browser/apps/shortcut_manager_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/app_list/keep_alive_service.h"
#include "chrome/browser/ui/app_list/keep_alive_service_impl.h"
#include "chrome/browser/ui/app_list/profile_loader.h"
#include "chrome/browser/ui/app_list/profile_store.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
namespace {
void SendAppListAppLaunch(int count) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Apps.AppListDailyAppLaunches", count, 1, 1000, 50);
if (count > 0)
UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppToday", 1, 2);
}
void SendAppListLaunch(int count) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Apps.AppListDailyLaunches", count, 1, 1000, 50);
if (count > 0)
UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppListToday", 1, 2);
}
bool SendDailyEventFrequency(
const char* last_ping_pref,
const char* count_pref,
void (*send_callback)(int count)) {
PrefService* local_state = g_browser_process->local_state();
base::Time now = base::Time::Now();
base::Time last = base::Time::FromInternalValue(local_state->GetInt64(
last_ping_pref));
int days = (now - last).InDays();
if (days > 0) {
send_callback(local_state->GetInteger(count_pref));
local_state->SetInt64(
last_ping_pref,
(last + base::TimeDelta::FromDays(days)).ToInternalValue());
local_state->SetInteger(count_pref, 0);
return true;
}
return false;
}
void RecordDailyEventFrequency(
const char* last_ping_pref,
const char* count_pref,
void (*send_callback)(int count)) {
PrefService* local_state = g_browser_process->local_state();
int count = local_state->GetInteger(count_pref);
local_state->SetInteger(count_pref, count + 1);
if (SendDailyEventFrequency(last_ping_pref, count_pref, send_callback)) {
local_state->SetInteger(count_pref, 1);
}
}
class ProfileStoreImpl : public ProfileStore {
public:
explicit ProfileStoreImpl(ProfileManager* profile_manager)
: profile_manager_(profile_manager),
weak_factory_(this) {
}
virtual void AddProfileObserver(ProfileInfoCacheObserver* observer) OVERRIDE {
profile_manager_->GetProfileInfoCache().AddObserver(observer);
}
virtual void LoadProfileAsync(
const base::FilePath& path,
base::Callback<void(Profile*)> callback) OVERRIDE {
profile_manager_->CreateProfileAsync(
path,
base::Bind(&ProfileStoreImpl::OnProfileCreated,
weak_factory_.GetWeakPtr(),
callback),
base::string16(),
base::string16(),
std::string());
}
void OnProfileCreated(base::Callback<void(Profile*)> callback,
Profile* profile,
Profile::CreateStatus status) {
switch (status) {
case Profile::CREATE_STATUS_CREATED:
break;
case Profile::CREATE_STATUS_INITIALIZED:
callback.Run(profile);
break;
case Profile::CREATE_STATUS_LOCAL_FAIL:
case Profile::CREATE_STATUS_REMOTE_FAIL:
case Profile::CREATE_STATUS_CANCELED:
break;
case Profile::MAX_CREATE_STATUS:
NOTREACHED();
break;
}
}
virtual Profile* GetProfileByPath(const base::FilePath& path) OVERRIDE {
return profile_manager_->GetProfileByPath(path);
}
virtual base::FilePath GetUserDataDir() OVERRIDE {
return profile_manager_->user_data_dir();
}
virtual bool IsProfileManaged(const base::FilePath& profile_path) OVERRIDE {
ProfileInfoCache& profile_info =
g_browser_process->profile_manager()->GetProfileInfoCache();
size_t profile_index = profile_info.GetIndexOfProfileWithPath(profile_path);
return profile_info.ProfileIsManagedAtIndex(profile_index);
}
private:
ProfileManager* profile_manager_;
base::WeakPtrFactory<ProfileStoreImpl> weak_factory_;
};
} // namespace
// static
void AppListServiceImpl::RecordAppListLaunch() {
RecordDailyEventFrequency(prefs::kLastAppListLaunchPing,
prefs::kAppListLaunchCount,
&SendAppListLaunch);
}
// static
void AppListServiceImpl::RecordAppListAppLaunch() {
RecordDailyEventFrequency(prefs::kLastAppListAppLaunchPing,
prefs::kAppListAppLaunchCount,
&SendAppListAppLaunch);
}
// static
void AppListServiceImpl::SendAppListStats() {
if (!g_browser_process || g_browser_process->IsShuttingDown())
return;
SendDailyEventFrequency(prefs::kLastAppListLaunchPing,
prefs::kAppListLaunchCount,
&SendAppListLaunch);
SendDailyEventFrequency(prefs::kLastAppListAppLaunchPing,
prefs::kAppListAppLaunchCount,
&SendAppListAppLaunch);
}
AppListServiceImpl::AppListServiceImpl()
: profile_store_(new ProfileStoreImpl(
g_browser_process->profile_manager())),
weak_factory_(this),
command_line_(*CommandLine::ForCurrentProcess()),
local_state_(g_browser_process->local_state()),
profile_loader_(new ProfileLoader(
profile_store_.get(),
scoped_ptr<KeepAliveService>(new KeepAliveServiceImpl))) {
profile_store_->AddProfileObserver(this);
}
AppListServiceImpl::AppListServiceImpl(
const CommandLine& command_line,
PrefService* local_state,
scoped_ptr<ProfileStore> profile_store,
scoped_ptr<KeepAliveService> keep_alive_service)
: profile_store_(profile_store.Pass()),
weak_factory_(this),
command_line_(command_line),
local_state_(local_state),
profile_loader_(new ProfileLoader(
profile_store_.get(), keep_alive_service.Pass())) {
profile_store_->AddProfileObserver(this);
}
AppListServiceImpl::~AppListServiceImpl() {}
void AppListServiceImpl::SetAppListNextPaintCallback(void (*callback)()) {}
void AppListServiceImpl::HandleFirstRun() {}
void AppListServiceImpl::Init(Profile* initial_profile) {}
base::FilePath AppListServiceImpl::GetProfilePath(
const base::FilePath& user_data_dir) {
std::string app_list_profile;
if (local_state_->HasPrefPath(prefs::kAppListProfile))
app_list_profile = local_state_->GetString(prefs::kAppListProfile);
// If the user has no profile preference for the app launcher, default to the
// last browser profile used.
if (app_list_profile.empty() &&
local_state_->HasPrefPath(prefs::kProfileLastUsed)) {
app_list_profile = local_state_->GetString(prefs::kProfileLastUsed);
}
// If there is no last used profile recorded, use the initial profile.
if (app_list_profile.empty())
app_list_profile = chrome::kInitialProfile;
return user_data_dir.AppendASCII(app_list_profile);
}
void AppListServiceImpl::SetProfilePath(const base::FilePath& profile_path) {
// Ensure we don't set the pref to a managed user's profile path.
// TODO(calamity): Filter out managed profiles from the settings app so this
// can't get hit, so we can remove it.
if (profile_store_->IsProfileManaged(profile_path))
return;
local_state_->SetString(
prefs::kAppListProfile,
profile_path.BaseName().MaybeAsASCII());
}
void AppListServiceImpl::CreateShortcut() {}
// We need to watch for profile removal to keep kAppListProfile updated.
void AppListServiceImpl::OnProfileWillBeRemoved(
const base::FilePath& profile_path) {
// If the profile the app list uses just got deleted, reset it to the last
// used profile.
std::string app_list_last_profile = local_state_->GetString(
prefs::kAppListProfile);
if (profile_path.BaseName().MaybeAsASCII() == app_list_last_profile) {
local_state_->SetString(prefs::kAppListProfile,
local_state_->GetString(prefs::kProfileLastUsed));
}
}
void AppListServiceImpl::Show() {
profile_loader_->LoadProfileInvalidatingOtherLoads(
GetProfilePath(profile_store_->GetUserDataDir()),
base::Bind(&AppListServiceImpl::ShowForProfile,
weak_factory_.GetWeakPtr()));
}
void AppListServiceImpl::EnableAppList(Profile* initial_profile) {
SetProfilePath(initial_profile->GetPath());
if (local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled))
return;
local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, true);
CreateShortcut();
AppShortcutManager* shortcut_manager =
AppShortcutManagerFactory::GetForProfile(initial_profile);
if (shortcut_manager)
shortcut_manager->OnceOffCreateShortcuts();
}
void AppListServiceImpl::InvalidatePendingProfileLoads() {
profile_loader_->InvalidatePendingProfileLoads();
}
void AppListServiceImpl::HandleCommandLineFlags(Profile* initial_profile) {
if (command_line_.HasSwitch(switches::kEnableAppList))
EnableAppList(initial_profile);
if (command_line_.HasSwitch(switches::kResetAppListInstallState))
local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false);
}
void AppListServiceImpl::SendUsageStats() {
// Send app list usage stats after a delay.
const int kSendUsageStatsDelay = 5;
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&AppListServiceImpl::SendAppListStats),
base::TimeDelta::FromSeconds(kSendUsageStatsDelay));
}