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/options/personal_options_handler.h"
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/callback.h"
11#include "base/command_line.h"
12#include "base/path_service.h"
13#include "base/stl_util-inl.h"
14#include "base/stringprintf.h"
15#include "base/time.h"
16#include "base/utf_string_conversions.h"
17#include "base/values.h"
18#include "build/build_config.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/profiles/profile_manager.h"
21#include "chrome/browser/sync/profile_sync_service.h"
22#include "chrome/browser/sync/sync_setup_flow.h"
23#include "chrome/browser/sync/sync_ui_util.h"
24#include "chrome/browser/themes/theme_service.h"
25#include "chrome/browser/themes/theme_service_factory.h"
26#include "chrome/browser/ui/browser_list.h"
27#include "chrome/browser/ui/options/options_page_base.h"
28#include "chrome/browser/ui/options/options_window.h"
29#include "chrome/browser/ui/webui/options/options_managed_banner_handler.h"
30#include "chrome/common/chrome_paths.h"
31#include "chrome/common/chrome_switches.h"
32#include "chrome/common/net/gaia/google_service_auth_error.h"
33#include "chrome/common/url_constants.h"
34#include "content/common/notification_service.h"
35#include "grit/chromium_strings.h"
36#include "grit/generated_resources.h"
37#include "grit/locale_settings.h"
38#include "grit/theme_resources.h"
39#include "ui/base/l10n/l10n_util.h"
40
41#if defined(OS_CHROMEOS)
42#include "chrome/browser/chromeos/login/user_manager.h"
43#include "chrome/browser/chromeos/options/take_photo_dialog.h"
44#include "chrome/browser/ui/browser_window.h"
45#include "chrome/browser/ui/views/window.h"
46#include "third_party/skia/include/core/SkBitmap.h"
47#include "views/window/window.h"
48#endif  // defined(OS_CHROMEOS)
49#if defined(TOOLKIT_GTK)
50#include "chrome/browser/ui/gtk/gtk_theme_service.h"
51#endif  // defined(TOOLKIT_GTK)
52
53PersonalOptionsHandler::PersonalOptionsHandler() {
54  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
55  multiprofile_ = browser_command_line.HasSwitch(switches::kMultiProfiles);
56#if defined(OS_CHROMEOS)
57  registrar_.Add(this,
58                 NotificationType::LOGIN_USER_IMAGE_CHANGED,
59                 NotificationService::AllSources());
60#endif
61}
62
63PersonalOptionsHandler::~PersonalOptionsHandler() {
64  ProfileSyncService* sync_service =
65      web_ui_->GetProfile()->GetProfileSyncService();
66  if (sync_service)
67    sync_service->RemoveObserver(this);
68}
69
70void PersonalOptionsHandler::GetLocalizedValues(
71    DictionaryValue* localized_strings) {
72  DCHECK(localized_strings);
73
74  RegisterTitle(localized_strings, "personalPage",
75                IDS_OPTIONS_CONTENT_TAB_LABEL);
76
77
78  localized_strings->SetString(
79      "syncOverview",
80      l10n_util::GetStringFUTF16(IDS_SYNC_OVERVIEW,
81                                 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
82  localized_strings->SetString(
83      "syncFurtherOverview",
84      l10n_util::GetStringUTF16(IDS_SYNC_FURTHER_OVERVIEW));
85  localized_strings->SetString("syncSection",
86      multiprofile_ ?
87          l10n_util::GetStringUTF16(IDS_PROFILES_OPTIONS_GROUP_NAME) :
88          l10n_util::GetStringUTF16(IDS_SYNC_OPTIONS_GROUP_NAME));
89  localized_strings->SetString("customizeSync",
90      multiprofile_ ?
91          l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_CUSTOMIZE_BUTTON_LABEL) :
92          l10n_util::GetStringUTF16(IDS_SYNC_CUSTOMIZE_BUTTON_LABEL));
93  if (multiprofile_) {
94    localized_strings->SetString("createNewProfile",
95        l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_INFO));
96    localized_strings->SetString("createProfileButton",
97        l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_BUTTON_LABEL));
98  }
99
100  localized_strings->SetString("passwords",
101      l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_GROUP_NAME));
102  localized_strings->SetString("passwordsAskToSave",
103      l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_ASKTOSAVE));
104  localized_strings->SetString("passwordsNeverSave",
105      l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_NEVERSAVE));
106  localized_strings->SetString("manage_passwords",
107      l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS));
108
109  localized_strings->SetString("autofill",
110      l10n_util::GetStringUTF16(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME));
111  localized_strings->SetString("autofillEnabled",
112      l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOFILL_ENABLE));
113  localized_strings->SetString("manageAutofillSettings",
114      l10n_util::GetStringUTF16(IDS_OPTIONS_MANAGE_AUTOFILL_SETTINGS));
115
116  localized_strings->SetString("browsingData",
117      l10n_util::GetStringUTF16(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME));
118  localized_strings->SetString("importData",
119      l10n_util::GetStringUTF16(IDS_OPTIONS_IMPORT_DATA_BUTTON));
120
121  localized_strings->SetString("themesGallery",
122      l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_BUTTON));
123  localized_strings->SetString("themesGalleryURL",
124      l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_URL));
125
126#if defined(TOOLKIT_GTK)
127  localized_strings->SetString("appearance",
128      l10n_util::GetStringUTF16(IDS_APPEARANCE_GROUP_NAME));
129  localized_strings->SetString("themesGTKButton",
130      l10n_util::GetStringUTF16(IDS_THEMES_GTK_BUTTON));
131  localized_strings->SetString("themesSetClassic",
132      l10n_util::GetStringUTF16(IDS_THEMES_SET_CLASSIC));
133  localized_strings->SetString("showWindowDecorations",
134      l10n_util::GetStringUTF16(IDS_SHOW_WINDOW_DECORATIONS_RADIO));
135  localized_strings->SetString("hideWindowDecorations",
136      l10n_util::GetStringUTF16(IDS_HIDE_WINDOW_DECORATIONS_RADIO));
137#else
138  localized_strings->SetString("themes",
139      l10n_util::GetStringUTF16(IDS_THEMES_GROUP_NAME));
140  localized_strings->SetString("themesReset",
141      l10n_util::GetStringUTF16(IDS_THEMES_RESET_BUTTON));
142#endif
143
144  // Sync select control.
145  ListValue* sync_select_list = new ListValue;
146  ListValue* datatypes = new ListValue;
147  datatypes->Append(Value::CreateBooleanValue(false));
148  datatypes->Append(
149      Value::CreateStringValue(
150          l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_DATATYPES)));
151  sync_select_list->Append(datatypes);
152  ListValue* everything = new ListValue;
153  everything->Append(Value::CreateBooleanValue(true));
154  everything->Append(
155      Value::CreateStringValue(
156          l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_EVERYTHING)));
157  sync_select_list->Append(everything);
158  localized_strings->Set("syncSelectList", sync_select_list);
159
160  // Sync page.
161  localized_strings->SetString("syncPage",
162      l10n_util::GetStringUTF16(IDS_SYNC_NTP_SYNC_SECTION_TITLE));
163  localized_strings->SetString("sync_title",
164      l10n_util::GetStringUTF16(IDS_CUSTOMIZE_SYNC_DESCRIPTION));
165  localized_strings->SetString("syncsettings",
166      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PREFERENCES));
167  localized_strings->SetString("syncbookmarks",
168      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_BOOKMARKS));
169  localized_strings->SetString("synctypedurls",
170      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TYPED_URLS));
171  localized_strings->SetString("syncpasswords",
172      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PASSWORDS));
173  localized_strings->SetString("syncextensions",
174      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_EXTENSIONS));
175  localized_strings->SetString("syncautofill",
176      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_AUTOFILL));
177  localized_strings->SetString("syncthemes",
178      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_THEMES));
179  localized_strings->SetString("syncapps",
180      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_APPS));
181  localized_strings->SetString("syncsessions",
182      l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_SESSIONS));
183
184#if defined(OS_CHROMEOS)
185  localized_strings->SetString("account",
186      l10n_util::GetStringUTF16(IDS_OPTIONS_PERSONAL_ACCOUNT_GROUP_NAME));
187  localized_strings->SetString("enableScreenlock",
188      l10n_util::GetStringUTF16(IDS_OPTIONS_ENABLE_SCREENLOCKER_CHECKBOX));
189  localized_strings->SetString("changePicture",
190      l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE));
191#endif
192}
193
194void PersonalOptionsHandler::RegisterMessages() {
195  DCHECK(web_ui_);
196  web_ui_->RegisterMessageCallback(
197      "showSyncActionDialog",
198      NewCallback(this, &PersonalOptionsHandler::ShowSyncActionDialog));
199  web_ui_->RegisterMessageCallback(
200      "showSyncLoginDialog",
201      NewCallback(this, &PersonalOptionsHandler::ShowSyncLoginDialog));
202  web_ui_->RegisterMessageCallback(
203      "showCustomizeSyncDialog",
204      NewCallback(this, &PersonalOptionsHandler::ShowCustomizeSyncDialog));
205  web_ui_->RegisterMessageCallback(
206      "themesReset",
207      NewCallback(this, &PersonalOptionsHandler::ThemesReset));
208#if defined(TOOLKIT_GTK)
209  web_ui_->RegisterMessageCallback(
210      "themesSetGTK",
211      NewCallback(this, &PersonalOptionsHandler::ThemesSetGTK));
212#endif
213  web_ui_->RegisterMessageCallback("updatePreferredDataTypes",
214      NewCallback(this, &PersonalOptionsHandler::OnPreferredDataTypesUpdated));
215#if defined(OS_CHROMEOS)
216  web_ui_->RegisterMessageCallback(
217      "loadAccountPicture",
218      NewCallback(this, &PersonalOptionsHandler::LoadAccountPicture));
219#endif
220}
221
222void PersonalOptionsHandler::Observe(NotificationType type,
223                                     const NotificationSource& source,
224                                     const NotificationDetails& details) {
225  if (type == NotificationType::BROWSER_THEME_CHANGED) {
226    ObserveThemeChanged();
227#if defined(OS_CHROMEOS)
228  } else if (type == NotificationType::LOGIN_USER_IMAGE_CHANGED) {
229    LoadAccountPicture(NULL);
230#endif
231  } else {
232    OptionsPageUIHandler::Observe(type, source, details);
233  }
234}
235
236void PersonalOptionsHandler::OnStateChanged() {
237  string16 status_label;
238  string16 link_label;
239  ProfileSyncService* service = web_ui_->GetProfile()->GetProfileSyncService();
240  DCHECK(service);
241  bool managed = service->IsManaged();
242  bool sync_setup_completed = service->HasSyncSetupCompleted();
243  bool status_has_error = sync_ui_util::GetStatusLabels(service,
244      &status_label, &link_label) == sync_ui_util::SYNC_ERROR;
245
246  string16 start_stop_button_label;
247  bool is_start_stop_button_visible = false;
248  bool is_start_stop_button_enabled = false;
249  if (sync_setup_completed) {
250    start_stop_button_label = multiprofile_ ?
251        l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON_LABEL) :
252        l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL);
253#if defined(OS_CHROMEOS)
254    is_start_stop_button_visible = false;
255#else
256    is_start_stop_button_visible = true;
257#endif  // defined(OS_CHROMEOS)
258    is_start_stop_button_enabled = !managed;
259  } else if (service->SetupInProgress()) {
260    start_stop_button_label =
261        l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS);
262    is_start_stop_button_visible = true;
263    is_start_stop_button_enabled = false;
264  } else {
265    start_stop_button_label =
266        multiprofile_ ?
267            l10n_util::GetStringUTF16(IDS_PROFILES_CONNECT_BUTTON_LABEL) :
268            l10n_util::GetStringUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL);
269    is_start_stop_button_visible = true;
270    is_start_stop_button_enabled = !managed;
271  }
272
273  scoped_ptr<Value> completed(Value::CreateBooleanValue(sync_setup_completed));
274  web_ui_->CallJavascriptFunction("PersonalOptions.setSyncSetupCompleted",
275                                  *completed);
276
277  scoped_ptr<Value> label(Value::CreateStringValue(status_label));
278  web_ui_->CallJavascriptFunction("PersonalOptions.setSyncStatus", *label);
279
280  scoped_ptr<Value> enabled(
281      Value::CreateBooleanValue(is_start_stop_button_enabled));
282  web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonEnabled",
283                                  *enabled);
284
285  scoped_ptr<Value> visible(
286      Value::CreateBooleanValue(is_start_stop_button_visible));
287  web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonVisible",
288                                  *visible);
289
290  label.reset(Value::CreateStringValue(start_stop_button_label));
291  web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonLabel",
292                                  *label);
293
294  label.reset(Value::CreateStringValue(link_label));
295  web_ui_->CallJavascriptFunction("PersonalOptions.setSyncActionLinkLabel",
296                                  *label);
297
298  enabled.reset(Value::CreateBooleanValue(!managed));
299  web_ui_->CallJavascriptFunction("PersonalOptions.setSyncActionLinkEnabled",
300                                  *enabled);
301
302  visible.reset(Value::CreateBooleanValue(status_has_error));
303  web_ui_->CallJavascriptFunction("PersonalOptions.setSyncStatusErrorVisible",
304                                  *visible);
305
306  // Set profile creation text and button if multi-profiles switch is on.
307  if (multiprofile_) {
308    visible.reset(Value::CreateBooleanValue(true));
309    web_ui_->CallJavascriptFunction("PersonalOptions.setProfilesSectionVisible",
310                                    *visible);
311
312    // TODO(mirandac): enable when back end is ready.
313    enabled.reset(Value::CreateBooleanValue(false));
314    web_ui_->CallJavascriptFunction(
315        "PersonalOptions.setNewProfileButtonEnabled", *enabled);
316  } else {
317    visible.reset(Value::CreateBooleanValue(false));
318    web_ui_->CallJavascriptFunction("PersonalOptions.setProfilesSectionVisible",
319                                    *visible);
320  }
321}
322
323void PersonalOptionsHandler::OnLoginSuccess() {
324  OnStateChanged();
325}
326
327void PersonalOptionsHandler::OnLoginFailure(
328    const GoogleServiceAuthError& error) {
329  OnStateChanged();
330}
331
332void PersonalOptionsHandler::ObserveThemeChanged() {
333  Profile* profile = web_ui_->GetProfile();
334#if defined(TOOLKIT_GTK)
335  GtkThemeService* provider = GtkThemeService::GetFrom(profile);
336  bool is_gtk_theme = provider->UseGtkTheme();
337  FundamentalValue gtk_enabled(!is_gtk_theme);
338  web_ui_->CallJavascriptFunction(
339      "options.PersonalOptions.setGtkThemeButtonEnabled", gtk_enabled);
340#else
341  ThemeService* provider = ThemeServiceFactory::GetForProfile(profile);
342  bool is_gtk_theme = false;
343#endif
344
345  bool is_classic_theme = !is_gtk_theme && provider->UsingDefaultTheme();
346  FundamentalValue enabled(!is_classic_theme);
347  web_ui_->CallJavascriptFunction(
348      "options.PersonalOptions.setThemesResetButtonEnabled", enabled);
349}
350
351void PersonalOptionsHandler::Initialize() {
352  banner_handler_.reset(
353      new OptionsManagedBannerHandler(web_ui_,
354                                      ASCIIToUTF16("PersonalOptions"),
355                                      OPTIONS_PAGE_CONTENT));
356
357  // Listen for theme installation.
358  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
359                 NotificationService::AllSources());
360  ObserveThemeChanged();
361
362  ProfileSyncService* sync_service =
363      web_ui_->GetProfile()->GetProfileSyncService();
364  if (sync_service) {
365    sync_service->AddObserver(this);
366    OnStateChanged();
367
368    DictionaryValue args;
369    SyncSetupFlow::GetArgsForConfigure(sync_service, &args);
370
371    web_ui_->CallJavascriptFunction("PersonalOptions.setRegisteredDataTypes",
372                                    args);
373  } else {
374    web_ui_->CallJavascriptFunction("options.PersonalOptions.hideSyncSection");
375  }
376}
377
378void PersonalOptionsHandler::ShowSyncActionDialog(const ListValue* args) {
379  ProfileSyncService* service = web_ui_->GetProfile()->GetProfileSyncService();
380  DCHECK(service);
381  service->ShowErrorUI(NULL);
382}
383
384void PersonalOptionsHandler::ShowSyncLoginDialog(const ListValue* args) {
385  ProfileSyncService* service = web_ui_->GetProfile()->GetProfileSyncService();
386  DCHECK(service);
387  service->ShowLoginDialog(NULL);
388  ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
389}
390
391void PersonalOptionsHandler::ShowCustomizeSyncDialog(const ListValue* args) {
392  ProfileSyncService* service = web_ui_->GetProfile()->GetProfileSyncService();
393  DCHECK(service);
394  service->ShowConfigure(NULL, false);
395}
396
397void PersonalOptionsHandler::ThemesReset(const ListValue* args) {
398  UserMetricsRecordAction(UserMetricsAction("Options_ThemesReset"));
399  ThemeServiceFactory::GetForProfile(web_ui_->GetProfile())->UseDefaultTheme();
400}
401
402#if defined(TOOLKIT_GTK)
403void PersonalOptionsHandler::ThemesSetGTK(const ListValue* args) {
404  UserMetricsRecordAction(UserMetricsAction("Options_GtkThemeSet"));
405  ThemeServiceFactory::GetForProfile(web_ui_->GetProfile())->SetNativeTheme();
406}
407#endif
408
409void PersonalOptionsHandler::OnPreferredDataTypesUpdated(
410    const ListValue* args) {
411  NotificationService::current()->Notify(
412      NotificationType::SYNC_DATA_TYPES_UPDATED,
413      Source<Profile>(web_ui_->GetProfile()),
414      NotificationService::NoDetails());
415}
416
417#if defined(OS_CHROMEOS)
418void PersonalOptionsHandler::LoadAccountPicture(const ListValue* args) {
419  const chromeos::UserManager::User& user =
420      chromeos::UserManager::Get()->logged_in_user();
421  std::string email = user.email();
422  if (!email.empty()) {
423    // int64 is either long or long long, but we need a certain format
424    // specifier.
425    long long timestamp = base::TimeTicks::Now().ToInternalValue();
426    StringValue image_url(
427        StringPrintf("%s%s?id=%lld",
428                     chrome::kChromeUIUserImageURL,
429                     email.c_str(),
430                     timestamp));
431    web_ui_->CallJavascriptFunction("PersonalOptions.setAccountPicture",
432                                    image_url);
433  }
434}
435
436#endif
437