Basic code structures for rewritten options dialogs as DOM UI. Also includes the initial implementation of System page in ChromeOS options.


BUG=chromium-os:
TEST=none yet, work in progress

Review URL: http://codereview.chromium.org/2781005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50117 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 1c3f1bb..330e0df 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -38,11 +38,12 @@
       <include name="IDR_CREDITS_HTML" file="resources\about_credits.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_HISTORY_HTML" file="resources\history.html" flattenhtml="true" type="BINDATA" />
       <if expr="pp_ifdef('chromeos') or pp_ifdef('toolkit_views')">
-  <include name="IDR_FILEBROWSE_HTML" file="resources\filebrowse.html" flattenhtml="true" type="BINDATA" />
-  <include name="IDR_OS_CREDITS_HTML" file="resources\about_os_credits.html" flattenhtml="true" type="BINDATA" />
-  <include name="IDR_MEDIAPLAYER_HTML" file="resources\mediaplayer.html" flattenhtml="true" type="BINDATA" />
-  <include name="IDR_MEDIAPLAYERPLAYLIST_HTML" file="resources\playlist.html" flattenhtml="true" type="BINDATA" />
-  <include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_FILEBROWSE_HTML" file="resources\filebrowse.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_OS_CREDITS_HTML" file="resources\about_os_credits.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_MEDIAPLAYER_HTML" file="resources\mediaplayer.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_MEDIAPLAYERPLAYLIST_HTML" file="resources\playlist.html" flattenhtml="true" type="BINDATA" />   
+        <include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_OPTIONS_HTML" file="resources\options.html" flattenhtml="true" type="BINDATA" />
       </if>
       <include name="IDR_APP_GALLERY_ICON" file="resources\app_gallery_icon.png" type="BINDATA" />
       <include name="IDR_BOOKMARKS_MANIFEST" file="resources\bookmark_manager\manifest.json" type="BINDATA" />
diff --git a/chrome/browser/chromeos/dom_ui/system_options_handler.cc b/chrome/browser/chromeos/dom_ui/system_options_handler.cc
new file mode 100644
index 0000000..32469025
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/system_options_handler.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2010 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/chromeos/dom_ui/system_options_handler.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/i18n/time_formatting.h"
+#include "base/stl_util-inl.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/notification_service.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+
+static const char* kTimeZonesUtf8[] = {
+    "Pacific/Samoa",
+    "US/Hawaii",
+    "US/Alaska",
+    "US/Pacific",
+    "US/Mountain",
+    "US/Central",
+    "US/Eastern",
+    "America/Santiago",
+    "America/Sao_Paulo",
+    "Atlantic/South_Georgia",
+    "Atlantic/Cape_Verde",
+    "Europe/London",
+    "Europe/Rome",
+    "Europe/Helsinki",
+    "Europe/Moscow",
+    "Asia/Dubai",
+    "Asia/Karachi",
+    "Asia/Dhaka",
+    "Asia/Bangkok",
+    "Asia/Hong_Kong",
+    "Asia/Tokyo",
+    "Australia/Sydney",
+    "Asia/Magadan",
+    "Pacific/Auckland" };
+
+SystemOptionsHandler::SystemOptionsHandler() {
+  // TODO(chocobo): For now, add all the GMT timezones.
+  // We may eventually want to use icu::TimeZone::createEnumeration()
+  // to list all the timezones and pick the ones we want to show.
+  // NOTE: This currently does not handle daylight savings properly
+  // b/c this is just a manually selected list of timezones that
+  // happen to span the GMT-11 to GMT+12 Today. When daylight savings
+  // kick in, this list might have more than one timezone in the same
+  // GMT bucket.
+  for (size_t i = 0; i < arraysize(kTimeZonesUtf8); i++) {
+    timezones_.push_back(icu::TimeZone::createTimeZone(
+        icu::UnicodeString::fromUTF8(kTimeZonesUtf8[i])));
+  }
+}
+
+SystemOptionsHandler::~SystemOptionsHandler() {
+  STLDeleteElements(&timezones_);
+}
+
+void SystemOptionsHandler::GetLocalizedValues(
+    DictionaryValue* localized_strings) {
+  DCHECK(localized_strings);
+  // System page - ChromeOS
+  localized_strings->SetString(L"datetime_title",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME));
+  localized_strings->SetString(L"timezone",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION));
+
+  localized_strings->SetString(L"touchpad",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_TOUCHPAD));
+  localized_strings->SetString(L"enable_tap_to_click",
+      l10n_util::GetString(
+          IDS_OPTIONS_SETTINGS_TAP_TO_CLICK_ENABLED_DESCRIPTION));
+  localized_strings->SetString(L"enable_vert_edge_scroll",
+      l10n_util::GetString(
+          IDS_OPTIONS_SETTINGS_VERT_EDGE_SCROLL_ENABLED_DESCRIPTION));
+  localized_strings->SetString(L"sensitivity",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_SENSITIVITY_DESCRIPTION));
+  localized_strings->SetString(L"speed_factor",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_SPEED_FACTOR_DESCRIPTION));
+
+  localized_strings->SetString(L"language",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_LANGUAGE));
+  localized_strings->SetString(L"language_customize",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_LANGUAGES_CUSTOMIZE));
+
+  localized_strings->SetString(L"accessibility_title",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_SECTION_TITLE_ACCESSIBILITY));
+  localized_strings->SetString(L"accessibility",
+      l10n_util::GetString(IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DESCRIPTION));
+
+  localized_strings->Set(L"timezoneMap", GetTimezoneMap());
+}
+
+DictionaryValue* SystemOptionsHandler::GetTimezoneMap() {
+  DictionaryValue* timezoneMap = new DictionaryValue();
+  for (std::vector<icu::TimeZone*>::iterator iter = timezones_.begin();
+       iter != timezones_.end(); ++iter) {
+    const icu::TimeZone* timezone = *iter;
+    timezoneMap->SetString(GetTimezoneID(timezone).c_str(),
+                           GetTimezoneName(timezone));
+  }
+  return timezoneMap;
+}
+
+std::string SystemOptionsHandler::GetTimezoneName(
+    const icu::TimeZone* timezone) {
+  DCHECK(timezone);
+  icu::UnicodeString name;
+  timezone->getDisplayName(name);
+  std::string output;
+  UTF16ToUTF8(name.getBuffer(), name.length(), &output);
+  int hour_offset = timezone->getRawOffset() / 3600000;
+  const char* format;
+  if (hour_offset == 0)
+    format = "(GMT) ";
+  else
+    format = "(GMT%+d) ";
+
+  return StringPrintf(format, hour_offset) + output;
+}
+
+std::wstring SystemOptionsHandler::GetTimezoneID(
+    const icu::TimeZone* timezone) {
+  DCHECK(timezone);
+  icu::UnicodeString id;
+  timezone->getID(id);
+  std::wstring output;
+  UTF16ToWide(id.getBuffer(), id.length(), &output);
+  return output;
+}
diff --git a/chrome/browser/chromeos/dom_ui/system_options_handler.h b/chrome/browser/chromeos/dom_ui/system_options_handler.h
new file mode 100644
index 0000000..488eccdd3
--- /dev/null
+++ b/chrome/browser/chromeos/dom_ui/system_options_handler.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_DOM_UI_SYSTEM_OPTIONS_HANDLER_H_
+#define CHROME_BROWSER_CHROMEOS_DOM_UI_SYSTEM_OPTIONS_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "chrome/browser/dom_ui/options_ui.h"
+#include "third_party/icu/public/i18n/unicode/timezone.h"
+
+// ChromeOS system options page UI handler.
+class SystemOptionsHandler : public OptionsPageUIHandler {
+ public:
+  SystemOptionsHandler();
+  virtual ~SystemOptionsHandler();
+
+  // OptionsUIHandler implementation.
+  virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+
+ private:
+  // Creates the map of timezones used by the options page.
+  DictionaryValue* GetTimezoneMap();
+
+  // Gets timezone name.
+  std::string GetTimezoneName(const icu::TimeZone* timezone);
+
+  // Gets timezone ID which is also used as timezone pref value.
+  std::wstring GetTimezoneID(const icu::TimeZone* timezone);
+
+  // Timezones.
+  std::vector<icu::TimeZone*> timezones_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemOptionsHandler);
+};
+
+#endif  // CHROME_BROWSER_CHROMEOS_DOM_UI_SYSTEM_OPTIONS_HANDLER_H_
diff --git a/chrome/browser/dom_ui/core_options_handler.cc b/chrome/browser/dom_ui/core_options_handler.cc
new file mode 100644
index 0000000..3aa1587
--- /dev/null
+++ b/chrome/browser/dom_ui/core_options_handler.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2010 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/dom_ui/core_options_handler.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/browser/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+
+CoreOptionsHandler::CoreOptionsHandler() {
+}
+
+void CoreOptionsHandler::GetLocalizedValues(
+    DictionaryValue* localized_strings) {
+  DCHECK(localized_strings);
+  // Main
+  localized_strings->SetString(L"title",
+      l10n_util::GetStringF(IDS_OPTIONS_DIALOG_TITLE,
+          l10n_util::GetString(IDS_PRODUCT_NAME)));
+
+#if defined(OS_CHROMEOS)
+  localized_strings->SetString(L"systemPage",
+      l10n_util::GetString(IDS_OPTIONS_SYSTEM_TAB_LABEL));
+  localized_strings->SetString(L"internetPage",
+      l10n_util::GetString(IDS_OPTIONS_INTERNET_TAB_LABEL));
+#endif
+
+  localized_strings->SetString(L"basicsPage",
+      l10n_util::GetString(IDS_OPTIONS_GENERAL_TAB_LABEL));
+  localized_strings->SetString(L"personalStuffPage",
+      l10n_util::GetString(IDS_OPTIONS_CONTENT_TAB_LABEL));
+  localized_strings->SetString(L"underHoodPage",
+      l10n_util::GetString(IDS_OPTIONS_ADVANCED_TAB_LABEL));
+}
+
+void CoreOptionsHandler::Observe(NotificationType type,
+                                 const NotificationSource& source,
+                                 const NotificationDetails& details) {
+  if (type == NotificationType::PREF_CHANGED)
+    NotifyPrefChanged(Details<std::wstring>(details).ptr());
+}
+
+void CoreOptionsHandler::RegisterMessages() {
+  dom_ui_->RegisterMessageCallback("fetchPrefs",
+      NewCallback(this, &CoreOptionsHandler::HandleFetchPrefs));
+  dom_ui_->RegisterMessageCallback("observePrefs",
+      NewCallback(this, &CoreOptionsHandler::HandleFetchPrefs));
+  dom_ui_->RegisterMessageCallback("setBooleanPref",
+      NewCallback(this, &CoreOptionsHandler::HandleSetBooleanPref));
+  dom_ui_->RegisterMessageCallback("setIntegerPref",
+      NewCallback(this, &CoreOptionsHandler::HandleSetIntegerPref));
+  dom_ui_->RegisterMessageCallback("setStringPref",
+      NewCallback(this, &CoreOptionsHandler::HandleSetStringPref));
+}
+
+
+void CoreOptionsHandler::HandleFetchPrefs(const Value* value) {
+  if (!value || !value->IsType(Value::TYPE_LIST))
+    return;
+
+  const ListValue* param_values = static_cast<const ListValue*>(value);
+
+  // First param is name of callback function, the second one is the value of
+  // context that is just passed through - so, there needs to be at least one
+  // more for the actual preference identifier.
+  const size_t kMinFetchPrefsParamCount = 3;
+  if (param_values->GetSize() < kMinFetchPrefsParamCount)
+    return;
+
+  size_t idx = param_values->GetSize();
+  LOG(INFO) << "param_values->GetSize() = " << idx;
+  // Get callback JS function name.
+  Value* callback;
+  if (!param_values->Get(0, &callback) || !callback->IsType(Value::TYPE_STRING))
+    return;
+
+  std::wstring callback_function;
+  if (!callback->GetAsString(&callback_function))
+    return;
+
+  // Get context param (just passthrough value)
+  Value* context;
+  if (!param_values->Get(1, &context) || !context)
+    return;
+
+  // Get the list of name for prefs to build the response dictionary.
+  DictionaryValue result_value;
+  Value* list_member;
+  DCHECK(dom_ui_);
+  PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+
+  for (size_t i = 2; i < param_values->GetSize(); i++) {
+    if (!param_values->Get(i, &list_member))
+      break;
+
+    if (!list_member->IsType(Value::TYPE_STRING))
+      continue;
+
+    std::wstring pref_name;
+    if (!list_member->GetAsString(&pref_name))
+      continue;
+
+    const PrefService::Preference* pref =
+        pref_service->FindPreference(pref_name.c_str());
+    result_value.Set(pref_name.c_str(),
+        pref ? pref->GetValue()->DeepCopy() : Value::CreateNullValue());
+  }
+  dom_ui_->CallJavascriptFunction(callback_function.c_str(), *context,
+                                  result_value);
+}
+
+void CoreOptionsHandler::HandleObservePefs(const Value* value) {
+  if (!value || !value->IsType(Value::TYPE_LIST))
+    return;
+
+  DCHECK(dom_ui_);
+  PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+  DictionaryValue result_value;
+  const ListValue* list_value = static_cast<const ListValue*>(value);
+  Value* list_member;
+  for (size_t i = 0; i < list_value->GetSize(); i++) {
+    if (!list_value->Get(i, &list_member))
+      break;
+
+    if (!list_member->IsType(Value::TYPE_STRING))
+      continue;
+
+    std::wstring pref_name;
+    if (!list_member->GetAsString(&pref_name))
+      continue;
+
+    pref_service->AddPrefObserver(pref_name.c_str(), this);
+  }
+}
+
+void CoreOptionsHandler::HandleSetBooleanPref(const Value* value) {
+  HandleSetPref(value, Value::TYPE_BOOLEAN);
+}
+
+void CoreOptionsHandler::HandleSetIntegerPref(const Value* value) {
+  HandleSetPref(value, Value::TYPE_INTEGER);
+}
+
+void CoreOptionsHandler::HandleSetStringPref(const Value* value) {
+  HandleSetPref(value, Value::TYPE_STRING);
+}
+
+void CoreOptionsHandler::HandleSetPref(const Value* value,
+                                       Value::ValueType type) {
+  if (!value || !value->IsType(Value::TYPE_LIST))
+    return;
+  const ListValue* param_values = static_cast<const ListValue*>(value);
+  size_t size = param_values->GetSize();
+  LOG(INFO) << "Array size = " << size;
+  if (param_values->GetSize() != 2)
+    return;
+
+  DCHECK(dom_ui_);
+  PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+
+  Value* name_element;
+  std::wstring pref_name;
+  if (!param_values->Get(0, &name_element) ||
+      !name_element->IsType(Value::TYPE_STRING) ||
+      !name_element->GetAsString(&pref_name))
+    return;
+
+  Value* value_element;
+  std::string value_string;
+  if (!param_values->Get(1, &value_element) ||
+      !value_element->IsType(Value::TYPE_STRING) ||
+      !value_element->GetAsString(&value_string))
+    return;
+
+  switch (type) {
+    case Value::TYPE_BOOLEAN:
+      pref_service->SetBoolean(pref_name.c_str(), value_string == "true");
+      break;
+    case Value::TYPE_INTEGER:
+      int int_value;
+      if (StringToInt(value_string, &int_value))
+        pref_service->SetInteger(pref_name.c_str(), int_value);
+      break;
+    case Value::TYPE_STRING:
+      pref_service->SetString(pref_name.c_str(), UTF8ToWide(value_string));
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void CoreOptionsHandler::NotifyPrefChanged(const std::wstring* pref_name) {
+  DCHECK(dom_ui_);
+  PrefService* pref_service = dom_ui_->GetProfile()->GetPrefs();
+  const PrefService::Preference* pref =
+      pref_service->FindPreference(pref_name->c_str());
+  if (pref) {
+    DictionaryValue result_value;
+    result_value.Set(pref_name->c_str(), pref->GetValue()->DeepCopy());
+    dom_ui_->CallJavascriptFunction(L"prefsChanged", result_value);
+  }
+}
diff --git a/chrome/browser/dom_ui/core_options_handler.h b/chrome/browser/dom_ui/core_options_handler.h
new file mode 100644
index 0000000..a71489f4
--- /dev/null
+++ b/chrome/browser/dom_ui/core_options_handler.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_DOM_UI_CORE_OPTIONS_HANDLER_H_
+#define CHROME_BROWSER_DOM_UI_CORE_OPTIONS_HANDLER_H_
+
+#include "base/values.h"
+#include "chrome/browser/dom_ui/options_ui.h"
+
+// Core options UI handler.
+// Handles resource and JS calls common to all options sub-pages.
+class CoreOptionsHandler : public OptionsPageUIHandler {
+ public:
+  CoreOptionsHandler();
+
+  // OptionsUIHandler implementation.
+  virtual void GetLocalizedValues(DictionaryValue* localized_strings);
+
+  // NotificationObserver implementation.
+  virtual void Observe(NotificationType type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details);
+
+  // DOMMessageHandler implementation.
+  virtual void RegisterMessages();
+
+ private:
+  // Callback for the "fetchPrefs" message. This message accepts the list of
+  // preference names passed as |value| parameter (ListValue). It passes results
+  // dictionary of preference values by calling prefsFetched() JS method on the
+  // page.
+  void HandleFetchPrefs(const Value* value);
+
+  // Callback for the "observePrefs" message. This message initiates
+  // notification observing for given array of preference names.
+  void HandleObservePefs(const Value* value);
+
+  // Callbacks for the "set<type>Pref" message. This message saves the new
+  // preference value. The input value is an array of strings representing
+  // name-value preference pair.
+  void HandleSetBooleanPref(const Value* value);
+  void HandleSetIntegerPref(const Value* value);
+  void HandleSetStringPref(const Value* value);
+
+  void HandleSetPref(const Value* value, Value::ValueType type);
+
+  void NotifyPrefChanged(const std::wstring* pref_name);
+
+  DISALLOW_COPY_AND_ASSIGN(CoreOptionsHandler);
+};
+
+#endif  // CHROME_BROWSER_DOM_UI_CORE_OPTIONS_HANDLER_H_
diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc
index 0ef066a7..4ddfac6 100644
--- a/chrome/browser/dom_ui/dom_ui_factory.cc
+++ b/chrome/browser/dom_ui/dom_ui_factory.cc
@@ -8,10 +8,8 @@
 #include "chrome/browser/dom_ui/bookmarks_ui.h"
 #include "chrome/browser/dom_ui/downloads_ui.h"
 #include "chrome/browser/dom_ui/devtools_ui.h"
-#include "chrome/browser/dom_ui/filebrowse_ui.h"
 #include "chrome/browser/dom_ui/history_ui.h"
 #include "chrome/browser/dom_ui/html_dialog_ui.h"
-#include "chrome/browser/dom_ui/mediaplayer_ui.h"
 #include "chrome/browser/dom_ui/net_internals_ui.h"
 #include "chrome/browser/dom_ui/new_tab_ui.h"
 #include "chrome/browser/dom_ui/plugins_ui.h"
@@ -24,6 +22,12 @@
 #include "chrome/common/url_constants.h"
 #include "googleurl/src/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/dom_ui/filebrowse_ui.h"
+#include "chrome/browser/dom_ui/mediaplayer_ui.h"
+#include "chrome/browser/dom_ui/options_ui.h"
+#endif
+
 const DOMUITypeID DOMUIFactory::kNoDOMUI = NULL;
 
 // A function for creating a new DOMUI. The caller owns the return value, which
@@ -106,9 +110,10 @@
 #if defined(OS_CHROMEOS)
   if (url.host() == chrome::kChromeUIFileBrowseHost)
     return &NewDOMUI<FileBrowseUI>;
-
   if (url.host() == chrome::kChromeUIMediaplayerHost)
     return &NewDOMUI<MediaplayerUI>;
+  if (url.host() == chrome::kChromeUIOptionsHost)
+    return &NewDOMUI<OptionsUI>;
 #endif
 
   return NULL;
diff --git a/chrome/browser/dom_ui/options_ui.cc b/chrome/browser/dom_ui/options_ui.cc
new file mode 100644
index 0000000..652a168
--- /dev/null
+++ b/chrome/browser/dom_ui/options_ui.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2010 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/dom_ui/options_ui.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/callback.h"
+#include "base/i18n/time_formatting.h"
+#include "base/message_loop.h"
+#include "base/singleton.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/thread.h"
+#include "base/time.h"
+#include "base/values.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/dom_ui/core_options_handler.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/pref_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/tab_contents/tab_contents_delegate.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/time_format.h"
+#include "chrome/common/url_constants.h"
+#include "net/base/escape.h"
+
+#include "grit/browser_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/dom_ui/system_options_handler.h"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OptionsUIHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+OptionsUIHTMLSource::OptionsUIHTMLSource(DictionaryValue* localized_strings)
+    : DataSource(chrome::kChromeUIOptionsHost, MessageLoop::current()) {
+  DCHECK(localized_strings);
+  localized_strings_.reset(localized_strings);
+}
+
+void OptionsUIHTMLSource::StartDataRequest(const std::string& path,
+                                           bool is_off_the_record,
+                                           int request_id) {
+  SetFontAndTextDirection(localized_strings_.get());
+
+  static const base::StringPiece options_html(
+      ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_OPTIONS_HTML));
+  const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
+      options_html, localized_strings_.get());
+
+  scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+  html_bytes->data.resize(full_html.size());
+  std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+  SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OptionsUIHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+OptionsPageUIHandler::OptionsPageUIHandler() {
+}
+
+OptionsPageUIHandler::~OptionsPageUIHandler() {
+}
+
+void OptionsPageUIHandler::UserMetricsRecordAction(
+    const UserMetricsAction& action, PrefService* prefs) {
+  UserMetrics::RecordAction(action, dom_ui_->GetProfile());
+  if (prefs)
+    prefs->ScheduleSavePersistentPrefs();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OptionsUIContents
+//
+////////////////////////////////////////////////////////////////////////////////
+
+OptionsUI::OptionsUI(TabContents* contents) : DOMUI(contents) {
+  DictionaryValue* localized_strings = new DictionaryValue();
+
+  // TODO(zelidrag): Add all other page handlers here as we implement them.
+  AddOptionsPageUIHandler(localized_strings, new CoreOptionsHandler());
+#if defined(OS_CHROMEOS)
+  AddOptionsPageUIHandler(localized_strings, new SystemOptionsHandler());
+#endif
+
+  // |localized_strings| ownership is taken over by this constructor.
+  OptionsUIHTMLSource* html_source =
+      new OptionsUIHTMLSource(localized_strings);
+
+  // Set up the chrome://options/ source.
+  ChromeThread::PostTask(
+      ChromeThread::IO, FROM_HERE,
+      NewRunnableMethod(
+          Singleton<ChromeURLDataManager>::get(),
+          &ChromeURLDataManager::AddDataSource,
+          make_scoped_refptr(html_source)));
+}
+
+void OptionsUI::AddOptionsPageUIHandler(DictionaryValue* localized_strings,
+                                        OptionsPageUIHandler* handler) {
+  DCHECK(handler);
+  handler->GetLocalizedValues(localized_strings);
+  AddMessageHandler(handler->Attach(this));
+}
diff --git a/chrome/browser/dom_ui/options_ui.h b/chrome/browser/dom_ui/options_ui.h
new file mode 100644
index 0000000..a79b3bb
--- /dev/null
+++ b/chrome/browser/dom_ui/options_ui.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_DOM_UI_OPTIONS_UI_H_
+#define CHROME_BROWSER_DOM_UI_OPTIONS_UI_H_
+
+#include <string>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_type.h"
+
+class GURL;
+class PrefService;
+struct UserMetricsAction;
+
+class OptionsUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+  // The constructor takes over ownership of |localized_strings|.
+  explicit OptionsUIHTMLSource(DictionaryValue* localized_strings);
+  virtual ~OptionsUIHTMLSource() {}
+
+  // Called when the network layer has requested a resource underneath
+  // the path we registered.
+  virtual void StartDataRequest(const std::string& path,
+                                bool is_off_the_record,
+                                int request_id);
+  virtual std::string GetMimeType(const std::string&) const {
+    return "text/html";
+  }
+
+ private:
+   // Localized strings collection.
+  scoped_ptr<DictionaryValue> localized_strings_;
+
+  DISALLOW_COPY_AND_ASSIGN(OptionsUIHTMLSource);
+};
+
+// The base class handler of Javascript messages of options pages.
+class OptionsPageUIHandler : public DOMMessageHandler,
+                             public NotificationObserver {
+ public:
+  OptionsPageUIHandler();
+  virtual ~OptionsPageUIHandler();
+
+  // Collects localized strings for options page.
+  virtual void GetLocalizedValues(DictionaryValue* localized_strings) = 0;
+
+  // DOMMessageHandler implementation.
+  virtual void RegisterMessages() {}
+
+  // NotificationObserver implementation.
+  virtual void Observe(NotificationType type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) {}
+
+  void UserMetricsRecordAction(const UserMetricsAction& action,
+                               PrefService* prefs);
+
+ protected:
+  NotificationRegistrar registrar_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OptionsPageUIHandler);
+};
+
+class OptionsUI : public DOMUI {
+ public:
+  explicit OptionsUI(TabContents* contents);
+  virtual ~OptionsUI() {}
+
+ private:
+  void AddOptionsPageUIHandler(DictionaryValue* localized_strings,
+                               OptionsPageUIHandler* handler);
+
+  DISALLOW_COPY_AND_ASSIGN(OptionsUI);
+};
+
+#endif  // CHROME_BROWSER_DOM_UI_OPTIONS_UI_H_
diff --git a/chrome/browser/resources/options.html b/chrome/browser/resources/options.html
new file mode 100644
index 0000000..8bdec64
--- /dev/null
+++ b/chrome/browser/resources/options.html
@@ -0,0 +1,258 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;" id="t">
+<head>
+<meta charset="utf-8">
+<title i18n-content="title"></title>
+<link rel="icon" href="../../app/theme/history_favicon.png">
+<script src="shared/js/local_strings.js"></script>
+<script>
+///////////////////////////////////////////////////////////////////////////////
+// Globals:
+
+function $(o) {return document.getElementById(o);}
+
+// Extracts preference value out of reponse callback of fetchPrefs call.
+function getPref(dict, name) {
+  return eval('dict.'+name);
+}
+
+// Sets new value for preference.
+function setBooleanPref(name, value) {
+  chrome.send('setBooleanPref', [name, String(value)]);
+}
+
+function setIntegerPref(name, value) {
+  chrome.send('setIntegerPref', [name, String(value)]);
+}
+
+function setStringPref(name, value) {
+  chrome.send('setStringPref', [name, value]);
+}
+///////////////////////////////////////////////////////////////////////////////
+// Document Functions:
+/**
+ * Window onload handler, sets up the page.
+ */
+function load() {
+  localStrings = new LocalStrings();
+  loadSystemPrefs();
+    
+  selectPage('system');
+  // TODO(zelidrag): preserve first that needs to be shown.
+}
+
+function selectPage(name) {
+  var page = $(name+'Page');
+  var nav = $(name+'PageNav');
+  page.style.visibility = 'visible';
+  nav.class = 'navbar_item navbar_item_selected';
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// System (ChromeOS) Functions:
+
+var kTimeZone = 'settings.datetime.timezone';
+var kTapToClickEnabled = 'settings.touchpad.enable_tap_to_click';
+var kVertEdgeScrollEnabled = 'settings.touchpad.enable_vert_edge_scroll';
+var kTouchpadSpeedFactor = 'settings.touchpad.speed_factor';
+var kTouchpadSensitivity = 'settings.touchpad.sensitivity';
+var kAccessibilityEnabled = 'settings.accessibility';
+       
+/**
+ * Loads ChromeOS System preferences.
+ */
+function loadSystemPrefs() {
+  chrome.send("fetchPrefs", ['systemPrefsFetched', '',
+                             kTimeZone,
+                             kTapToClickEnabled,
+                             kVertEdgeScrollEnabled,
+                             kTouchpadSpeedFactor,
+                             kTouchpadSensitivity,
+                             kAccessibilityEnabled]);
+}
+
+function setupTimezones(selectedValue) {
+  timezoneSel = $('timezoneSel');
+  for (key in templateData.timezoneMap) {
+    var selected = key == selectedValue;
+    timezoneSel.options[timezoneSel.options.length] =
+        new Option(templateData.timezoneMap[key], key, false, selected);
+  }
+}
+
+function systemPrefsFetched(context, dict) {
+  $('tapToClickChk').checked = getPref(dict, kTapToClickEnabled);
+  $('vertScrollChk').checked = getPref(dict, kVertEdgeScrollEnabled);
+  $('sensitivityRng').value = getPref(dict, kTouchpadSensitivity);
+  $('speedRng').value = getPref(dict, kTouchpadSpeedFactor);
+  $('accesibilityChk').checked = getPref(dict, kAccessibilityEnabled);
+  setupTimezones(getPref(dict, kTimeZone));
+}
+
+function selectChanged(control) {
+  if (control.id == 'timezoneSel') {
+    setStringPref(kTimeZone, control.options[control.selectedIndex].value);
+  }
+}
+
+function checkboxChanged(control) {
+  if (control.id == 'tapToClickChk') {
+    setBooleanPref(kTapToClickEnabled, control.checked);
+  } else if (control.id == 'vertScrollChk') {
+    setBooleanPref(kVertEdgeScrollEnabled, control.checked);
+  } else if (control.id == 'vertScrollChk') {
+    setBooleanPref(kTapToClickEnabled, control.checked);
+  } else if (control.id == 'accesibilityChk') {
+    setBooleanPref(kAccessibilityEnabled, control.checked);
+  } 
+}
+
+function rangeChanged(control) {
+  if (control.id == 'sensitivityRng') {
+    setIntegerPref(kTouchpadSensitivity, control.value);
+  } else if (control.id == 'speedRng') {
+    setIntegerPref(kTouchpadSpeedFactor, control.value);
+  }
+}
+
+function buttonClicked(control) {
+  if (conrol.id == 'languageBtn') {
+    // TODO: Open ChromeOS language settings page.
+  }
+}
+
+
+</script>
+<link rel="stylesheet" href="dom_ui.css">
+<!-- TODO(zelidrag) just a temp style placeholder until redesign -->
+<style>
+.navbar_container {
+  border: 1px solid black;
+  background-color: #dfdfdf;  
+  cursor:pointer;
+  font-weight: bold; 
+  float:left;
+  height: 400px;
+  padding: 10px;
+  position:relative;
+  width: 200px;
+}
+.navbar_item, .navbar_item2 {
+  margin: 5px;
+  padding: 5px;
+}
+.navbar_item_selected {
+  background-color: #000000;  
+}
+.navbar_item_normal {
+  background-color: #dfdfdf;  
+}
+#mainview {
+  border: 1px solid black;
+  float:left;
+  height: 400px;
+  width: 600px;
+  padding: 10px;
+  position:relative;
+}
+.section {
+  margin-top: 10px;
+}
+.option {
+  margin-top: 5px;
+}
+.section_title {
+  font-weight: bold; 
+}
+.option_control_table {
+  padding-left:10px;
+}
+.navbar2 {
+  visibility: hidden;
+}
+.page {
+  visibility: hidden;
+}
+</style>
+</head>
+<body onload="load();" i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+<div class="header">
+</div>
+<div class="main">
+  <div class="navbar_container">
+     <ul class="navbar">
+       <li class="navbar_item navbar_item_normal" id="systemPageNav" i18n-values=".innerText:systemPage"></li>
+       <li class="navbar_item navbar_item_normal" id="internetPageNav" i18n-values=".innerText:internetPage"></li>
+       <li class="navbar_item navbar_item_normal" id="basicsPageNav" i18n-values=".innerText:basicsPage"></li>
+       <li class="navbar_item navbar_item_normal" id="personalStuffPageNav" i18n-values=".innerText:personalStuffPage"></li>
+       <li class="navbar_item navbar_item_normal" id="underHoodPageNav" i18n-values=".innerText:underHoodPage"></li>
+     </ul>
+     <hr/>
+     <ul class="navbar2">
+     </ul>
+  </div>
+  <div id="mainview">
+     <div class="page" id="systemPage">
+       <div class="section">
+          <div class="section_title" i18n-values=".innerText:datetime_title"></div>
+          <div class="option">
+             <table class="option_control_table">
+             <tr>
+               <td class="option_name" i18n-values=".innerText:timezone"></td>
+               <td class="option_value">
+                 <select id="timezoneSel" class="control timezone_dropdown" onchange="selectChanged(this)"></select>
+               </td>
+             </tr>
+             </table>
+          </div>
+       </div>
+       <div class="section">
+          <div class="section_title" i18n-values=".innerText:touchpad"></div>
+          <div class="option">
+             <table class="option_control_table">
+             <tr>
+               <td class="option_name" i18n-values=".innerText:sensitivity"></td>
+               <td class="option_value">
+                 <input id="sensitivityRng" type="range" min="1" max="10" class="touchSlider" style="-webkit-appearance:slider-horizontal;" onchange="rangeChanged(this)">
+               </td>
+             </tr>
+             <tr>
+               <td class="option_name" i18n-values=".innerText:speed_factor"></td>
+               <td class="option_value">
+                 <input id="speedRng" type="range" min="1" max="10" class="touchSlider" style="-webkit-appearance:slider-horizontal;" onchange="rangeChanged(this)">
+               </td>
+             </tr>
+             <tr>
+               <td class="option_name" colspan="2"><input id="tapToClickChk" type="checkbox" onchange="checkboxChanged(this)"/><span  i18n-values=".innerText:enable_tap_to_click"></span></td>
+             </tr>
+             <tr>
+               <td class="option_name" colspan="2"><input id="vertScrollChk" type="checkbox" onchange="checkboxChanged(this)"/><span  i18n-values=".innerText:enable_vert_edge_scroll"></span></td>
+             </tr>
+             </table>
+          </div>
+       </div>
+       <div class="section">
+          <div class="section_title" i18n-values=".innerText:language"></div>
+          <div class="option">
+             <table class="option_control_table">
+             <tr>
+               <td class="option_name"><button id="languageBtn" onclick="buttonClicked" i18n-values=".innerText:language_customize"></button></td>
+             </tr>
+             </table>
+          </div>
+       </div>
+       <div class="section">
+          <div class="section_title" i18n-values=".innerText:accessibility_title"></div>
+          <div class="option">
+             <table class="option_control_table">
+             <tr>
+               <td class="option_name"><input id="accesibilityChk" onchange="checkboxChanged(this)" type="checkbox"/><span  i18n-values=".innerText:accessibility"></span></td>
+             </tr>
+             </table>
+          </div>
+       </div>
+     </div>
+  </div>
+</div>
+</body>
+</html>
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 119b1a9..38d609c9 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -379,8 +379,10 @@
         'browser/chromeos/cros/synaptics_library.h',
         'browser/chromeos/cros/syslogs_library.cc',
         'browser/chromeos/cros/syslogs_library.h',
-        'browser/chromeos/customization_document.h',
         'browser/chromeos/customization_document.cc',
+        'browser/chromeos/customization_document.h',
+        'browser/chromeos/dom_ui/system_options_handler.cc',
+        'browser/chromeos/dom_ui/system_options_handler.h',
         'browser/chromeos/external_cookie_handler.cc',
         'browser/chromeos/external_cookie_handler.h',
         'browser/chromeos/external_metrics.cc',
@@ -966,6 +968,8 @@
         'browser/dom_ui/bookmarks_ui.h',
         'browser/dom_ui/chrome_url_data_manager.cc',
         'browser/dom_ui/chrome_url_data_manager.h',
+        'browser/dom_ui/core_options_handler.cc',
+        'browser/dom_ui/core_options_handler.h',
         'browser/dom_ui/devtools_ui.cc',
         'browser/dom_ui/devtools_ui.h',
         'browser/dom_ui/dom_ui.cc',
@@ -1006,6 +1010,8 @@
         'browser/dom_ui/new_tab_ui.h',
         'browser/dom_ui/ntp_resource_cache.cc',
         'browser/dom_ui/ntp_resource_cache.h',
+        'browser/dom_ui/options_ui.cc',
+        'browser/dom_ui/options_ui.h',
         'browser/dom_ui/plugins_ui.cc',
         'browser/dom_ui/plugins_ui.h',
         'browser/dom_ui/shown_sections_handler.cc',
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 9a9cb66..6f06ab6 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -67,6 +67,7 @@
 const char kChromeUIFavIconURL[] = "chrome://favicon/";
 const char kChromeUIFileBrowseURL[] = "chrome://filebrowse/";
 const char kChromeUIMediaplayerURL[] = "chrome://mediaplayer/";
+const char kChromeUIOptionsURL[] = "chrome://options/";
 const char kChromeUIIPCURL[] = "chrome://about/ipc";
 const char kChromeUINetworkURL[] = "chrome://about/network";
 const char kChromeUINewTabURL[] = "chrome://newtab";
@@ -83,6 +84,7 @@
 const char kChromeUIResourcesHost[] = "resources";
 const char kChromeUIFileBrowseHost[] = "filebrowse";
 const char kChromeUIMediaplayerHost[] = "mediaplayer";
+const char kChromeUIOptionsHost[] = "options";
 const char kChromeUIInspectorHost[] = "inspector";
 const char kChromeUINetInternalsHost[] = "net-internals";
 const char kChromeUINewTabHost[] = "newtab";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 8da164d..991c9e1 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -54,15 +54,16 @@
 extern const char kChromeUIDevToolsURL[];
 extern const char kChromeUIDownloadsURL[];
 extern const char kChromeUIExtensionsURL[];
-extern const char kChromeUIHistoryURL[];
-extern const char kChromeUIPluginsURL[];
-extern const char kChromeUIPrintURL[];
 extern const char kChromeUIFavIconURL[];
 extern const char kChromeUIFileBrowseURL[];
-extern const char kChromeUIMediaplayerURL[];
+extern const char kChromeUIHistoryURL[];
 extern const char kChromeUIIPCURL[];
+extern const char kChromeUIMediaplayerURL[];
+extern const char kChromeUIOptionsURL[];
 extern const char kChromeUINetworkURL[];
 extern const char kChromeUINewTabURL[];
+extern const char kChromeUIPluginsURL[];
+extern const char kChromeUIPrintURL[];
 
 // chrome components of URLs. Should be kept in sync with the full URLs
 // above.
@@ -72,15 +73,16 @@
 extern const char kChromeUIDownloadsHost[];
 extern const char kChromeUIExtensionsHost[];
 extern const char kChromeUIFavIconHost[];
+extern const char kChromeUIFileBrowseHost[];
 extern const char kChromeUIHistoryHost[];
+extern const char kChromeUIInspectorHost[];
+extern const char kChromeUIMediaplayerHost[];
+extern const char kChromeUINetInternalsHost[];
+extern const char kChromeUINewTabHost[];
+extern const char kChromeUIOptionsHost[];
 extern const char kChromeUIPluginsHost[];
 extern const char kChromeUIPrintHost[];
 extern const char kChromeUIResourcesHost[];
-extern const char kChromeUIFileBrowseHost[];
-extern const char kChromeUIMediaplayerHost[];
-extern const char kChromeUIInspectorHost[];
-extern const char kChromeUINetInternalsHost[];
-extern const char kChromeUINewTabHost[];
 extern const char kChromeUIThumbnailPath[];
 extern const char kChromeUIThemePath[];