1a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// found in the LICENSE file.
4a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
5a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/ui/app_list/app_list_service_impl.h"
6a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/command_line.h"
11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/metrics/histogram.h"
12a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/prefs/pref_service.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/strings/string16.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/browser_process.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
17a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/profile_loader.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/profile_store.h"
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/chrome_constants.h"
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "chrome/common/chrome_switches.h"
23a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "chrome/common/pref_names.h"
24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)namespace {
26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kDiscoverabilityTimeoutMinutes = 60;
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SendAppListAppLaunch(int count) {
30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS(
31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      "Apps.AppListDailyAppLaunches", count, 1, 1000, 50);
32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (count > 0)
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppToday", 1, 2);
34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void SendAppListLaunch(int count) {
37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS(
38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      "Apps.AppListDailyLaunches", count, 1, 1000, 50);
39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (count > 0)
40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Apps.AppListHasLaunchedAppListToday", 1, 2);
41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool SendDailyEventFrequency(
44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const char* last_ping_pref,
45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const char* count_pref,
46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    void (*send_callback)(int count)) {
47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::Time now = base::Time::Now();
50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::Time last = base::Time::FromInternalValue(local_state->GetInt64(
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      last_ping_pref));
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  int days = (now - last).InDays();
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (days > 0) {
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    send_callback(local_state->GetInteger(count_pref));
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    local_state->SetInt64(
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        last_ping_pref,
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        (last + base::TimeDelta::FromDays(days)).ToInternalValue());
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    local_state->SetInteger(count_pref, 0);
59a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return true;
60a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
61a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return false;
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
63a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
64a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void RecordDailyEventFrequency(
65a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const char* last_ping_pref,
66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const char* count_pref,
67a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    void (*send_callback)(int count)) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!g_browser_process)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;  // In a unit test.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
71a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!local_state)
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;  // In a unit test.
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
75a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  int count = local_state->GetInteger(count_pref);
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  local_state->SetInteger(count_pref, count + 1);
77a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (SendDailyEventFrequency(last_ping_pref, count_pref, send_callback)) {
78a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    local_state->SetInteger(count_pref, 1);
79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  }
80a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
81a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class ProfileStoreImpl : public ProfileStore {
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public:
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  explicit ProfileStoreImpl(ProfileManager* profile_manager)
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      : profile_manager_(profile_manager),
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        weak_factory_(this) {
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
88ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void AddProfileObserver(ProfileInfoCacheObserver* observer) OVERRIDE {
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_manager_->GetProfileInfoCache().AddObserver(observer);
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void LoadProfileAsync(
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const base::FilePath& path,
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Callback<void(Profile*)> callback) OVERRIDE {
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    profile_manager_->CreateProfileAsync(
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        path,
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        base::Bind(&ProfileStoreImpl::OnProfileCreated,
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   weak_factory_.GetWeakPtr(),
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   callback),
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        base::string16(),
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        base::string16(),
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        std::string());
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void OnProfileCreated(base::Callback<void(Profile*)> callback,
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                        Profile* profile,
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                        Profile::CreateStatus status) {
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    switch (status) {
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case Profile::CREATE_STATUS_CREATED:
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case Profile::CREATE_STATUS_INITIALIZED:
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        callback.Run(profile);
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case Profile::CREATE_STATUS_LOCAL_FAIL:
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case Profile::CREATE_STATUS_REMOTE_FAIL:
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case Profile::CREATE_STATUS_CANCELED:
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case Profile::MAX_CREATE_STATUS:
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        NOTREACHED();
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual Profile* GetProfileByPath(const base::FilePath& path) OVERRIDE {
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return profile_manager_->GetProfileByPath(path);
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual base::FilePath GetUserDataDir() OVERRIDE {
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return profile_manager_->user_data_dir();
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual bool IsProfileSupervised(
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const base::FilePath& profile_path) OVERRIDE {
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ProfileInfoCache& profile_info =
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        g_browser_process->profile_manager()->GetProfileInfoCache();
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    size_t profile_index = profile_info.GetIndexOfProfileWithPath(profile_path);
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return profile_index != std::string::npos &&
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        profile_info.ProfileIsSupervisedAtIndex(profile_index);
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ProfileManager* profile_manager_;
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::WeakPtrFactory<ProfileStoreImpl> weak_factory_;
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecordAppListDiscoverability(PrefService* local_state,
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  bool is_startup_check) {
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Since this task may be delayed, ensure it does not interfere with shutdown
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // when they unluckily coincide.
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (browser_shutdown::IsTryingToQuit())
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int64 enable_time_value = local_state->GetInt64(prefs::kAppListEnableTime);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (enable_time_value == 0)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;  // Already recorded or never enabled.
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Time app_list_enable_time =
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Time::FromInternalValue(enable_time_value);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (is_startup_check) {
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // When checking at startup, only clear and record the "timeout" case,
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // otherwise wait for a timeout.
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::TimeDelta time_remaining =
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        app_list_enable_time +
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::TimeDelta::FromMinutes(kDiscoverabilityTimeoutMinutes) -
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Time::Now();
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (time_remaining > base::TimeDelta()) {
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::MessageLoop::current()->PostDelayedTask(
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          FROM_HERE,
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(&RecordAppListDiscoverability,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     base::Unretained(local_state),
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     false),
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          time_remaining);
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state->SetInt64(prefs::kAppListEnableTime, 0);
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppListService::AppListEnableSource enable_source =
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<AppListService::AppListEnableSource>(
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          local_state->GetInteger(prefs::kAppListEnableMethod));
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (enable_source == AppListService::ENABLE_FOR_APP_INSTALL) {
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::TimeDelta time_taken = base::Time::Now() - app_list_enable_time;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // This means the user "discovered" the app launcher naturally, after it was
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // enabled on the first app install. Record how long it took to discover.
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Note that the last bucket is essentially "not discovered": subtract 1
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // minute to account for clock inaccuracy.
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES(
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "Apps.AppListTimeToDiscover",
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        time_taken,
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::TimeDelta::FromSeconds(1),
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::TimeDelta::FromMinutes(kDiscoverabilityTimeoutMinutes - 1),
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        10 /* bucket_count */);
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("Apps.AppListHowEnabled",
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            enable_source,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            AppListService::ENABLE_NUM_ENABLE_SOURCES);
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
201a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}  // namespace
202a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
203a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppListServiceImpl::RecordAppListLaunch() {
204a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  RecordDailyEventFrequency(prefs::kLastAppListLaunchPing,
205a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            prefs::kAppListLaunchCount,
206a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            &SendAppListLaunch);
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordAppListDiscoverability(local_state_, false);
208a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
209a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
210a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static
211a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppListServiceImpl::RecordAppListAppLaunch() {
212a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  RecordDailyEventFrequency(prefs::kLastAppListAppLaunchPing,
213a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            prefs::kAppListAppLaunchCount,
214a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            &SendAppListAppLaunch);
215a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
216a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
217a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static
218a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppListServiceImpl::SendAppListStats() {
219a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (!g_browser_process || g_browser_process->IsShuttingDown())
220a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return;
221a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
222a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SendDailyEventFrequency(prefs::kLastAppListLaunchPing,
223a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          prefs::kAppListLaunchCount,
224a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          &SendAppListLaunch);
225a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  SendDailyEventFrequency(prefs::kLastAppListAppLaunchPing,
226a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          prefs::kAppListAppLaunchCount,
227a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                          &SendAppListAppLaunch);
228a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
229a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
230a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)AppListServiceImpl::AppListServiceImpl()
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : profile_store_(
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          new ProfileStoreImpl(g_browser_process->profile_manager())),
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      command_line_(*CommandLine::ForCurrentProcess()),
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      local_state_(g_browser_process->local_state()),
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      profile_loader_(new ProfileLoader(profile_store_.get())),
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_store_->AddProfileObserver(this);
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2400529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochAppListServiceImpl::AppListServiceImpl(const CommandLine& command_line,
2410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       PrefService* local_state,
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       scoped_ptr<ProfileStore> profile_store)
2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    : profile_store_(profile_store.Pass()),
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      command_line_(command_line),
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      local_state_(local_state),
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      profile_loader_(new ProfileLoader(profile_store_.get())),
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_store_->AddProfileObserver(this);
249a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
250a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)AppListServiceImpl::~AppListServiceImpl() {}
252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciAppListViewDelegate* AppListServiceImpl::GetViewDelegate(Profile* profile) {
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!view_delegate_)
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    view_delegate_.reset(new AppListViewDelegate(GetControllerDelegate()));
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  view_delegate_->SetProfile(profile);
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return view_delegate_.get();
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AppListServiceImpl::SetAppListNextPaintCallback(void (*callback)()) {}
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppListServiceImpl::HandleFirstRun() {}
263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
264a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppListServiceImpl::Init(Profile* initial_profile) {}
265a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)base::FilePath AppListServiceImpl::GetProfilePath(
267a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::FilePath& user_data_dir) {
268a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  std::string app_list_profile;
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (local_state_->HasPrefPath(prefs::kAppListProfile))
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    app_list_profile = local_state_->GetString(prefs::kAppListProfile);
271a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
272a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // If the user has no profile preference for the app launcher, default to the
273a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // last browser profile used.
274a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (app_list_profile.empty() &&
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      local_state_->HasPrefPath(prefs::kProfileLastUsed)) {
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    app_list_profile = local_state_->GetString(prefs::kProfileLastUsed);
277ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
278ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
279ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // If there is no last used profile recorded, use the initial profile.
280ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (app_list_profile.empty())
281ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    app_list_profile = chrome::kInitialProfile;
282a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
283ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return user_data_dir.AppendASCII(app_list_profile);
284ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
285a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
286ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppListServiceImpl::SetProfilePath(const base::FilePath& profile_path) {
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  local_state_->SetString(
288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      prefs::kAppListProfile,
289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      profile_path.BaseName().MaybeAsASCII());
290a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
291a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppListServiceImpl::CreateShortcut() {}
293a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
294a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppListServiceImpl::OnProfileWillBeRemoved(
295a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    const base::FilePath& profile_path) {
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We need to watch for profile removal to keep kAppListProfile updated, for
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the case that the deleted profile is being used by the app list.
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string app_list_last_profile = local_state_->GetString(
299a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      prefs::kAppListProfile);
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (profile_path.BaseName().MaybeAsASCII() != app_list_last_profile)
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Switch the app list over to a valid profile.
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Before ProfileInfoCache::DeleteProfileFromCache() calls this function,
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // ProfileManager::ScheduleProfileForDeletion() will have checked to see if
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the deleted profile was also "last used", and updated that setting with
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // something valid.
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  local_state_->SetString(prefs::kAppListProfile,
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          local_state_->GetString(prefs::kProfileLastUsed));
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If the app list was never shown, there won't be a |view_delegate_| yet.
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!view_delegate_)
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The Chrome AppListViewDelegate now needs its profile cleared, because:
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //  1. it has many references to the profile and can't be profile-keyed, and
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //  2. the last used profile might not be loaded yet.
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //    - this loading is sometimes done by the ProfileManager asynchronously,
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //      so the app list can't just switch to that.
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Only Mac supports showing the app list with a NULL profile, so tear down
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the view.
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DestroyAppList();
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  view_delegate_->SetProfile(NULL);
324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid AppListServiceImpl::Show() {
3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_loader_->LoadProfileInvalidatingOtherLoads(
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GetProfilePath(profile_store_->GetUserDataDir()),
329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::Bind(&AppListServiceImpl::ShowForProfile,
330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 weak_factory_.GetWeakPtr()));
331a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
332a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AppListServiceImpl::AutoShowForProfile(Profile* requested_profile) {
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (local_state_->GetInt64(prefs::kAppListEnableTime) != 0) {
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // User has not yet discovered the app launcher. Update the enable method to
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // indicate this. It will then be recorded in UMA.
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    local_state_->SetInteger(prefs::kAppListEnableMethod,
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             ENABLE_SHOWN_UNDISCOVERED);
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ShowForProfile(requested_profile);
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AppListServiceImpl::EnableAppList(Profile* initial_profile,
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       AppListEnableSource enable_source) {
345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  SetProfilePath(initial_profile->GetPath());
346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Always allow the webstore "enable" button to re-run the install flow.
347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (enable_source != AppListService::ENABLE_VIA_WEBSTORE_LINK &&
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      local_state_->GetBoolean(prefs::kAppLauncherHasBeenEnabled)) {
349ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
351ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, true);
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CreateShortcut();
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // UMA for launcher discoverability.
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->SetInt64(prefs::kAppListEnableTime,
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         base::Time::Now().ToInternalValue());
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  local_state_->SetInteger(prefs::kAppListEnableMethod, enable_source);
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (base::MessageLoop::current()) {
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Ensure a value is recorded if the user "never" shows the app list. Note
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // there is no message loop in unit tests.
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&RecordAppListDiscoverability,
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Unretained(local_state_),
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   false),
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::TimeDelta::FromMinutes(kDiscoverabilityTimeoutMinutes));
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
369a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
371a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void AppListServiceImpl::InvalidatePendingProfileLoads() {
3724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  profile_loader_->InvalidatePendingProfileLoads();
373a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
374a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AppListServiceImpl::PerformStartupChecks(Profile* initial_profile) {
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Except in rare, once-off cases, this just checks that a pref is "0" and
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // returns.
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordAppListDiscoverability(local_state_, true);
379ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
3808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (command_line_.HasSwitch(switches::kResetAppListInstallState))
3814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    local_state_->SetBoolean(prefs::kAppLauncherHasBeenEnabled, false);
38268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (command_line_.HasSwitch(switches::kEnableAppList))
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EnableAppList(initial_profile, ENABLE_VIA_COMMAND_LINE);
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!base::MessageLoop::current())
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;  // In a unit test.
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
38968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Send app list usage stats after a delay.
39068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const int kSendUsageStatsDelay = 5;
39168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
39268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      FROM_HERE,
39368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::Bind(&AppListServiceImpl::SendAppListStats),
39468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::TimeDelta::FromSeconds(kSendUsageStatsDelay));
395a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
396