1// Copyright (c) 2011 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/ui/webui/flags_ui.h"
6
7#include <string>
8
9#include "base/memory/singleton.h"
10#include "base/values.h"
11#include "chrome/browser/about_flags.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/prefs/pref_service.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
17#include "chrome/common/jstemplate_builder.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/common/url_constants.h"
20#include "content/browser/browser_thread.h"
21#include "content/browser/tab_contents/tab_contents.h"
22#include "grit/browser_resources.h"
23#include "grit/chromium_strings.h"
24#include "grit/generated_resources.h"
25#include "grit/theme_resources.h"
26#include "ui/base/l10n/l10n_util.h"
27#include "ui/base/resource/resource_bundle.h"
28
29#if defined(OS_CHROMEOS)
30#include "chrome/browser/chromeos/user_cros_settings_provider.h"
31#include "chrome/browser/chromeos/login/user_manager.h"
32#endif
33
34namespace {
35
36///////////////////////////////////////////////////////////////////////////////
37//
38// FlagsUIHTMLSource
39//
40///////////////////////////////////////////////////////////////////////////////
41
42class FlagsUIHTMLSource : public ChromeURLDataManager::DataSource {
43 public:
44  FlagsUIHTMLSource()
45      : DataSource(chrome::kChromeUIFlagsHost, MessageLoop::current()) {}
46
47  // Called when the network layer has requested a resource underneath
48  // the path we registered.
49  virtual void StartDataRequest(const std::string& path,
50                                bool is_incognito,
51                                int request_id);
52  virtual std::string GetMimeType(const std::string&) const {
53    return "text/html";
54  }
55
56 private:
57  ~FlagsUIHTMLSource() {}
58
59  DISALLOW_COPY_AND_ASSIGN(FlagsUIHTMLSource);
60};
61
62void FlagsUIHTMLSource::StartDataRequest(const std::string& path,
63                                        bool is_incognito,
64                                        int request_id) {
65  // Strings used in the JsTemplate file.
66  DictionaryValue localized_strings;
67  localized_strings.SetString("flagsLongTitle",
68      l10n_util::GetStringUTF16(IDS_FLAGS_LONG_TITLE));
69  localized_strings.SetString("flagsTableTitle",
70      l10n_util::GetStringUTF16(IDS_FLAGS_TABLE_TITLE));
71  localized_strings.SetString("flagsNoExperimentsAvailable",
72      l10n_util::GetStringUTF16(IDS_FLAGS_NO_EXPERIMENTS_AVAILABLE));
73  localized_strings.SetString("flagsWarningHeader", l10n_util::GetStringUTF16(
74      IDS_FLAGS_WARNING_HEADER));
75  localized_strings.SetString("flagsBlurb", l10n_util::GetStringUTF16(
76      IDS_FLAGS_WARNING_TEXT));
77  localized_strings.SetString("flagsRestartNotice", l10n_util::GetStringFUTF16(
78      IDS_FLAGS_RELAUNCH_NOTICE,
79      l10n_util::GetStringUTF16(
80#if defined(OS_CHROMEOS)
81          IDS_PRODUCT_OS_NAME
82#else
83          IDS_PRODUCT_NAME
84#endif
85          )));
86  localized_strings.SetString("flagsRestartButton",
87      l10n_util::GetStringUTF16(IDS_FLAGS_RELAUNCH_BUTTON));
88  localized_strings.SetString("disable",
89      l10n_util::GetStringUTF16(IDS_FLAGS_DISABLE));
90  localized_strings.SetString("enable",
91      l10n_util::GetStringUTF16(IDS_FLAGS_ENABLE));
92
93  base::StringPiece html =
94      ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_FLAGS_HTML);
95#if defined (OS_CHROMEOS)
96  if (!chromeos::UserManager::Get()->current_user_is_owner()) {
97    html = ResourceBundle::GetSharedInstance().GetRawDataResource(
98        IDR_FLAGS_HTML_WARNING);
99
100    // Set the strings to show which user can actually change the flags
101    localized_strings.SetString("ownerOnly", l10n_util::GetStringUTF16(
102        IDS_OPTIONS_ACCOUNTS_OWNER_ONLY));
103    localized_strings.SetString("ownerUserId", UTF8ToUTF16(
104        chromeos::UserCrosSettingsProvider::cached_owner()));
105  }
106#endif
107  static const base::StringPiece flags_html(html);
108  ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
109
110  std::string full_html(flags_html.data(), flags_html.size());
111  jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
112  jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
113  jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
114  jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
115
116  scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
117  html_bytes->data.resize(full_html.size());
118  std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
119
120  SendResponse(request_id, html_bytes);
121}
122
123////////////////////////////////////////////////////////////////////////////////
124//
125// FlagsDOMHandler
126//
127////////////////////////////////////////////////////////////////////////////////
128
129// The handler for Javascript messages for the about:flags page.
130class FlagsDOMHandler : public WebUIMessageHandler {
131 public:
132  FlagsDOMHandler() {}
133  virtual ~FlagsDOMHandler() {}
134
135  // WebUIMessageHandler implementation.
136  virtual void RegisterMessages();
137
138  // Callback for the "requestFlagsExperiments" message.
139  void HandleRequestFlagsExperiments(const ListValue* args);
140
141  // Callback for the "enableFlagsExperiment" message.
142  void HandleEnableFlagsExperimentMessage(const ListValue* args);
143
144  // Callback for the "restartBrowser" message. Restores all tabs on restart.
145  void HandleRestartBrowser(const ListValue* args);
146
147 private:
148  DISALLOW_COPY_AND_ASSIGN(FlagsDOMHandler);
149};
150
151void FlagsDOMHandler::RegisterMessages() {
152  web_ui_->RegisterMessageCallback("requestFlagsExperiments",
153      NewCallback(this, &FlagsDOMHandler::HandleRequestFlagsExperiments));
154  web_ui_->RegisterMessageCallback("enableFlagsExperiment",
155      NewCallback(this, &FlagsDOMHandler::HandleEnableFlagsExperimentMessage));
156  web_ui_->RegisterMessageCallback("restartBrowser",
157      NewCallback(this, &FlagsDOMHandler::HandleRestartBrowser));
158}
159
160void FlagsDOMHandler::HandleRequestFlagsExperiments(const ListValue* args) {
161  DictionaryValue results;
162  results.Set("flagsExperiments",
163              about_flags::GetFlagsExperimentsData(
164                  g_browser_process->local_state()));
165  results.SetBoolean("needsRestart",
166                     about_flags::IsRestartNeededToCommitChanges());
167  web_ui_->CallJavascriptFunction("returnFlagsExperiments", results);
168}
169
170void FlagsDOMHandler::HandleEnableFlagsExperimentMessage(
171    const ListValue* args) {
172  DCHECK_EQ(2u, args->GetSize());
173  if (args->GetSize() != 2)
174    return;
175
176  std::string experiment_internal_name;
177  std::string enable_str;
178  if (!args->GetString(0, &experiment_internal_name) ||
179      !args->GetString(1, &enable_str))
180    return;
181
182  about_flags::SetExperimentEnabled(
183      g_browser_process->local_state(),
184      experiment_internal_name,
185      enable_str == "true");
186}
187
188void FlagsDOMHandler::HandleRestartBrowser(const ListValue* args) {
189#if !defined(OS_CHROMEOS)
190  // Set the flag to restore state after the restart.
191  PrefService* pref_service = g_browser_process->local_state();
192  pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
193  BrowserList::CloseAllBrowsersAndExit();
194#else
195  // For CrOS instead of browser restart (which is not supported) perform a full
196  // sign out. Session will be only restored is user has that setting set.
197  // Same session restore behavior happens in case of full restart after update.
198  BrowserList::GetLastActive()->Exit();
199#endif
200}
201
202}  // namespace
203
204///////////////////////////////////////////////////////////////////////////////
205//
206// FlagsUI
207//
208///////////////////////////////////////////////////////////////////////////////
209
210FlagsUI::FlagsUI(TabContents* contents) : WebUI(contents) {
211  AddMessageHandler((new FlagsDOMHandler())->Attach(this));
212
213  FlagsUIHTMLSource* html_source = new FlagsUIHTMLSource();
214
215  // Set up the about:flags source.
216  contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
217}
218
219// static
220RefCountedMemory* FlagsUI::GetFaviconResourceBytes() {
221  return ResourceBundle::GetSharedInstance().
222      LoadDataResourceBytes(IDR_FLAGS);
223}
224
225// static
226void FlagsUI::RegisterPrefs(PrefService* prefs) {
227  prefs->RegisterListPref(prefs::kEnabledLabsExperiments);
228}
229