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. 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 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 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 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 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 96 void SessionStartupPref::SetStartupPref( 97 Profile* profile, 98 const SessionStartupPref& pref) { 99 DCHECK(profile); 100 SetStartupPref(profile->GetPrefs(), pref); 101 } 102 103 // static 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 127 SessionStartupPref SessionStartupPref::GetStartupPref(Profile* profile) { 128 DCHECK(profile); 129 return GetStartupPref(profile->GetPrefs()); 130 } 131 132 // static 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 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 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 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 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 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 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 302 SessionStartupPref::SessionStartupPref(Type type) : type(type) {} 303 304 SessionStartupPref::~SessionStartupPref() {} 305