• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 namespace {
25 
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,
31 };
32 
33 // Converts a SessionStartupPref::Type to an integer written to prefs.
TypeToPrefValue(SessionStartupPref::Type type)34 int 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 
SetNewURLList(PrefService * prefs)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);
49   }
50 }
51 
URLListToPref(const base::ListValue * url_list,SessionStartupPref * pref)52 void 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
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)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,
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
GetDefaultStartupType()87 SessionStartupPref::Type SessionStartupPref::GetDefaultStartupType() {
88 #if defined(OS_CHROMEOS)
89   return SessionStartupPref::LAST;
90 #else
91   return SessionStartupPref::DEFAULT;
92 #endif
93 }
94 
95 // static
SetStartupPref(Profile * profile,const SessionStartupPref & pref)96 void SessionStartupPref::SetStartupPref(
97     Profile* profile,
98     const SessionStartupPref& pref) {
99   DCHECK(profile);
100   SetStartupPref(profile->GetPrefs(), pref);
101 }
102 
103 // static
SetStartupPref(PrefService * prefs,const SessionStartupPref & pref)104 void 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
GetStartupPref(Profile * profile)127 SessionStartupPref SessionStartupPref::GetStartupPref(Profile* profile) {
128   DCHECK(profile);
129   return GetStartupPref(profile->GetPrefs());
130 }
131 
132 // static
GetStartupPref(PrefService * prefs)133 SessionStartupPref 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
MigrateIfNecessary(PrefService * prefs)151 void 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     UMA_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
MigrateMacDefaultPrefIfNecessary(PrefService * prefs)247 void 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
TypeIsManaged(PrefService * prefs)266 bool 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
URLsAreManaged(PrefService * prefs)275 bool 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
TypeIsDefault(PrefService * prefs)284 bool 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
PrefValueToType(int pref_value)293 SessionStartupPref::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 
SessionStartupPref(Type type)302 SessionStartupPref::SessionStartupPref(Type type) : type(type) {}
303 
~SessionStartupPref()304 SessionStartupPref::~SessionStartupPref() {}
305