Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / app_list_service_impl.cc
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/bind.h"
11 #include "base/command_line.h"
12 #include "base/metrics/histogram.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/string16.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/apps/shortcut_manager.h"
17 #include "chrome/browser/apps/shortcut_manager_factory.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/browser_shutdown.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/ui/app_list/keep_alive_service.h"
22 #include "chrome/browser/ui/app_list/keep_alive_service_impl.h"
23 #include "chrome/browser/ui/app_list/profile_loader.h"
24 #include "chrome/browser/ui/app_list/profile_store.h"
25 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28
29 namespace {
30
31 const int kDiscoverabilityTimeoutMinutes = 60;
32
33 void SendAppListAppLaunch(int count) {
34   UMA_HISTOGRAM_CUSTOM_COUNTS(
35       "Apps.AppListDailyAppLaunches", count, 1, 1000, 50);
36   if (count > 0)
37     UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppToday", 1, 2);
38 }
39
40 void SendAppListLaunch(int count) {
41   UMA_HISTOGRAM_CUSTOM_COUNTS(
42       "Apps.AppListDailyLaunches", count, 1, 1000, 50);
43   if (count > 0)
44     UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppListToday", 1, 2);
45 }
46
47 bool SendDailyEventFrequency(
48     const char* last_ping_pref,
49     const char* count_pref,
50     void (*send_callback)(int count)) {
51   PrefService* local_state = g_browser_process->local_state();
52
53   base::Time now = base::Time::Now();
54   base::Time last = base::Time::FromInternalValue(local_state->GetInt64(
55       last_ping_pref));
56   int days = (now - last).InDays();
57   if (days > 0) {
58     send_callback(local_state->GetInteger(count_pref));
59     local_state->SetInt64(
60         last_ping_pref,
61         (last + base::TimeDelta::FromDays(days)).ToInternalValue());
62     local_state->SetInteger(count_pref, 0);
63     return true;
64   }
65   return false;
66 }
67
68 void RecordDailyEventFrequency(
69     const char* last_ping_pref,
70     const char* count_pref,
71     void (*send_callback)(int count)) {
72   if (!g_browser_process)
73     return;  // In a unit test.
74
75   PrefService* local_state = g_browser_process->local_state();
76
77   int count = local_state->GetInteger(count_pref);
78   local_state->SetInteger(count_pref, count + 1);
79   if (SendDailyEventFrequency(last_ping_pref, count_pref, send_callback)) {
80     local_state->SetInteger(count_pref, 1);
81   }
82 }
83
84 class ProfileStoreImpl : public ProfileStore {
85  public:
86   explicit ProfileStoreImpl(ProfileManager* profile_manager)
87       : profile_manager_(profile_manager),
88         weak_factory_(this) {
89   }
90
91   virtual void AddProfileObserver(ProfileInfoCacheObserver* observer) OVERRIDE {
92     profile_manager_->GetProfileInfoCache().AddObserver(observer);
93   }
94
95   virtual void LoadProfileAsync(
96       const base::FilePath& path,
97       base::Callback<void(Profile*)> callback) OVERRIDE {
98     profile_manager_->CreateProfileAsync(
99         path,
100         base::Bind(&ProfileStoreImpl::OnProfileCreated,
101                    weak_factory_.GetWeakPtr(),
102                    callback),
103         base::string16(),
104         base::string16(),
105         std::string());
106   }
107
108   void OnProfileCreated(base::Callback<void(Profile*)> callback,
109                         Profile* profile,
110                         Profile::CreateStatus status) {
111     switch (status) {
112       case Profile::CREATE_STATUS_CREATED:
113         break;
114       case Profile::CREATE_STATUS_INITIALIZED:
115         callback.Run(profile);
116         break;
117       case Profile::CREATE_STATUS_LOCAL_FAIL:
118       case Profile::CREATE_STATUS_REMOTE_FAIL:
119       case Profile::CREATE_STATUS_CANCELED:
120         break;
121       case Profile::MAX_CREATE_STATUS:
122         NOTREACHED();
123         break;
124     }
125   }
126
127   virtual Profile* GetProfileByPath(const base::FilePath& path) OVERRIDE {
128     return profile_manager_->GetProfileByPath(path);
129   }
130
131   virtual base::FilePath GetUserDataDir() OVERRIDE {
132     return profile_manager_->user_data_dir();
133   }
134
135   virtual bool IsProfileManaged(const base::FilePath& profile_path) OVERRIDE {
136     ProfileInfoCache& profile_info =
137         g_browser_process->profile_manager()->GetProfileInfoCache();
138     size_t profile_index = profile_info.GetIndexOfProfileWithPath(profile_path);
139     return profile_info.ProfileIsManagedAtIndex(profile_index);
140   }
141
142  private:
143   ProfileManager* profile_manager_;
144   base::WeakPtrFactory<ProfileStoreImpl> weak_factory_;
145 };
146
147 void RecordAppListDiscoverability(PrefService* local_state,
148                                   bool is_startup_check) {
149   // Since this task may be delayed, ensure it does not interfere with shutdown
150   // when they unluckily coincide.
151   if (browser_shutdown::IsTryingToQuit())
152     return;
153
154   int64 enable_time_value = local_state->GetInt64(prefs::kAppListEnableTime);
155   if (enable_time_value == 0)
156     return;  // Already recorded or never enabled.
157
158   base::Time app_list_enable_time =
159       base::Time::FromInternalValue(enable_time_value);
160   if (is_startup_check) {
161     // When checking at startup, only clear and record the "timeout" case,
162     // otherwise wait for a timeout.
163     base::TimeDelta time_remaining =
164         app_list_enable_time +
165         base::TimeDelta::FromMinutes(kDiscoverabilityTimeoutMinutes) -
166         base::Time::Now();
167     if (time_remaining > base::TimeDelta()) {
168       base::MessageLoop::current()->PostDelayedTask(
169           FROM_HERE,
170           base::Bind(&RecordAppListDiscoverability,
171                      base::Unretained(local_state),
172                      false),
173           time_remaining);
174       return;
175     }
176   }
177
178   local_state->SetInt64(prefs::kAppListEnableTime, 0);
179
180   AppListService::AppListEnableSource enable_source =
181       static_cast<AppListService::AppListEnableSource>(
182           local_state->GetInteger(prefs::kAppListEnableMethod));
183   if (enable_source == AppListService::ENABLE_FOR_APP_INSTALL) {
184     base::TimeDelta time_taken = base::Time::Now() - app_list_enable_time;
185     // This means the user "discovered" the app launcher naturally, after it was
186     // enabled on the first app install. Record how long it took to discover.
187     // Note that the last bucket is essentially "not discovered": subtract 1
188     // minute to account for clock inaccuracy.
189     UMA_HISTOGRAM_CUSTOM_TIMES(
190         "Apps.AppListTimeToDiscover",
191         time_taken,
192         base::TimeDelta::FromSeconds(1),
193         base::TimeDelta::FromMinutes(kDiscoverabilityTimeoutMinutes - 1),
194         10 /* bucket_count */);
195   }
196   UMA_HISTOGRAM_ENUMERATION("Apps.AppListHowEnabled",
197                             enable_source,
198                             AppListService::ENABLE_NUM_ENABLE_SOURCES);
199 }
200
201 }  // namespace
202
203 void AppListServiceImpl::RecordAppListLaunch() {
204   RecordDailyEventFrequency(prefs::kLastAppListLaunchPing,
205                             prefs::kAppListLaunchCount,
206                             &SendAppListLaunch);
207   RecordAppListDiscoverability(local_state_, false);
208 }
209
210 // static
211 void AppListServiceImpl::RecordAppListAppLaunch() {
212   RecordDailyEventFrequency(prefs::kLastAppListAppLaunchPing,
213                             prefs::kAppListAppLaunchCount,
214                             &SendAppListAppLaunch);
215 }
216
217 // static
218 void AppListServiceImpl::SendAppListStats() {
219   if (!g_browser_process || g_browser_process->IsShuttingDown())
220     return;
221
222   SendDailyEventFrequency(prefs::kLastAppListLaunchPing,
223                           prefs::kAppListLaunchCount,
224                           &SendAppListLaunch);
225   SendDailyEventFrequency(prefs::kLastAppListAppLaunchPing,
226                           prefs::kAppListAppLaunchCount,
227                           &SendAppListAppLaunch);
228 }
229
230 AppListServiceImpl::AppListServiceImpl()
231     : profile_store_(new ProfileStoreImpl(
232           g_browser_process->profile_manager())),
233       weak_factory_(this),
234       command_line_(*CommandLine::ForCurrentProcess()),
235       local_state_(g_browser_process->local_state()),
236       profile_loader_(new ProfileLoader(
237           profile_store_.get(),
238           scoped_ptr<KeepAliveService>(new KeepAliveServiceImpl))) {
239   profile_store_->AddProfileObserver(this);
240 }
241
242 AppListServiceImpl::AppListServiceImpl(
243     const CommandLine& command_line,
244     PrefService* local_state,
245     scoped_ptr<ProfileStore> profile_store,
246     scoped_ptr<KeepAliveService> keep_alive_service)
247     : profile_store_(profile_store.Pass()),
248       weak_factory_(this),
249       command_line_(command_line),
250       local_state_(local_state),
251       profile_loader_(new ProfileLoader(
252           profile_store_.get(), keep_alive_service.Pass())) {
253   profile_store_->AddProfileObserver(this);
254 }
255
256 AppListServiceImpl::~AppListServiceImpl() {}
257
258 void AppListServiceImpl::SetAppListNextPaintCallback(void (*callback)()) {}
259
260 void AppListServiceImpl::HandleFirstRun() {}
261
262 void AppListServiceImpl::Init(Profile* initial_profile) {}
263
264 base::FilePath AppListServiceImpl::GetProfilePath(
265     const base::FilePath& user_data_dir) {
266   std::string app_list_profile;
267   if (local_state_->HasPrefPath(prefs::kAppListProfile))
268     app_list_profile = local_state_->GetString(prefs::kAppListProfile);
269
270   // If the user has no profile preference for the app launcher, default to the
271   // last browser profile used.
272   if (app_list_profile.empty() &&
273       local_state_->HasPrefPath(prefs::kProfileLastUsed)) {
274     app_list_profile = local_state_->GetString(prefs::kProfileLastUsed);
275   }
276
277   // If there is no last used profile recorded, use the initial profile.
278   if (app_list_profile.empty())
279     app_list_profile = chrome::kInitialProfile;
280
281   return user_data_dir.AppendASCII(app_list_profile);
282 }
283
284 void AppListServiceImpl::SetProfilePath(const base::FilePath& profile_path) {
285   // Ensure we don't set the pref to a managed user's profile path.
286   // TODO(calamity): Filter out managed profiles from the settings app so this
287   // can't get hit, so we can remove it.
288   if (profile_store_->IsProfileManaged(profile_path))
289     return;
290
291   local_state_->SetString(
292       prefs::kAppListProfile,
293       profile_path.BaseName().MaybeAsASCII());
294 }
295
296 void AppListServiceImpl::CreateShortcut() {}
297
298 // We need to watch for profile removal to keep kAppListProfile updated.
299 void AppListServiceImpl::OnProfileWillBeRemoved(
300     const base::FilePath& profile_path) {
301   // If the profile the app list uses just got deleted, reset it to the last
302   // used profile.
303   std::string app_list_last_profile = local_state_->GetString(
304       prefs::kAppListProfile);
305   if (profile_path.BaseName().MaybeAsASCII() == app_list_last_profile) {
306     local_state_->SetString(prefs::kAppListProfile,
307         local_state_->GetString(prefs::kProfileLastUsed));
308   }
309 }
310
311 void AppListServiceImpl::Show() {
312   profile_loader_->LoadProfileInvalidatingOtherLoads(
313       GetProfilePath(profile_store_->GetUserDataDir()),
314       base::Bind(&AppListServiceImpl::ShowForProfile,
315                  weak_factory_.GetWeakPtr()));
316 }
317
318 void AppListServiceImpl::AutoShowForProfile(Profile* requested_profile) {
319   if (local_state_->GetInt64(prefs::kAppListEnableTime) != 0) {
320     // User has not yet discovered the app launcher. Update the enable method to
321     // indicate this. It will then be recorded in UMA.
322     local_state_->SetInteger(prefs::kAppListEnableMethod,
323                              ENABLE_SHOWN_UNDISCOVERED);
324   }
325   ShowForProfile(requested_profile);
326 }
327
328 void AppListServiceImpl::EnableAppList(Profile* initial_profile,
329                                        AppListEnableSource enable_source) {
330   SetProfilePath(initial_profile->GetPath());
331   if (local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled))
332     return;
333
334   local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, true);
335   CreateShortcut();
336
337   // UMA for launcher discoverability.
338   local_state_->SetInt64(prefs::kAppListEnableTime,
339                          base::Time::Now().ToInternalValue());
340   local_state_->SetInteger(prefs::kAppListEnableMethod, enable_source);
341   if (base::MessageLoop::current()) {
342     // Ensure a value is recorded if the user "never" shows the app list. Note
343     // there is no message loop in unit tests.
344     base::MessageLoop::current()->PostDelayedTask(
345         FROM_HERE,
346         base::Bind(&RecordAppListDiscoverability,
347                    base::Unretained(local_state_),
348                    false),
349         base::TimeDelta::FromMinutes(kDiscoverabilityTimeoutMinutes));
350   }
351
352   AppShortcutManager* shortcut_manager =
353       AppShortcutManagerFactory::GetForProfile(initial_profile);
354   if (shortcut_manager)
355     shortcut_manager->OnceOffCreateShortcuts();
356 }
357
358 void AppListServiceImpl::InvalidatePendingProfileLoads() {
359   profile_loader_->InvalidatePendingProfileLoads();
360 }
361
362 void AppListServiceImpl::PerformStartupChecks(Profile* initial_profile) {
363   // Except in rare, once-off cases, this just checks that a pref is "0" and
364   // returns.
365   RecordAppListDiscoverability(local_state_, true);
366
367   if (command_line_.HasSwitch(switches::kResetAppListInstallState))
368     local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false);
369
370   if (command_line_.HasSwitch(switches::kEnableAppList))
371     EnableAppList(initial_profile, ENABLE_VIA_COMMAND_LINE);
372
373   if (!base::MessageLoop::current())
374     return;  // In a unit test.
375
376   // Send app list usage stats after a delay.
377   const int kSendUsageStatsDelay = 5;
378   base::MessageLoop::current()->PostDelayedTask(
379       FROM_HERE,
380       base::Bind(&AppListServiceImpl::SendAppListStats),
381       base::TimeDelta::FromSeconds(kSendUsageStatsDelay));
382 }