普通文本  |  305行  |  10.8 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prefs/session_startup_pref.h"

#include <string>

#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/time/time.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/net/url_fixer_upper.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"

#if defined(OS_MACOSX)
#include "chrome/browser/ui/cocoa/window_restore_utils.h"
#endif

namespace {

enum StartupURLsMigrationMetrics {
  STARTUP_URLS_MIGRATION_METRICS_PERFORMED,
  STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT,
  STARTUP_URLS_MIGRATION_METRICS_RESET,
  STARTUP_URLS_MIGRATION_METRICS_MAX,
};

// Converts a SessionStartupPref::Type to an integer written to prefs.
int TypeToPrefValue(SessionStartupPref::Type type) {
  switch (type) {
    case SessionStartupPref::LAST: return SessionStartupPref::kPrefValueLast;
    case SessionStartupPref::URLS: return SessionStartupPref::kPrefValueURLs;
    default:                       return SessionStartupPref::kPrefValueNewTab;
  }
}

void SetNewURLList(PrefService* prefs) {
  if (prefs->IsUserModifiablePreference(prefs::kURLsToRestoreOnStartup)) {
    base::ListValue new_url_pref_list;
    base::StringValue* home_page =
        new base::StringValue(prefs->GetString(prefs::kHomePage));
    new_url_pref_list.Append(home_page);
    prefs->Set(prefs::kURLsToRestoreOnStartup, new_url_pref_list);
  }
}

void URLListToPref(const base::ListValue* url_list, SessionStartupPref* pref) {
  pref->urls.clear();
  for (size_t i = 0; i < url_list->GetSize(); ++i) {
    std::string url_text;
    if (url_list->GetString(i, &url_text)) {
      GURL fixed_url = URLFixerUpper::FixupURL(url_text, std::string());
      pref->urls.push_back(fixed_url);
    }
  }
}

}  // namespace

// static
void SessionStartupPref::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterIntegerPref(
      prefs::kRestoreOnStartup,
      TypeToPrefValue(GetDefaultStartupType()),
      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
  registry->RegisterListPref(prefs::kURLsToRestoreOnStartup,
                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
  registry->RegisterListPref(prefs::kURLsToRestoreOnStartupOld,
                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterBooleanPref(
      prefs::kRestoreOnStartupMigrated,
      false,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterInt64Pref(
      prefs::kRestoreStartupURLsMigrationTime,
      false,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

// static
SessionStartupPref::Type SessionStartupPref::GetDefaultStartupType() {
#if defined(OS_CHROMEOS)
  return SessionStartupPref::LAST;
#else
  return SessionStartupPref::DEFAULT;
#endif
}

// static
void SessionStartupPref::SetStartupPref(
    Profile* profile,
    const SessionStartupPref& pref) {
  DCHECK(profile);
  SetStartupPref(profile->GetPrefs(), pref);
}

// static
void SessionStartupPref::SetStartupPref(PrefService* prefs,
                                        const SessionStartupPref& pref) {
  DCHECK(prefs);

  if (!SessionStartupPref::TypeIsManaged(prefs))
    prefs->SetInteger(prefs::kRestoreOnStartup, TypeToPrefValue(pref.type));

  if (!SessionStartupPref::URLsAreManaged(prefs)) {
    // Always save the URLs, that way the UI can remain consistent even if the
    // user changes the startup type pref.
    // Ownership of the ListValue retains with the pref service.
    ListPrefUpdate update(prefs, prefs::kURLsToRestoreOnStartup);
    ListValue* url_pref_list = update.Get();
    DCHECK(url_pref_list);
    url_pref_list->Clear();
    for (size_t i = 0; i < pref.urls.size(); ++i) {
      url_pref_list->Set(static_cast<int>(i),
                         new StringValue(pref.urls[i].spec()));
    }
  }
}

// static
SessionStartupPref SessionStartupPref::GetStartupPref(Profile* profile) {
  DCHECK(profile);
  return GetStartupPref(profile->GetPrefs());
}

// static
SessionStartupPref SessionStartupPref::GetStartupPref(PrefService* prefs) {
  DCHECK(prefs);

  MigrateIfNecessary(prefs);
  MigrateMacDefaultPrefIfNecessary(prefs);

  SessionStartupPref pref(
      PrefValueToType(prefs->GetInteger(prefs::kRestoreOnStartup)));

  // Always load the urls, even if the pref type isn't URLS. This way the
  // preferences panels can show the user their last choice.
  const ListValue* url_list = prefs->GetList(prefs::kURLsToRestoreOnStartup);
  URLListToPref(url_list, &pref);

  return pref;
}

// static
void SessionStartupPref::MigrateIfNecessary(PrefService* prefs) {
  DCHECK(prefs);

  // Check if we need to migrate the old version of the startup URLs preference
  // to the new name, and also send metrics about the migration.
  StartupURLsMigrationMetrics metrics_result =
      STARTUP_URLS_MIGRATION_METRICS_MAX;
  const base::ListValue* old_startup_urls =
      prefs->GetList(prefs::kURLsToRestoreOnStartupOld);
  if (!prefs->GetUserPrefValue(prefs::kRestoreStartupURLsMigrationTime)) {
    // Record the absence of the migration timestamp, this will get overwritten
    // below if migration occurs now.
    metrics_result = STARTUP_URLS_MIGRATION_METRICS_NOT_PRESENT;

    // Seems like we never migrated, do it if necessary.
    if (!prefs->GetUserPrefValue(prefs::kURLsToRestoreOnStartup)) {
      if (old_startup_urls && !old_startup_urls->empty()) {
        prefs->Set(prefs::kURLsToRestoreOnStartup, *old_startup_urls);
        prefs->ClearPref(prefs::kURLsToRestoreOnStartupOld);
      }
      metrics_result = STARTUP_URLS_MIGRATION_METRICS_PERFORMED;
    }

    prefs->SetInt64(prefs::kRestoreStartupURLsMigrationTime,
                    base::Time::Now().ToInternalValue());
  } else if (old_startup_urls && !old_startup_urls->empty()) {
    // Migration needs to be reset.
    prefs->ClearPref(prefs::kURLsToRestoreOnStartupOld);
    base::Time last_migration_time = base::Time::FromInternalValue(
        prefs->GetInt64(prefs::kRestoreStartupURLsMigrationTime));
    base::Time now = base::Time::Now();
    prefs->SetInt64(prefs::kRestoreStartupURLsMigrationTime,
                    now.ToInternalValue());
    if (now < last_migration_time)
      last_migration_time = now;
    UMA_HISTOGRAM_CUSTOM_TIMES("Settings.StartupURLsResetTime",
                               now - last_migration_time,
                               base::TimeDelta::FromDays(0),
                               base::TimeDelta::FromDays(7),
                               50);
    metrics_result = STARTUP_URLS_MIGRATION_METRICS_RESET;
  }

  // Record a metric migration event if something interesting happened.
  if (metrics_result != STARTUP_URLS_MIGRATION_METRICS_MAX) {
    UMA_HISTOGRAM_ENUMERATION(
          "Settings.StartupURLsMigration",
          metrics_result,
          STARTUP_URLS_MIGRATION_METRICS_MAX);
  }

  if (!prefs->GetBoolean(prefs::kRestoreOnStartupMigrated)) {
    // Read existing values.
    const base::Value* homepage_is_new_tab_page_value =
        prefs->GetUserPrefValue(prefs::kHomePageIsNewTabPage);
    bool homepage_is_new_tab_page = true;
    if (homepage_is_new_tab_page_value) {
      if (!homepage_is_new_tab_page_value->GetAsBoolean(
              &homepage_is_new_tab_page))
        NOTREACHED();
    }

    const base::Value* restore_on_startup_value =
        prefs->GetUserPrefValue(prefs::kRestoreOnStartup);
    int restore_on_startup = -1;
    if (restore_on_startup_value) {
      if (!restore_on_startup_value->GetAsInteger(&restore_on_startup))
        NOTREACHED();
    }

    // If restore_on_startup has the deprecated value kPrefValueHomePage,
    // migrate it to open the homepage on startup. If 'homepage is NTP' is set,
    // that means just opening the NTP. If not, it means opening a one-item URL
    // list containing the homepage.
    if (restore_on_startup == kPrefValueHomePage) {
      if (homepage_is_new_tab_page) {
        prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueNewTab);
      } else {
        prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueURLs);
        SetNewURLList(prefs);
      }
    } else if (!restore_on_startup_value && !homepage_is_new_tab_page &&
               GetDefaultStartupType() == DEFAULT) {
      // kRestoreOnStartup was never set by the user, but the homepage was set.
      // Migrate to the list of URLs. (If restore_on_startup was never set,
      // and homepage_is_new_tab_page is true, no action is needed. The new
      // default value is "open the new tab page" which is what we want.)
      prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueURLs);
      SetNewURLList(prefs);
    }

    prefs->SetBoolean(prefs::kRestoreOnStartupMigrated, true);
  }
}

// static
void SessionStartupPref::MigrateMacDefaultPrefIfNecessary(PrefService* prefs) {
#if defined(OS_MACOSX)
  DCHECK(prefs);
  if (!restore_utils::IsWindowRestoreEnabled())
    return;
  // The default startup pref used to be LAST, now it is DEFAULT. Don't change
  // the setting for existing profiles (even if the user has never changed it),
  // but make new profiles default to DEFAULT.
  bool old_profile_version =
      !prefs->FindPreference(
          prefs::kProfileCreatedByVersion)->IsDefaultValue() &&
      Version(prefs->GetString(prefs::kProfileCreatedByVersion)).IsOlderThan(
          "21.0.1180.0");
  if (old_profile_version && TypeIsDefault(prefs))
    prefs->SetInteger(prefs::kRestoreOnStartup, kPrefValueLast);
#endif
}

// static
bool SessionStartupPref::TypeIsManaged(PrefService* prefs) {
  DCHECK(prefs);
  const PrefService::Preference* pref_restore =
      prefs->FindPreference(prefs::kRestoreOnStartup);
  DCHECK(pref_restore);
  return pref_restore->IsManaged();
}

// static
bool SessionStartupPref::URLsAreManaged(PrefService* prefs) {
  DCHECK(prefs);
  const PrefService::Preference* pref_urls =
      prefs->FindPreference(prefs::kURLsToRestoreOnStartup);
  DCHECK(pref_urls);
  return pref_urls->IsManaged();
}

// static
bool SessionStartupPref::TypeIsDefault(PrefService* prefs) {
  DCHECK(prefs);
  const PrefService::Preference* pref_restore =
      prefs->FindPreference(prefs::kRestoreOnStartup);
  DCHECK(pref_restore);
  return pref_restore->IsDefaultValue();
}

// static
SessionStartupPref::Type SessionStartupPref::PrefValueToType(int pref_value) {
  switch (pref_value) {
    case kPrefValueLast:     return SessionStartupPref::LAST;
    case kPrefValueURLs:     return SessionStartupPref::URLS;
    case kPrefValueHomePage: return SessionStartupPref::HOMEPAGE;
    default:                 return SessionStartupPref::DEFAULT;
  }
}

SessionStartupPref::SessionStartupPref(Type type) : type(type) {}

SessionStartupPref::~SessionStartupPref() {}