session_startup_pref.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1// Copyright (c) 2012 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/prefs/session_startup_pref.h"
6
7#include <string>
8
9#include "base/metrics/histogram.h"
10#include "base/prefs/pref_service.h"
11#include "base/prefs/scoped_user_pref_update.h"
12#include "base/time/time.h"
13#include "base/values.h"
14#include "base/version.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/net/url_fixer_upper.h"
17#include "chrome/common/pref_names.h"
18#include "components/user_prefs/pref_registry_syncable.h"
19
20#if defined(OS_MACOSX)
21#include "chrome/browser/ui/cocoa/window_restore_utils.h"
22#endif
23
24namespace {
25
26enum StartupURLsMigrationMetrics {
27  STARTUP_URLS_MIGRATION_METRICS_PERFORMED,
28  STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT,
29  STARTUP_URLS_MIGRATION_METRICS_RESET,
30  STARTUP_URLS_MIGRATION_METRICS_MAX,
31};
32
33// Converts a SessionStartupPref::Type to an integer written to prefs.
34int TypeToPrefValue(SessionStartupPref::Type type) {
35  switch (type) {
36    case SessionStartupPref::LAST: return SessionStartupPref::kPrefValueLast;
37    case SessionStartupPref::URLS: return SessionStartupPref::kPrefValueURLs;
38    default:                       return SessionStartupPref::kPrefValueNewTab;
39  }
40}
41
42void SetNewURLList(PrefService* prefs) {
43  if (prefs->IsUserModifiablePreference(prefs::kURLsToRestoreOnStartup)) {
44    base::ListValue new_url_pref_list;
45    base::StringValue* home_page =
46        new base::StringValue(prefs->GetString(prefs::kHomePage));
47    new_url_pref_list.Append(home_page);
48    prefs->Set(prefs::kURLsToRestoreOnStartup, new_url_pref_list);
49  }
50}
51
52void URLListToPref(const base::ListValue* url_list, SessionStartupPref* pref) {
53  pref->urls.clear();
54  for (size_t i = 0; i < url_list->GetSize(); ++i) {
55    std::string url_text;
56    if (url_list->GetString(i, &url_text)) {
57      GURL fixed_url = URLFixerUpper::FixupURL(url_text, std::string());
58      pref->urls.push_back(fixed_url);
59    }
60  }
61}
62
63}  // namespace
64
65// static
66void SessionStartupPref::RegisterProfilePrefs(
67    user_prefs::PrefRegistrySyncable* registry) {
68  registry->RegisterIntegerPref(
69      prefs::kRestoreOnStartup,
70      TypeToPrefValue(GetDefaultStartupType()),
71      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
72  registry->RegisterListPref(prefs::kURLsToRestoreOnStartup,
73                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
74  registry->RegisterListPref(prefs::kURLsToRestoreOnStartupOld,
75                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
76  registry->RegisterBooleanPref(
77      prefs::kRestoreOnStartupMigrated,
78      false,
79      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
80  registry->RegisterInt64Pref(
81      prefs::kRestoreStartupURLsMigrationTime,
82      false,
83      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
84}
85
86// static
87SessionStartupPref::Type SessionStartupPref::GetDefaultStartupType() {
88#if defined(OS_CHROMEOS)
89  return SessionStartupPref::LAST;
90#else
91  return SessionStartupPref::DEFAULT;
92#endif
93}
94
95// static
96void SessionStartupPref::SetStartupPref(
97    Profile* profile,
98    const SessionStartupPref& pref) {
99  DCHECK(profile);
100  SetStartupPref(profile->GetPrefs(), pref);
101}
102
103// static
104void SessionStartupPref::SetStartupPref(PrefService* prefs,
105                                        const SessionStartupPref& pref) {
106  DCHECK(prefs);
107
108  if (!SessionStartupPref::TypeIsManaged(prefs))
109    prefs->SetInteger(prefs::kRestoreOnStartup, TypeToPrefValue(pref.type));
110
111  if (!SessionStartupPref::URLsAreManaged(prefs)) {
112    // Always save the URLs, that way the UI can remain consistent even if the
113    // user changes the startup type pref.
114    // Ownership of the ListValue retains with the pref service.
115    ListPrefUpdate update(prefs, prefs::kURLsToRestoreOnStartup);
116    ListValue* url_pref_list = update.Get();
117    DCHECK(url_pref_list);
118    url_pref_list->Clear();
119    for (size_t i = 0; i < pref.urls.size(); ++i) {
120      url_pref_list->Set(static_cast<int>(i),
121                         new StringValue(pref.urls[i].spec()));
122    }
123  }
124}
125
126// static
127SessionStartupPref SessionStartupPref::GetStartupPref(Profile* profile) {
128  DCHECK(profile);
129  return GetStartupPref(profile->GetPrefs());
130}
131
132// static
133SessionStartupPref SessionStartupPref::GetStartupPref(PrefService* prefs) {
134  DCHECK(prefs);
135
136  MigrateIfNecessary(prefs);
137  MigrateMacDefaultPrefIfNecessary(prefs);
138
139  SessionStartupPref pref(
140      PrefValueToType(prefs->GetInteger(prefs::kRestoreOnStartup)));
141
142  // Always load the urls, even if the pref type isn't URLS. This way the
143  // preferences panels can show the user their last choice.
144  const ListValue* url_list = prefs->GetList(prefs::kURLsToRestoreOnStartup);
145  URLListToPref(url_list, &pref);
146
147  return pref;
148}
149
150// static
151void SessionStartupPref::MigrateIfNecessary(PrefService* prefs) {
152  DCHECK(prefs);
153
154  // Check if we need to migrate the old version of the startup URLs preference
155  // to the new name, and also send metrics about the migration.
156  StartupURLsMigrationMetrics metrics_result =
157      STARTUP_URLS_MIGRATION_METRICS_MAX;
158  const base::ListValue* old_startup_urls =
159      prefs->GetList(prefs::kURLsToRestoreOnStartupOld);
160  if (!prefs->GetUserPrefValue(prefs::kRestoreStartupURLsMigrationTime)) {
161    // Record the absence of the migration timestamp, this will get overwritten
162    // below if migration occurs now.
163    metrics_result = STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT;
164
165    // Seems like we never migrated, do it if necessary.
166    if (!prefs->GetUserPrefValue(prefs::kURLsToRestoreOnStartup)) {
167      if (old_startup_urls && !old_startup_urls->empty()) {
168        prefs->Set(prefs::kURLsToRestoreOnStartup, *old_startup_urls);
169        prefs->ClearPref(prefs::kURLsToRestoreOnStartupOld);
170      }
171      metrics_result = STARTUP_URLS_MIGRATION_METRICS_PERFORMED;
172    }
173
174    prefs->SetInt64(prefs::kRestoreStartupURLsMigrationTime,
175                    base::Time::Now().ToInternalValue());
176  } else if (old_startup_urls && !old_startup_urls->empty()) {
177    // Migration needs to be reset.
178    prefs->ClearPref(prefs::kURLsToRestoreOnStartupOld);
179    base::Time last_migration_time = base::Time::FromInternalValue(
180        prefs->GetInt64(prefs::kRestoreStartupURLsMigrationTime));
181    base::Time now = base::Time::Now();
182    prefs->SetInt64(prefs::kRestoreStartupURLsMigrationTime,
183                    now.ToInternalValue());
184    if (now < last_migration_time)
185      last_migration_time = now;
186    HISTOGRAM_CUSTOM_TIMES("Settings.StartupURLsResetTime",
187                           now - last_migration_time,
188                           base::TimeDelta::FromDays(0),
189                           base::TimeDelta::FromDays(7),
190                           50);
191    metrics_result = STARTUP_URLS_MIGRATION_METRICS_RESET;
192  }
193
194  // Record a metric migration event if something interesting happened.
195  if (metrics_result != STARTUP_URLS_MIGRATION_METRICS_MAX) {
196    UMA_HISTOGRAM_ENUMERATION(
197          "Settings.StartupURLsMigration",
198          metrics_result,
199          STARTUP_URLS_MIGRATION_METRICS_MAX);
200  }
201
202  if (!prefs->GetBoolean(prefs::kRestoreOnStartupMigrated)) {
203    // Read existing values.
204    const base::Value* homepage_is_new_tab_page_value =
205        prefs->GetUserPrefValue(prefs::kHomePageIsNewTabPage);
206    bool homepage_is_new_tab_page = true;
207    if (homepage_is_new_tab_page_value) {
208      if (!homepage_is_new_tab_page_value->GetAsBoolean(
209              &homepage_is_new_tab_page))
210        NOTREACHED();
211    }
212
213    const base::Value* restore_on_startup_value =
214        prefs->GetUserPrefValue(prefs::kRestoreOnStartup);
215    int restore_on_startup = -1;
216    if (restore_on_startup_value) {
217      if (!restore_on_startup_value->GetAsInteger(&restore_on_startup))
218        NOTREACHED();
219    }
220
221    // If restore_on_startup has the deprecated value kPrefValueHomePage,
222    // migrate it to open the homepage on startup. If 'homepage is NTP' is set,
223    // that means just opening the NTP. If not, it means opening a one-item URL
224    // list containing the homepage.
225    if (restore_on_startup == kPrefValueHomePage) {
226      if (homepage_is_new_tab_page) {
227        prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueNewTab);
228      } else {
229        prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueURLs);
230        SetNewURLList(prefs);
231      }
232    } else if (!restore_on_startup_value && !homepage_is_new_tab_page &&
233               GetDefaultStartupType() == DEFAULT) {
234      // kRestoreOnStartup was never set by the user, but the homepage was set.
235      // Migrate to the list of URLs. (If restore_on_startup was never set,
236      // and homepage_is_new_tab_page is true, no action is needed. The new
237      // default value is "open the new tab page" which is what we want.)
238      prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueURLs);
239      SetNewURLList(prefs);
240    }
241
242    prefs->SetBoolean(prefs::kRestoreOnStartupMigrated, true);
243  }
244}
245
246// static
247void SessionStartupPref::MigrateMacDefaultPrefIfNecessary(PrefService* prefs) {
248#if defined(OS_MACOSX)
249  DCHECK(prefs);
250  if (!restore_utils::IsWindowRestoreEnabled())
251    return;
252  // The default startup pref used to be LAST, now it is DEFAULT. Don't change
253  // the setting for existing profiles (even if the user has never changed it),
254  // but make new profiles default to DEFAULT.
255  bool old_profile_version =
256      !prefs->FindPreference(
257          prefs::kProfileCreatedByVersion)->IsDefaultValue() &&
258      Version(prefs->GetString(prefs::kProfileCreatedByVersion)).IsOlderThan(
259          "21.0.1180.0");
260  if (old_profile_version && TypeIsDefault(prefs))
261    prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueLast);
262#endif
263}
264
265// static
266bool SessionStartupPref::TypeIsManaged(PrefService* prefs) {
267  DCHECK(prefs);
268  const PrefService::Preference* pref_restore =
269      prefs->FindPreference(prefs::kRestoreOnStartup);
270  DCHECK(pref_restore);
271  return pref_restore->IsManaged();
272}
273
274// static
275bool SessionStartupPref::URLsAreManaged(PrefService* prefs) {
276  DCHECK(prefs);
277  const PrefService::Preference* pref_urls =
278      prefs->FindPreference(prefs::kURLsToRestoreOnStartup);
279  DCHECK(pref_urls);
280  return pref_urls->IsManaged();
281}
282
283// static
284bool SessionStartupPref::TypeIsDefault(PrefService* prefs) {
285  DCHECK(prefs);
286  const PrefService::Preference* pref_restore =
287      prefs->FindPreference(prefs::kRestoreOnStartup);
288  DCHECK(pref_restore);
289  return pref_restore->IsDefaultValue();
290}
291
292// static
293SessionStartupPref::Type SessionStartupPref::PrefValueToType(int pref_value) {
294  switch (pref_value) {
295    case kPrefValueLast:     return SessionStartupPref::LAST;
296    case kPrefValueURLs:     return SessionStartupPref::URLS;
297    case kPrefValueHomePage: return SessionStartupPref::HOMEPAGE;
298    default:                 return SessionStartupPref::DEFAULT;
299  }
300}
301
302SessionStartupPref::SessionStartupPref(Type type) : type(type) {}
303
304SessionStartupPref::~SessionStartupPref() {}
305