app_list_service_impl.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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/app_list_service_impl.h" 6 7#include <string> 8 9#include "apps/pref_names.h" 10#include "base/command_line.h" 11#include "base/metrics/histogram.h" 12#include "base/prefs/pref_service.h" 13#include "base/strings/string16.h" 14#include "base/time/time.h" 15#include "chrome/browser/browser_process.h" 16#include "chrome/browser/profiles/profile_manager.h" 17#include "chrome/browser/ui/app_list/keep_alive_service.h" 18#include "chrome/browser/ui/app_list/keep_alive_service_impl.h" 19#include "chrome/browser/ui/app_list/profile_loader.h" 20#include "chrome/browser/ui/app_list/profile_store.h" 21#include "chrome/common/chrome_constants.h" 22#include "chrome/common/chrome_switches.h" 23#include "chrome/common/pref_names.h" 24#include "content/public/browser/browser_thread.h" 25 26namespace { 27 28void SendAppListAppLaunch(int count) { 29 UMA_HISTOGRAM_CUSTOM_COUNTS( 30 "Apps.AppListDailyAppLaunches", count, 1, 1000, 50); 31 if (count > 0) 32 UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppToday", 1, 2); 33} 34 35void SendAppListLaunch(int count) { 36 UMA_HISTOGRAM_CUSTOM_COUNTS( 37 "Apps.AppListDailyLaunches", count, 1, 1000, 50); 38 if (count > 0) 39 UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppListToday", 1, 2); 40} 41 42bool SendDailyEventFrequency( 43 const char* last_ping_pref, 44 const char* count_pref, 45 void (*send_callback)(int count)) { 46 PrefService* local_state = g_browser_process->local_state(); 47 48 base::Time now = base::Time::Now(); 49 base::Time last = base::Time::FromInternalValue(local_state->GetInt64( 50 last_ping_pref)); 51 int days = (now - last).InDays(); 52 if (days > 0) { 53 send_callback(local_state->GetInteger(count_pref)); 54 local_state->SetInt64( 55 last_ping_pref, 56 (last + base::TimeDelta::FromDays(days)).ToInternalValue()); 57 local_state->SetInteger(count_pref, 0); 58 return true; 59 } 60 return false; 61} 62 63void RecordDailyEventFrequency( 64 const char* last_ping_pref, 65 const char* count_pref, 66 void (*send_callback)(int count)) { 67 PrefService* local_state = g_browser_process->local_state(); 68 69 int count = local_state->GetInteger(count_pref); 70 local_state->SetInteger(count_pref, count + 1); 71 if (SendDailyEventFrequency(last_ping_pref, count_pref, send_callback)) { 72 local_state->SetInteger(count_pref, 1); 73 } 74} 75 76class ProfileStoreImpl : public ProfileStore { 77 public: 78 explicit ProfileStoreImpl(ProfileManager* profile_manager) 79 : profile_manager_(profile_manager), 80 weak_factory_(this) { 81 } 82 83 virtual void AddProfileObserver(ProfileInfoCacheObserver* observer) OVERRIDE { 84 profile_manager_->GetProfileInfoCache().AddObserver(observer); 85 } 86 87 virtual void LoadProfileAsync( 88 const base::FilePath& path, 89 base::Callback<void(Profile*)> callback) OVERRIDE { 90 profile_manager_->CreateProfileAsync( 91 path, 92 base::Bind(&ProfileStoreImpl::OnProfileCreated, 93 weak_factory_.GetWeakPtr(), 94 callback), 95 base::string16(), 96 base::string16(), 97 std::string()); 98 } 99 100 void OnProfileCreated(base::Callback<void(Profile*)> callback, 101 Profile* profile, 102 Profile::CreateStatus status) { 103 switch (status) { 104 case Profile::CREATE_STATUS_CREATED: 105 break; 106 case Profile::CREATE_STATUS_INITIALIZED: 107 callback.Run(profile); 108 break; 109 case Profile::CREATE_STATUS_LOCAL_FAIL: 110 case Profile::CREATE_STATUS_REMOTE_FAIL: 111 case Profile::CREATE_STATUS_CANCELED: 112 break; 113 case Profile::MAX_CREATE_STATUS: 114 NOTREACHED(); 115 break; 116 } 117 } 118 119 virtual Profile* GetProfileByPath(const base::FilePath& path) OVERRIDE { 120 return profile_manager_->GetProfileByPath(path); 121 } 122 123 virtual base::FilePath GetUserDataDir() OVERRIDE { 124 return profile_manager_->user_data_dir(); 125 } 126 127 virtual bool IsProfileManaged(const base::FilePath& profile_path) OVERRIDE { 128 ProfileInfoCache& profile_info = 129 g_browser_process->profile_manager()->GetProfileInfoCache(); 130 size_t profile_index = profile_info.GetIndexOfProfileWithPath(profile_path); 131 return profile_info.ProfileIsManagedAtIndex(profile_index); 132 } 133 134 private: 135 ProfileManager* profile_manager_; 136 base::WeakPtrFactory<ProfileStoreImpl> weak_factory_; 137}; 138 139} // namespace 140 141// static 142void AppListServiceImpl::RecordAppListLaunch() { 143 RecordDailyEventFrequency(prefs::kLastAppListLaunchPing, 144 prefs::kAppListLaunchCount, 145 &SendAppListLaunch); 146} 147 148// static 149void AppListServiceImpl::RecordAppListAppLaunch() { 150 RecordDailyEventFrequency(prefs::kLastAppListAppLaunchPing, 151 prefs::kAppListAppLaunchCount, 152 &SendAppListAppLaunch); 153} 154 155// static 156void AppListServiceImpl::SendAppListStats() { 157 if (!g_browser_process || g_browser_process->IsShuttingDown()) 158 return; 159 160 SendDailyEventFrequency(prefs::kLastAppListLaunchPing, 161 prefs::kAppListLaunchCount, 162 &SendAppListLaunch); 163 SendDailyEventFrequency(prefs::kLastAppListAppLaunchPing, 164 prefs::kAppListAppLaunchCount, 165 &SendAppListAppLaunch); 166} 167 168AppListServiceImpl::AppListServiceImpl() 169 : profile_(NULL), 170 profile_store_(new ProfileStoreImpl( 171 g_browser_process->profile_manager())), 172 weak_factory_(this), 173 command_line_(*CommandLine::ForCurrentProcess()), 174 local_state_(g_browser_process->local_state()), 175 profile_loader_(new ProfileLoader( 176 profile_store_.get(), 177 scoped_ptr<KeepAliveService>(new KeepAliveServiceImpl))) { 178 profile_store_->AddProfileObserver(this); 179} 180 181AppListServiceImpl::AppListServiceImpl( 182 const CommandLine& command_line, 183 PrefService* local_state, 184 scoped_ptr<ProfileStore> profile_store, 185 scoped_ptr<KeepAliveService> keep_alive_service) 186 : profile_(NULL), 187 profile_store_(profile_store.Pass()), 188 weak_factory_(this), 189 command_line_(command_line), 190 local_state_(local_state), 191 profile_loader_(new ProfileLoader( 192 profile_store_.get(), keep_alive_service.Pass())) { 193 profile_store_->AddProfileObserver(this); 194} 195 196AppListServiceImpl::~AppListServiceImpl() {} 197 198void AppListServiceImpl::SetAppListNextPaintCallback( 199 const base::Closure& callback) {} 200 201void AppListServiceImpl::HandleFirstRun() {} 202 203void AppListServiceImpl::Init(Profile* initial_profile) {} 204 205base::FilePath AppListServiceImpl::GetProfilePath( 206 const base::FilePath& user_data_dir) { 207 std::string app_list_profile; 208 if (local_state_->HasPrefPath(prefs::kAppListProfile)) 209 app_list_profile = local_state_->GetString(prefs::kAppListProfile); 210 211 // If the user has no profile preference for the app launcher, default to the 212 // last browser profile used. 213 if (app_list_profile.empty() && 214 local_state_->HasPrefPath(prefs::kProfileLastUsed)) { 215 app_list_profile = local_state_->GetString(prefs::kProfileLastUsed); 216 } 217 218 // If there is no last used profile recorded, use the initial profile. 219 if (app_list_profile.empty()) 220 app_list_profile = chrome::kInitialProfile; 221 222 return user_data_dir.AppendASCII(app_list_profile); 223} 224 225void AppListServiceImpl::SetProfilePath(const base::FilePath& profile_path) { 226 // Ensure we don't set the pref to a managed user's profile path. 227 // TODO(calamity): Filter out managed profiles from the settings app so this 228 // can't get hit, so we can remove it. 229 if (profile_store_->IsProfileManaged(profile_path)) 230 return; 231 232 local_state_->SetString( 233 prefs::kAppListProfile, 234 profile_path.BaseName().MaybeAsASCII()); 235} 236 237void AppListServiceImpl::CreateShortcut() {} 238 239// We need to watch for profile removal to keep kAppListProfile updated. 240void AppListServiceImpl::OnProfileWillBeRemoved( 241 const base::FilePath& profile_path) { 242 // If the profile the app list uses just got deleted, reset it to the last 243 // used profile. 244 std::string app_list_last_profile = local_state_->GetString( 245 prefs::kAppListProfile); 246 if (profile_path.BaseName().MaybeAsASCII() == app_list_last_profile) { 247 local_state_->SetString(prefs::kAppListProfile, 248 local_state_->GetString(prefs::kProfileLastUsed)); 249 } 250} 251 252void AppListServiceImpl::Show() { 253 profile_loader_->LoadProfileInvalidatingOtherLoads( 254 GetProfilePath(profile_store_->GetUserDataDir()), 255 base::Bind(&AppListServiceImpl::ShowForProfile, 256 weak_factory_.GetWeakPtr())); 257} 258 259void AppListServiceImpl::EnableAppList(Profile* initial_profile) { 260 SetProfilePath(initial_profile->GetPath()); 261 if (local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled)) 262 return; 263 264 local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, true); 265 CreateShortcut(); 266} 267 268Profile* AppListServiceImpl::GetCurrentAppListProfile() { 269 return profile(); 270} 271 272void AppListServiceImpl::SetProfile(Profile* new_profile) { 273 profile_ = new_profile; 274} 275 276void AppListServiceImpl::InvalidatePendingProfileLoads() { 277 profile_loader_->InvalidatePendingProfileLoads(); 278} 279 280void AppListServiceImpl::HandleCommandLineFlags(Profile* initial_profile) { 281 if (command_line_.HasSwitch(switches::kEnableAppList)) 282 EnableAppList(initial_profile); 283 284 if (command_line_.HasSwitch(switches::kResetAppListInstallState)) 285 local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false); 286} 287 288void AppListServiceImpl::SendUsageStats() { 289 // Send app list usage stats after a delay. 290 const int kSendUsageStatsDelay = 5; 291 base::MessageLoop::current()->PostDelayedTask( 292 FROM_HERE, 293 base::Bind(&AppListServiceImpl::SendAppListStats), 294 base::TimeDelta::FromSeconds(kSendUsageStatsDelay)); 295} 296