Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / profile_resetter / resettable_settings_snapshot.cc
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.
4
5 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
6
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/generated_resources.h"
20 #include "chrome/grit/google_chrome_strings.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"
27
28 using feedback::FeedbackData;
29
30 namespace {
31
32 // Feedback bucket labels.
33 const char kProfileResetPromptBucket[] = "SamplingOfSettingsResetPrompt";
34 const char kProfileResetWebUIBucket[] = "ProfileResetReport";
35
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";
45
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);
54 }
55
56 }  // namespace
57
58 ResettableSettingsSnapshot::ResettableSettingsSnapshot(
59     Profile* profile)
60     : startup_(SessionStartupPref::GetStartupPref(profile)),
61       shortcuts_determined_(false),
62       weak_ptr_factory_(this) {
63   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
64   // URLs are always stored sorted.
65   std::sort(startup_.urls.begin(), startup_.urls.end());
66
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);
72
73   TemplateURLService* service =
74       TemplateURLServiceFactory::GetForProfile(profile);
75   DCHECK(service);
76   TemplateURL* dse = service->GetDefaultSearchProvider();
77   if (dse)
78     dse_url_ = dse->url();
79
80   const extensions::ExtensionSet& enabled_ext =
81       extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
82   enabled_extensions_.reserve(enabled_ext.size());
83
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()));
87
88   // ExtensionSet is sorted but it seems to be an implementation detail.
89   std::sort(enabled_extensions_.begin(), enabled_extensions_.end());
90 }
91
92 ResettableSettingsSnapshot::~ResettableSettingsSnapshot() {
93   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
94   if (cancellation_flag_.get())
95     cancellation_flag_->data.Set();
96 }
97
98 void ResettableSettingsSnapshot::Subtract(
99     const ResettableSettingsSnapshot& snapshot) {
100   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
101   ExtensionList extensions = base::STLSetDifference<ExtensionList>(
102       enabled_extensions_, snapshot.enabled_extensions_);
103   enabled_extensions_.swap(extensions);
104 }
105
106 int ResettableSettingsSnapshot::FindDifferentFields(
107     const ResettableSettingsSnapshot& snapshot) const {
108   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
109   int bit_mask = 0;
110
111   if (startup_.type != snapshot.startup_.type ||
112       startup_.urls != snapshot.startup_.urls)
113     bit_mask |= STARTUP_MODE;
114
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;
119
120   if (dse_url_ != snapshot.dse_url_)
121     bit_mask |= DSE_URL;
122
123   if (enabled_extensions_ != snapshot.enabled_extensions_)
124     bit_mask |= EXTENSIONS;
125
126   if (shortcuts_ != snapshot.shortcuts_)
127     bit_mask |= SHORTCUTS;
128
129   COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 31,
130                  add_new_field_here);
131
132   return bit_mask;
133 }
134
135 void ResettableSettingsSnapshot::RequestShortcuts(
136     const base::Closure& callback) {
137   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
138   DCHECK(!cancellation_flag_.get() && !shortcuts_determined());
139
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));
148 }
149
150 void ResettableSettingsSnapshot::SetShortcutsAndReport(
151     const base::Closure& callback,
152     const std::vector<ShortcutCommand>& shortcuts) {
153   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
154   shortcuts_ = shortcuts;
155   shortcuts_determined_ = true;
156   cancellation_flag_ = NULL;
157
158   if (!callback.is_null())
159     callback.Run();
160 }
161
162 std::string SerializeSettingsReport(const ResettableSettingsSnapshot& snapshot,
163                                     int field_mask) {
164   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
165   base::DictionaryValue dict;
166
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());
175   }
176
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());
181   }
182
183   if (field_mask & ResettableSettingsSnapshot::DSE_URL)
184     dict.SetString(kDefaultSearchEnginePath, snapshot.dse_url());
185
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);
196     }
197     dict.Set(kEnabledExtensions, list);
198   }
199
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);
210     }
211     dict.Set(kShortcuts, list);
212   }
213
214   COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 31,
215                  serialize_new_field_here);
216
217   std::string json;
218   base::JSONWriter::Write(&dict, &json);
219   return json;
220 }
221
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;
234   }
235   feedback_data->set_category_tag(bucket);
236   feedback_data->set_description(report);
237
238   feedback_data->set_image(make_scoped_ptr(new std::string));
239   feedback_data->set_context(profile);
240
241   feedback_data->set_page_url("");
242   feedback_data->set_user_email("");
243
244   feedback_util::SendReport(feedback_data);
245 }
246
247 scoped_ptr<base::ListValue> GetReadableFeedbackForSnapshot(
248     Profile* profile,
249     const ResettableSettingsSnapshot& snapshot) {
250   DCHECK(profile);
251   DCHECK(content::BrowserThread::CurrentlyOn(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);
265
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();
274   }
275   if (!startup_urls.empty()) {
276     AddPair(list.get(),
277             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_URLS),
278             startup_urls);
279   }
280
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;
295   }
296   AddPair(list.get(),
297           l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_STARTUP_TYPE),
298           startup_type);
299
300   if (!snapshot.homepage().empty()) {
301     AddPair(list.get(),
302             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_HOMEPAGE),
303             snapshot.homepage());
304   }
305
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));
312
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));
320
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());
329   }
330
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;
340     }
341     if (!shortcut_targets.empty()) {
342       AddPair(list.get(),
343               l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_SHORTCUTS),
344               shortcut_targets);
345     }
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));
351   }
352
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;
361   }
362   if (!extension_names.empty()) {
363     AddPair(list.get(),
364             l10n_util::GetStringUTF16(IDS_RESET_PROFILE_SETTINGS_EXTENSIONS),
365             extension_names);
366   }
367   return list.Pass();
368 }