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