app_list_service_impl.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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_store_(new ProfileStoreImpl(
170          g_browser_process->profile_manager())),
171      weak_factory_(this),
172      command_line_(*CommandLine::ForCurrentProcess()),
173      local_state_(g_browser_process->local_state()),
174      profile_loader_(new ProfileLoader(
175          profile_store_.get(),
176          scoped_ptr<KeepAliveService>(new KeepAliveServiceImpl))) {
177  profile_store_->AddProfileObserver(this);
178}
179
180AppListServiceImpl::AppListServiceImpl(
181    const CommandLine& command_line,
182    PrefService* local_state,
183    scoped_ptr<ProfileStore> profile_store,
184    scoped_ptr<KeepAliveService> keep_alive_service)
185    : profile_store_(profile_store.Pass()),
186      weak_factory_(this),
187      command_line_(command_line),
188      local_state_(local_state),
189      profile_loader_(new ProfileLoader(
190          profile_store_.get(), keep_alive_service.Pass())) {
191  profile_store_->AddProfileObserver(this);
192}
193
194AppListServiceImpl::~AppListServiceImpl() {}
195
196void AppListServiceImpl::SetAppListNextPaintCallback(
197    const base::Closure& callback) {}
198
199void AppListServiceImpl::HandleFirstRun() {}
200
201void AppListServiceImpl::Init(Profile* initial_profile) {}
202
203base::FilePath AppListServiceImpl::GetProfilePath(
204    const base::FilePath& user_data_dir) {
205  std::string app_list_profile;
206  if (local_state_->HasPrefPath(prefs::kAppListProfile))
207    app_list_profile = local_state_->GetString(prefs::kAppListProfile);
208
209  // If the user has no profile preference for the app launcher, default to the
210  // last browser profile used.
211  if (app_list_profile.empty() &&
212      local_state_->HasPrefPath(prefs::kProfileLastUsed)) {
213    app_list_profile = local_state_->GetString(prefs::kProfileLastUsed);
214  }
215
216  // If there is no last used profile recorded, use the initial profile.
217  if (app_list_profile.empty())
218    app_list_profile = chrome::kInitialProfile;
219
220  return user_data_dir.AppendASCII(app_list_profile);
221}
222
223void AppListServiceImpl::SetProfilePath(const base::FilePath& profile_path) {
224  // Ensure we don't set the pref to a managed user's profile path.
225  // TODO(calamity): Filter out managed profiles from the settings app so this
226  // can't get hit, so we can remove it.
227  if (profile_store_->IsProfileManaged(profile_path))
228    return;
229
230  local_state_->SetString(
231      prefs::kAppListProfile,
232      profile_path.BaseName().MaybeAsASCII());
233}
234
235void AppListServiceImpl::CreateShortcut() {}
236
237// We need to watch for profile removal to keep kAppListProfile updated.
238void AppListServiceImpl::OnProfileWillBeRemoved(
239    const base::FilePath& profile_path) {
240  // If the profile the app list uses just got deleted, reset it to the last
241  // used profile.
242  std::string app_list_last_profile = local_state_->GetString(
243      prefs::kAppListProfile);
244  if (profile_path.BaseName().MaybeAsASCII() == app_list_last_profile) {
245    local_state_->SetString(prefs::kAppListProfile,
246        local_state_->GetString(prefs::kProfileLastUsed));
247  }
248}
249
250void AppListServiceImpl::Show() {
251  profile_loader_->LoadProfileInvalidatingOtherLoads(
252      GetProfilePath(profile_store_->GetUserDataDir()),
253      base::Bind(&AppListServiceImpl::ShowForProfile,
254                 weak_factory_.GetWeakPtr()));
255}
256
257void AppListServiceImpl::EnableAppList(Profile* initial_profile) {
258  SetProfilePath(initial_profile->GetPath());
259  if (local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled))
260    return;
261
262  local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, true);
263  CreateShortcut();
264}
265
266void AppListServiceImpl::InvalidatePendingProfileLoads() {
267  profile_loader_->InvalidatePendingProfileLoads();
268}
269
270void AppListServiceImpl::HandleCommandLineFlags(Profile* initial_profile) {
271  if (command_line_.HasSwitch(switches::kEnableAppList))
272    EnableAppList(initial_profile);
273
274  if (command_line_.HasSwitch(switches::kResetAppListInstallState))
275    local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false);
276}
277
278void AppListServiceImpl::SendUsageStats() {
279  // Send app list usage stats after a delay.
280  const int kSendUsageStatsDelay = 5;
281  base::MessageLoop::current()->PostDelayedTask(
282      FROM_HERE,
283      base::Bind(&AppListServiceImpl::SendAppListStats),
284      base::TimeDelta::FromSeconds(kSendUsageStatsDelay));
285}
286