blob: 2786b357fb390dbd93439445f7311c781130cfdd [file] [log] [blame]
// Copyright (c) 2013 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/profile_resetter/resettable_settings_snapshot.h"
#include "base/json/json_writer.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/feedback/feedback_data.h"
#include "chrome/browser/feedback/feedback_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
#include "grit/google_chrome_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
// Feedback bucket labels.
const char kProfileResetPromptBucket[] = "SamplingOfSettingsResetPrompt";
const char kProfileResetWebUIBucket[] = "ProfileResetReport";
// Dictionary keys for feedback report.
const char kDefaultSearchEnginePath[] = "default_search_engine";
const char kEnabledExtensions[] = "enabled_extensions";
const char kHomepageIsNewTabPage[] = "homepage_is_ntp";
const char kHomepagePath[] = "homepage";
const char kStartupTypePath[] = "startup_type";
const char kStartupURLPath[] = "startup_urls";
template <class StringType>
void AddPair(ListValue* list,
const base::string16& key,
const StringType& value) {
DictionaryValue* results = new DictionaryValue();
results->SetString("key", key);
results->SetString("value", value);
list->Append(results);
}
} // namespace
ResettableSettingsSnapshot::ResettableSettingsSnapshot(Profile* profile)
: startup_(SessionStartupPref::GetStartupPref(profile)) {
// URLs are always stored sorted.
std::sort(startup_.urls.begin(), startup_.urls.end());
PrefService* prefs = profile->GetPrefs();
DCHECK(prefs);
homepage_ = prefs->GetString(prefs::kHomePage);
homepage_is_ntp_ = prefs->GetBoolean(prefs::kHomePageIsNewTabPage);
TemplateURLService* service =
TemplateURLServiceFactory::GetForProfile(profile);
DCHECK(service);
TemplateURL* dse = service->GetDefaultSearchProvider();
if (dse)
dse_url_ = dse->url();
ExtensionService* extension_service = profile->GetExtensionService();
DCHECK(extension_service);
const ExtensionSet* enabled_ext = extension_service->extensions();
enabled_extensions_.reserve(enabled_ext->size());
for (ExtensionSet::const_iterator it = enabled_ext->begin();
it != enabled_ext->end(); ++it)
enabled_extensions_.push_back(std::make_pair((*it)->id(), (*it)->name()));
// ExtensionSet is sorted but it seems to be an implementation detail.
std::sort(enabled_extensions_.begin(), enabled_extensions_.end());
}
ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {}
void ResettableSettingsSnapshot::Subtract(
const ResettableSettingsSnapshot& snapshot) {
ExtensionList extensions = base::STLSetDifference<ExtensionList>(
enabled_extensions_, snapshot.enabled_extensions_);
enabled_extensions_.swap(extensions);
}
int ResettableSettingsSnapshot::FindDifferentFields(
const ResettableSettingsSnapshot& snapshot) const {
int bit_mask = 0;
if (startup_.type != snapshot.startup_.type ||
startup_.urls != snapshot.startup_.urls)
bit_mask |= STARTUP_MODE;
if (homepage_is_ntp_ != snapshot.homepage_is_ntp_ ||
homepage_ != snapshot.homepage_)
bit_mask |= HOMEPAGE;
if (dse_url_ != snapshot.dse_url_)
bit_mask |= DSE_URL;
if (enabled_extensions_ != snapshot.enabled_extensions_)
bit_mask |= EXTENSIONS;
COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 15,
add_new_field_here);
return bit_mask;
}
std::string SerializeSettingsReport(const ResettableSettingsSnapshot& snapshot,
int field_mask) {
DictionaryValue dict;
if (field_mask & ResettableSettingsSnapshot::STARTUP_MODE) {
ListValue* list = new ListValue;
const std::vector<GURL>& urls = snapshot.startup_urls();
for (std::vector<GURL>::const_iterator i = urls.begin();
i != urls.end(); ++i)
list->AppendString(i->spec());
dict.Set(kStartupURLPath, list);
dict.SetInteger(kStartupTypePath, snapshot.startup_type());
}
if (field_mask & ResettableSettingsSnapshot::HOMEPAGE) {
dict.SetString(kHomepagePath, snapshot.homepage());
dict.SetBoolean(kHomepageIsNewTabPage, snapshot.homepage_is_ntp());
}
if (field_mask & ResettableSettingsSnapshot::DSE_URL)
dict.SetString(kDefaultSearchEnginePath, snapshot.dse_url());
if (field_mask & ResettableSettingsSnapshot::EXTENSIONS) {
ListValue* list = new ListValue;
const ResettableSettingsSnapshot::ExtensionList& extensions =
snapshot.enabled_extensions();
for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
extensions.begin(); i != extensions.end(); ++i) {
// Replace "\"" to simplify server-side analysis.
std::string ext_name;
base::ReplaceChars(i->second, "\"", "\'", &ext_name);
list->AppendString(i->first + ";" + ext_name);
}
dict.Set(kEnabledExtensions, list);
}
COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 15,
serialize_new_field_here);
std::string json;
base::JSONWriter::Write(&dict, &json);
return json;
}
void SendSettingsFeedback(const std::string& report,
Profile* profile,
SnapshotCaller caller) {
scoped_refptr<FeedbackData> feedback_data = new FeedbackData();
std::string bucket;
switch (caller) {
case PROFILE_RESET_WEBUI:
bucket = kProfileResetWebUIBucket;
break;
case PROFILE_RESET_PROMPT:
bucket = kProfileResetPromptBucket;
break;
}
feedback_data->set_category_tag(bucket);
feedback_data->set_description(report);
feedback_data->set_image(scoped_ptr<std::string>(new std::string));
feedback_data->set_profile(profile);
feedback_data->set_page_url("");
feedback_data->set_user_email("");
feedback_util::SendReport(feedback_data);
}
ListValue* GetReadableFeedback(Profile* profile) {
DCHECK(profile);
ListValue* list = new ListValue;
AddPair(list, l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE),
g_browser_process->GetApplicationLocale());
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_USER_AGENT),
content::GetUserAgent(GURL()));
chrome::VersionInfo version_info;
std::string version = version_info.Version();
version += chrome::VersionInfo::GetVersionStringModifier();
AddPair(list,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
version);
// Add snapshot data.
ResettableSettingsSnapshot snapshot(profile);
const std::vector<GURL>& urls = snapshot.startup_urls();
std::string startup_urls;
for (std::vector<GURL>::const_iterator i = urls.begin();
i != urls.end(); ++i) {
(startup_urls += i->host()) += ' ';
}
if (!startup_urls.empty()) {
startup_urls.erase(startup_urls.end() - 1);
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS),
startup_urls);
}
base::string16 startup_type;
switch (snapshot.startup_type()) {
case SessionStartupPref::DEFAULT:
startup_type = l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_NEWTAB);
break;
case SessionStartupPref::LAST:
startup_type = l10n_util::GetStringUTF16(
IDS_OPTIONS_STARTUP_RESTORE_LAST_SESSION);
break;
case SessionStartupPref::URLS:
startup_type = l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES);
break;
default:
break;
}
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE),
startup_type);
if (!snapshot.homepage().empty()) {
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE),
snapshot.homepage());
}
int is_ntp_message_id = snapshot.homepage_is_ntp() ?
IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_TRUE :
IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_FALSE;
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP),
l10n_util::GetStringUTF16(is_ntp_message_id));
TemplateURLService* service =
TemplateURLServiceFactory::GetForProfile(profile);
DCHECK(service);
TemplateURL* dse = service->GetDefaultSearchProvider();
if (dse) {
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE),
TemplateURLService::GenerateSearchURL(dse).host());
}
const ResettableSettingsSnapshot::ExtensionList& extensions =
snapshot.enabled_extensions();
std::string extension_names;
for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
extensions.begin(); i != extensions.end(); ++i) {
(extension_names += i->second) += '\n';
}
if (!extension_names.empty()) {
extension_names.erase(extension_names.end() - 1);
AddPair(list,
l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS),
extension_names);
}
return list;
}