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.
5 #include "chrome/browser/prefs/session_startup_pref.h"
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/pref_names.h"
17 #include "components/pref_registry/pref_registry_syncable.h"
18 #include "components/url_fixer/url_fixer.h"
20 #if defined(OS_MACOSX)
21 #include "chrome/browser/ui/cocoa/window_restore_utils.h"
26 enum 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
,
33 // Converts a SessionStartupPref::Type to an integer written to prefs.
34 int TypeToPrefValue(SessionStartupPref::Type type
) {
36 case SessionStartupPref::LAST
: return SessionStartupPref::kPrefValueLast
;
37 case SessionStartupPref::URLS
: return SessionStartupPref::kPrefValueURLs
;
38 default: return SessionStartupPref::kPrefValueNewTab
;
42 void 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
);
52 void URLListToPref(const base::ListValue
* url_list
, SessionStartupPref
* pref
) {
54 for (size_t i
= 0; i
< url_list
->GetSize(); ++i
) {
56 if (url_list
->GetString(i
, &url_text
)) {
57 GURL fixed_url
= url_fixer::FixupURL(url_text
, std::string());
58 pref
->urls
.push_back(fixed_url
);
66 void 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
,
79 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
80 registry
->RegisterInt64Pref(
81 prefs::kRestoreStartupURLsMigrationTime
,
83 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
87 SessionStartupPref::Type
SessionStartupPref::GetDefaultStartupType() {
88 #if defined(OS_CHROMEOS)
89 return SessionStartupPref::LAST
;
91 return SessionStartupPref::DEFAULT
;
96 void SessionStartupPref::SetStartupPref(
98 const SessionStartupPref
& pref
) {
100 SetStartupPref(profile
->GetPrefs(), pref
);
104 void SessionStartupPref::SetStartupPref(PrefService
* prefs
,
105 const SessionStartupPref
& pref
) {
108 if (!SessionStartupPref::TypeIsManaged(prefs
))
109 prefs
->SetInteger(prefs::kRestoreOnStartup
, TypeToPrefValue(pref
.type
));
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 base::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 base::StringValue(pref
.urls
[i
].spec()));
127 SessionStartupPref
SessionStartupPref::GetStartupPref(Profile
* profile
) {
129 return GetStartupPref(profile
->GetPrefs());
133 SessionStartupPref
SessionStartupPref::GetStartupPref(PrefService
* prefs
) {
136 MigrateIfNecessary(prefs
);
137 MigrateMacDefaultPrefIfNecessary(prefs
);
139 SessionStartupPref
pref(
140 PrefValueToType(prefs
->GetInteger(prefs::kRestoreOnStartup
)));
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 base::ListValue
* url_list
=
145 prefs
->GetList(prefs::kURLsToRestoreOnStartup
);
146 URLListToPref(url_list
, &pref
);
152 void SessionStartupPref::MigrateIfNecessary(PrefService
* prefs
) {
155 // Check if we need to migrate the old version of the startup URLs preference
156 // to the new name, and also send metrics about the migration.
157 StartupURLsMigrationMetrics metrics_result
=
158 STARTUP_URLS_MIGRATION_METRICS_MAX
;
159 const base::ListValue
* old_startup_urls
=
160 prefs
->GetList(prefs::kURLsToRestoreOnStartupOld
);
161 if (!prefs
->GetUserPrefValue(prefs::kRestoreStartupURLsMigrationTime
)) {
162 // Record the absence of the migration timestamp, this will get overwritten
163 // below if migration occurs now.
164 metrics_result
= STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT
;
166 // Seems like we never migrated, do it if necessary.
167 if (!prefs
->GetUserPrefValue(prefs::kURLsToRestoreOnStartup
)) {
168 if (old_startup_urls
&& !old_startup_urls
->empty()) {
169 prefs
->Set(prefs::kURLsToRestoreOnStartup
, *old_startup_urls
);
170 prefs
->ClearPref(prefs::kURLsToRestoreOnStartupOld
);
172 metrics_result
= STARTUP_URLS_MIGRATION_METRICS_PERFORMED
;
175 prefs
->SetInt64(prefs::kRestoreStartupURLsMigrationTime
,
176 base::Time::Now().ToInternalValue());
177 } else if (old_startup_urls
&& !old_startup_urls
->empty()) {
178 // Migration needs to be reset.
179 prefs
->ClearPref(prefs::kURLsToRestoreOnStartupOld
);
180 base::Time last_migration_time
= base::Time::FromInternalValue(
181 prefs
->GetInt64(prefs::kRestoreStartupURLsMigrationTime
));
182 base::Time now
= base::Time::Now();
183 prefs
->SetInt64(prefs::kRestoreStartupURLsMigrationTime
,
184 now
.ToInternalValue());
185 if (now
< last_migration_time
)
186 last_migration_time
= now
;
187 UMA_HISTOGRAM_CUSTOM_TIMES("Settings.StartupURLsResetTime",
188 now
- last_migration_time
,
189 base::TimeDelta::FromDays(0),
190 base::TimeDelta::FromDays(7),
192 metrics_result
= STARTUP_URLS_MIGRATION_METRICS_RESET
;
195 // Record a metric migration event if something interesting happened.
196 if (metrics_result
!= STARTUP_URLS_MIGRATION_METRICS_MAX
) {
197 UMA_HISTOGRAM_ENUMERATION(
198 "Settings.StartupURLsMigration",
200 STARTUP_URLS_MIGRATION_METRICS_MAX
);
203 if (!prefs
->GetBoolean(prefs::kRestoreOnStartupMigrated
)) {
204 // Read existing values.
205 const base::Value
* homepage_is_new_tab_page_value
=
206 prefs
->GetUserPrefValue(prefs::kHomePageIsNewTabPage
);
207 bool homepage_is_new_tab_page
= true;
208 if (homepage_is_new_tab_page_value
) {
209 if (!homepage_is_new_tab_page_value
->GetAsBoolean(
210 &homepage_is_new_tab_page
))
214 const base::Value
* restore_on_startup_value
=
215 prefs
->GetUserPrefValue(prefs::kRestoreOnStartup
);
216 int restore_on_startup
= -1;
217 if (restore_on_startup_value
) {
218 if (!restore_on_startup_value
->GetAsInteger(&restore_on_startup
))
222 // If restore_on_startup has the deprecated value kPrefValueHomePage,
223 // migrate it to open the homepage on startup. If 'homepage is NTP' is set,
224 // that means just opening the NTP. If not, it means opening a one-item URL
225 // list containing the homepage.
226 if (restore_on_startup
== kPrefValueHomePage
) {
227 if (homepage_is_new_tab_page
) {
228 prefs
->SetInteger(prefs::kRestoreOnStartup
, kPrefValueNewTab
);
230 prefs
->SetInteger(prefs::kRestoreOnStartup
, kPrefValueURLs
);
231 SetNewURLList(prefs
);
233 } else if (!restore_on_startup_value
&& !homepage_is_new_tab_page
&&
234 GetDefaultStartupType() == DEFAULT
) {
235 // kRestoreOnStartup was never set by the user, but the homepage was set.
236 // Migrate to the list of URLs. (If restore_on_startup was never set,
237 // and homepage_is_new_tab_page is true, no action is needed. The new
238 // default value is "open the new tab page" which is what we want.)
239 prefs
->SetInteger(prefs::kRestoreOnStartup
, kPrefValueURLs
);
240 SetNewURLList(prefs
);
243 prefs
->SetBoolean(prefs::kRestoreOnStartupMigrated
, true);
248 void SessionStartupPref::MigrateMacDefaultPrefIfNecessary(PrefService
* prefs
) {
249 #if defined(OS_MACOSX)
251 if (!restore_utils::IsWindowRestoreEnabled())
253 // The default startup pref used to be LAST, now it is DEFAULT. Don't change
254 // the setting for existing profiles (even if the user has never changed it),
255 // but make new profiles default to DEFAULT.
256 bool old_profile_version
=
257 !prefs
->FindPreference(
258 prefs::kProfileCreatedByVersion
)->IsDefaultValue() &&
259 Version(prefs
->GetString(prefs::kProfileCreatedByVersion
)).IsOlderThan(
261 if (old_profile_version
&& TypeIsDefault(prefs
))
262 prefs
->SetInteger(prefs::kRestoreOnStartup
, kPrefValueLast
);
267 bool SessionStartupPref::TypeIsManaged(PrefService
* prefs
) {
269 const PrefService::Preference
* pref_restore
=
270 prefs
->FindPreference(prefs::kRestoreOnStartup
);
271 DCHECK(pref_restore
);
272 return pref_restore
->IsManaged();
276 bool SessionStartupPref::URLsAreManaged(PrefService
* prefs
) {
278 const PrefService::Preference
* pref_urls
=
279 prefs
->FindPreference(prefs::kURLsToRestoreOnStartup
);
281 return pref_urls
->IsManaged();
285 bool SessionStartupPref::TypeIsDefault(PrefService
* prefs
) {
287 const PrefService::Preference
* pref_restore
=
288 prefs
->FindPreference(prefs::kRestoreOnStartup
);
289 DCHECK(pref_restore
);
290 return pref_restore
->IsDefaultValue();
294 SessionStartupPref::Type
SessionStartupPref::PrefValueToType(int pref_value
) {
295 switch (pref_value
) {
296 case kPrefValueLast
: return SessionStartupPref::LAST
;
297 case kPrefValueURLs
: return SessionStartupPref::URLS
;
298 case kPrefValueHomePage
: return SessionStartupPref::HOMEPAGE
;
299 default: return SessionStartupPref::DEFAULT
;
303 SessionStartupPref::SessionStartupPref(Type type
) : type(type
) {}
305 SessionStartupPref::~SessionStartupPref() {}