Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / profile_resetter / resettable_settings_snapshot.cc
blobda825508c93646f182b78ebe06907fe6e4bf9e66
1 // Copyright (c) 2013 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/profile_resetter/resettable_settings_snapshot.h"
7 #include "base/json/json_writer.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/synchronization/cancellation_flag.h"
12 #include "base/values.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/search_engines/template_url_service_factory.h"
16 #include "chrome/common/chrome_content_client.h"
17 #include "chrome/common/chrome_version_info.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/grit/chromium_strings.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "components/feedback/feedback_data.h"
22 #include "components/feedback/feedback_util.h"
23 #include "components/search_engines/template_url_service.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "ui/base/l10n/l10n_util.h"
28 using feedback::FeedbackData;
30 namespace {
32 // Feedback bucket labels.
33 const char kProfileResetPromptBucket[] = "SamplingOfSettingsResetPrompt";
34 const char kProfileResetWebUIBucket[] = "ProfileResetReport";
36 // Dictionary keys for feedback report.
37 const char kDefaultSearchEnginePath[] = "default_search_engine";
38 const char kEnabledExtensions[] = "enabled_extensions";
39 const char kHomepageIsNewTabPage[] = "homepage_is_ntp";
40 const char kHomepagePath[] = "homepage";
41 const char kShortcuts[] = "shortcuts";
42 const char kShowHomeButton[] = "show_home_button";
43 const char kStartupTypePath[] = "startup_type";
44 const char kStartupURLPath[] = "startup_urls";
46 template <class StringType>
47 void AddPair(base::ListValue* list,
48 const base::string16& key,
49 const StringType& value) {
50 base::DictionaryValue* results = new base::DictionaryValue();
51 results->SetString("key", key);
52 results->SetString("value", value);
53 list->Append(results);
56 } // namespace
58 ResettableSettingsSnapshot::ResettableSettingsSnapshot(
59 Profile* profile)
60 : startup_(SessionStartupPref::GetStartupPref(profile)),
61 shortcuts_determined_(false),
62 weak_ptr_factory_(this) {
63 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
64 // URLs are always stored sorted.
65 std::sort(startup_.urls.begin(), startup_.urls.end());
67 PrefService* prefs = profile->GetPrefs();
68 DCHECK(prefs);
69 homepage_ = prefs->GetString(prefs::kHomePage);
70 homepage_is_ntp_ = prefs->GetBoolean(prefs::kHomePageIsNewTabPage);
71 show_home_button_ = prefs->GetBoolean(prefs::kShowHomeButton);
73 TemplateURLService* service =
74 TemplateURLServiceFactory::GetForProfile(profile);
75 DCHECK(service);
76 TemplateURL* dse = service->GetDefaultSearchProvider();
77 if (dse)
78 dse_url_ = dse->url();
80 const extensions::ExtensionSet& enabled_ext =
81 extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
82 enabled_extensions_.reserve(enabled_ext.size());
84 for (extensions::ExtensionSet::const_iterator it = enabled_ext.begin();
85 it != enabled_ext.end(); ++it)
86 enabled_extensions_.push_back(std::make_pair((*it)->id(), (*it)->name()));
88 // ExtensionSet is sorted but it seems to be an implementation detail.
89 std::sort(enabled_extensions_.begin(), enabled_extensions_.end());
92 ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {
93 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
94 if (cancellation_flag_.get())
95 cancellation_flag_->data.Set();
98 void ResettableSettingsSnapshot::Subtract(
99 const ResettableSettingsSnapshot& snapshot) {
100 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
101 ExtensionList extensions = base::STLSetDifference<ExtensionList>(
102 enabled_extensions_, snapshot.enabled_extensions_);
103 enabled_extensions_.swap(extensions);
106 int ResettableSettingsSnapshot::FindDifferentFields(
107 const ResettableSettingsSnapshot& snapshot) const {
108 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
109 int bit_mask = 0;
111 if (startup_.type != snapshot.startup_.type ||
112 startup_.urls != snapshot.startup_.urls)
113 bit_mask |= STARTUP_MODE;
115 if (homepage_is_ntp_ != snapshot.homepage_is_ntp_ ||
116 homepage_ != snapshot.homepage_ ||
117 show_home_button_ != snapshot.show_home_button_)
118 bit_mask |= HOMEPAGE;
120 if (dse_url_ != snapshot.dse_url_)
121 bit_mask |= DSE_URL;
123 if (enabled_extensions_ != snapshot.enabled_extensions_)
124 bit_mask |= EXTENSIONS;
126 if (shortcuts_ != snapshot.shortcuts_)
127 bit_mask |= SHORTCUTS;
129 static_assert(ResettableSettingsSnapshot::ALL_FIELDS == 31,
130 "new field needs to be added here");
132 return bit_mask;
135 void ResettableSettingsSnapshot::RequestShortcuts(
136 const base::Closure& callback) {
137 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
138 DCHECK(!cancellation_flag_.get() && !shortcuts_determined());
140 cancellation_flag_ = new SharedCancellationFlag;
141 content::BrowserThread::PostTaskAndReplyWithResult(
142 content::BrowserThread::FILE,
143 FROM_HERE,
144 base::Bind(&GetChromeLaunchShortcuts, cancellation_flag_),
145 base::Bind(&ResettableSettingsSnapshot::SetShortcutsAndReport,
146 weak_ptr_factory_.GetWeakPtr(),
147 callback));
150 void ResettableSettingsSnapshot::SetShortcutsAndReport(
151 const base::Closure& callback,
152 const std::vector<ShortcutCommand>& shortcuts) {
153 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
154 shortcuts_ = shortcuts;
155 shortcuts_determined_ = true;
156 cancellation_flag_ = NULL;
158 if (!callback.is_null())
159 callback.Run();
162 std::string SerializeSettingsReport(const ResettableSettingsSnapshot& snapshot,
163 int field_mask) {
164 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
165 base::DictionaryValue dict;
167 if (field_mask & ResettableSettingsSnapshot::STARTUP_MODE) {
168 base::ListValue* list = new base::ListValue;
169 const std::vector<GURL>& urls = snapshot.startup_urls();
170 for (std::vector<GURL>::const_iterator i = urls.begin();
171 i != urls.end(); ++i)
172 list->AppendString(i->spec());
173 dict.Set(kStartupURLPath, list);
174 dict.SetInteger(kStartupTypePath, snapshot.startup_type());
177 if (field_mask & ResettableSettingsSnapshot::HOMEPAGE) {
178 dict.SetString(kHomepagePath, snapshot.homepage());
179 dict.SetBoolean(kHomepageIsNewTabPage, snapshot.homepage_is_ntp());
180 dict.SetBoolean(kShowHomeButton, snapshot.show_home_button());
183 if (field_mask & ResettableSettingsSnapshot::DSE_URL)
184 dict.SetString(kDefaultSearchEnginePath, snapshot.dse_url());
186 if (field_mask & ResettableSettingsSnapshot::EXTENSIONS) {
187 base::ListValue* list = new base::ListValue;
188 const ResettableSettingsSnapshot::ExtensionList& extensions =
189 snapshot.enabled_extensions();
190 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
191 extensions.begin(); i != extensions.end(); ++i) {
192 // Replace "\"" to simplify server-side analysis.
193 std::string ext_name;
194 base::ReplaceChars(i->second, "\"", "\'", &ext_name);
195 list->AppendString(i->first + ";" + ext_name);
197 dict.Set(kEnabledExtensions, list);
200 if (field_mask & ResettableSettingsSnapshot::SHORTCUTS) {
201 base::ListValue* list = new base::ListValue;
202 const std::vector<ShortcutCommand>& shortcuts = snapshot.shortcuts();
203 for (std::vector<ShortcutCommand>::const_iterator i = shortcuts.begin();
204 i != shortcuts.end(); ++i) {
205 base::string16 arguments;
206 // Replace "\"" to simplify server-side analysis.
207 base::ReplaceChars(i->second, base::ASCIIToUTF16("\""),
208 base::ASCIIToUTF16("\'"), &arguments);
209 list->AppendString(arguments);
211 dict.Set(kShortcuts, list);
214 static_assert(ResettableSettingsSnapshot::ALL_FIELDS == 31,
215 "new field needs to be serialized here");
217 std::string json;
218 base::JSONWriter::Write(dict, &json);
219 return json;
222 void SendSettingsFeedback(const std::string& report,
223 Profile* profile,
224 SnapshotCaller caller) {
225 scoped_refptr<FeedbackData> feedback_data = new FeedbackData();
226 std::string bucket;
227 switch (caller) {
228 case PROFILE_RESET_WEBUI:
229 bucket = kProfileResetWebUIBucket;
230 break;
231 case PROFILE_RESET_PROMPT:
232 bucket = kProfileResetPromptBucket;
233 break;
235 feedback_data->set_category_tag(bucket);
236 feedback_data->set_description(report);
238 feedback_data->set_image(make_scoped_ptr(new std::string));
239 feedback_data->set_context(profile);
241 feedback_data->set_page_url("");
242 feedback_data->set_user_email("");
244 feedback_util::SendReport(feedback_data);
247 scoped_ptr<base::ListValue> GetReadableFeedbackForSnapshot(
248 Profile* profile,
249 const ResettableSettingsSnapshot& snapshot) {
250 DCHECK(profile);
251 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
252 scoped_ptr<base::ListValue> list(new base::ListValue);
253 AddPair(list.get(),
254 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_LOCALE),
255 g_browser_process->GetApplicationLocale());
256 AddPair(list.get(),
257 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_USER_AGENT),
258 GetUserAgent());
259 chrome::VersionInfo version_info;
260 std::string version = version_info.Version();
261 version += chrome::VersionInfo::GetVersionStringModifier();
262 AddPair(list.get(),
263 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
264 version);
266 // Add snapshot data.
267 const std::vector<GURL>& urls = snapshot.startup_urls();
268 std::string startup_urls;
269 for (std::vector<GURL>::const_iterator i = urls.begin();
270 i != urls.end(); ++i) {
271 if (!startup_urls.empty())
272 startup_urls += ' ';
273 startup_urls += i->host();
275 if (!startup_urls.empty()) {
276 AddPair(list.get(),
277 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS),
278 startup_urls);
281 base::string16 startup_type;
282 switch (snapshot.startup_type()) {
283 case SessionStartupPref::DEFAULT:
284 startup_type = l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_NEWTAB);
285 break;
286 case SessionStartupPref::LAST:
287 startup_type = l10n_util::GetStringUTF16(
288 IDS_OPTIONS_STARTUP_RESTORE_LAST_SESSION);
289 break;
290 case SessionStartupPref::URLS:
291 startup_type = l10n_util::GetStringUTF16(IDS_OPTIONS_STARTUP_SHOW_PAGES);
292 break;
293 default:
294 break;
296 AddPair(list.get(),
297 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE),
298 startup_type);
300 if (!snapshot.homepage().empty()) {
301 AddPair(list.get(),
302 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE),
303 snapshot.homepage());
306 int is_ntp_message_id = snapshot.homepage_is_ntp() ?
307 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_TRUE :
308 IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP_FALSE;
309 AddPair(list.get(),
310 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE_IS_NTP),
311 l10n_util::GetStringUTF16(is_ntp_message_id));
313 int show_home_button_id = snapshot.show_home_button() ?
314 IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON_TRUE :
315 IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON_FALSE;
316 AddPair(
317 list.get(),
318 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHOW_HOME_BUTTON),
319 l10n_util::GetStringUTF16(show_home_button_id));
321 TemplateURLService* service =
322 TemplateURLServiceFactory::GetForProfile(profile);
323 DCHECK(service);
324 TemplateURL* dse = service->GetDefaultSearchProvider();
325 if (dse) {
326 AddPair(list.get(),
327 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_DSE),
328 dse->GenerateSearchURL(service->search_terms_data()).host());
331 if (snapshot.shortcuts_determined()) {
332 base::string16 shortcut_targets;
333 const std::vector<ShortcutCommand>& shortcuts = snapshot.shortcuts();
334 for (std::vector<ShortcutCommand>::const_iterator i =
335 shortcuts.begin(); i != shortcuts.end(); ++i) {
336 if (!shortcut_targets.empty())
337 shortcut_targets += base::ASCIIToUTF16("\n");
338 shortcut_targets += base::ASCIIToUTF16("chrome.exe ");
339 shortcut_targets += i->second;
341 if (!shortcut_targets.empty()) {
342 AddPair(list.get(),
343 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS),
344 shortcut_targets);
346 } else {
347 AddPair(list.get(),
348 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS),
349 l10n_util::GetStringUTF16(
350 IDS_RESET_PROFILE_SETTINGS_PROCESSING_SHORTCUTS));
353 const ResettableSettingsSnapshot::ExtensionList& extensions =
354 snapshot.enabled_extensions();
355 std::string extension_names;
356 for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
357 extensions.begin(); i != extensions.end(); ++i) {
358 if (!extension_names.empty())
359 extension_names += '\n';
360 extension_names += i->second;
362 if (!extension_names.empty()) {
363 AddPair(list.get(),
364 l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS),
365 extension_names);
367 return list.Pass();