OLD | NEW |
| (Empty) |
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/options2/personal_options_handler.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/bind.h" | |
11 #include "base/command_line.h" | |
12 #include "base/path_service.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/string_number_conversions.h" | |
15 #include "base/utf_string_conversions.h" | |
16 #include "base/value_conversions.h" | |
17 #include "base/values.h" | |
18 #include "build/build_config.h" | |
19 #include "chrome/browser/browser_process.h" | |
20 #include "chrome/browser/google/google_util.h" | |
21 #include "chrome/browser/profiles/profile.h" | |
22 #include "chrome/browser/profiles/profile_info_cache.h" | |
23 #include "chrome/browser/profiles/profile_info_util.h" | |
24 #include "chrome/browser/profiles/profile_manager.h" | |
25 #include "chrome/browser/sync/profile_sync_service.h" | |
26 #include "chrome/browser/sync/sync_setup_flow.h" | |
27 #include "chrome/browser/sync/sync_ui_util.h" | |
28 #include "chrome/browser/themes/theme_service.h" | |
29 #include "chrome/browser/themes/theme_service_factory.h" | |
30 #include "chrome/browser/ui/webui/web_ui_util.h" | |
31 #include "chrome/common/chrome_notification_types.h" | |
32 #include "chrome/common/chrome_paths.h" | |
33 #include "chrome/common/chrome_switches.h" | |
34 #include "chrome/common/net/gaia/google_service_auth_error.h" | |
35 #include "chrome/common/url_constants.h" | |
36 #include "content/browser/tab_contents/tab_contents.h" | |
37 #include "content/browser/user_metrics.h" | |
38 #include "content/public/browser/notification_service.h" | |
39 #include "grit/chromium_strings.h" | |
40 #include "grit/generated_resources.h" | |
41 #include "grit/locale_settings.h" | |
42 #include "grit/theme_resources.h" | |
43 #include "ui/base/l10n/l10n_util.h" | |
44 | |
45 #if defined(OS_CHROMEOS) | |
46 #include "chrome/browser/chromeos/login/user_manager.h" | |
47 #include "chrome/browser/chromeos/options2/take_photo_dialog.h" | |
48 #include "chrome/browser/ui/browser_window.h" | |
49 #include "chrome/browser/ui/views/window.h" | |
50 #include "third_party/skia/include/core/SkBitmap.h" | |
51 #endif // defined(OS_CHROMEOS) | |
52 #if defined(TOOLKIT_GTK) | |
53 #include "chrome/browser/ui/gtk/gtk_theme_service.h" | |
54 #endif // defined(TOOLKIT_GTK) | |
55 | |
56 PersonalOptionsHandler::PersonalOptionsHandler() { | |
57 multiprofile_ = ProfileManager::IsMultipleProfilesEnabled(); | |
58 #if defined(OS_CHROMEOS) | |
59 registrar_.Add(this, | |
60 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, | |
61 content::NotificationService::AllSources()); | |
62 #endif | |
63 } | |
64 | |
65 PersonalOptionsHandler::~PersonalOptionsHandler() { | |
66 ProfileSyncService* sync_service = | |
67 Profile::FromWebUI(web_ui_)->GetProfileSyncService(); | |
68 if (sync_service) | |
69 sync_service->RemoveObserver(this); | |
70 } | |
71 | |
72 void PersonalOptionsHandler::GetLocalizedValues( | |
73 DictionaryValue* localized_strings) { | |
74 DCHECK(localized_strings); | |
75 | |
76 RegisterTitle(localized_strings, "personalPage", | |
77 IDS_OPTIONS_CONTENT_TAB_LABEL); | |
78 | |
79 | |
80 localized_strings->SetString( | |
81 "syncOverview", | |
82 l10n_util::GetStringFUTF16(IDS_SYNC_OVERVIEW, | |
83 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); | |
84 localized_strings->SetString("syncSection", | |
85 l10n_util::GetStringUTF16(IDS_SYNC_OPTIONS_GROUP_NAME)); | |
86 localized_strings->SetString("customizeSync", | |
87 l10n_util::GetStringUTF16(IDS_SYNC_CUSTOMIZE_BUTTON_LABEL)); | |
88 localized_strings->SetString("syncLearnMoreURL", | |
89 google_util::StringAppendGoogleLocaleParam(chrome::kSyncLearnMoreURL)); | |
90 | |
91 localized_strings->SetString("profiles", | |
92 l10n_util::GetStringUTF16(IDS_PROFILES_OPTIONS_GROUP_NAME)); | |
93 localized_strings->SetString("profilesCreate", | |
94 l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_BUTTON_LABEL)); | |
95 localized_strings->SetString("profilesManage", | |
96 l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_BUTTON_LABEL)); | |
97 localized_strings->SetString("profilesDelete", | |
98 l10n_util::GetStringUTF16(IDS_PROFILES_DELETE_BUTTON_LABEL)); | |
99 localized_strings->SetString("profilesDeleteSingle", | |
100 l10n_util::GetStringUTF16(IDS_PROFILES_DELETE_SINGLE_BUTTON_LABEL)); | |
101 localized_strings->SetString("profilesListItemCurrent", | |
102 l10n_util::GetStringUTF16(IDS_PROFILES_LIST_ITEM_CURRENT)); | |
103 localized_strings->SetString("profilesSingleUser", | |
104 l10n_util::GetStringFUTF16(IDS_PROFILES_SINGLE_USER_MESSAGE, | |
105 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); | |
106 | |
107 localized_strings->SetString("passwords", | |
108 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_GROUP_NAME)); | |
109 localized_strings->SetString("passwordsAskToSave", | |
110 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_ASKTOSAVE)); | |
111 localized_strings->SetString("passwordsNeverSave", | |
112 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_NEVERSAVE)); | |
113 localized_strings->SetString("manage_passwords", | |
114 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS)); | |
115 #if defined(OS_MACOSX) | |
116 ProfileManager* profile_manager = g_browser_process->profile_manager(); | |
117 if (profile_manager->GetNumberOfProfiles() > 1) { | |
118 localized_strings->SetString("macPasswordsWarning", | |
119 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_MAC_WARNING)); | |
120 } | |
121 #endif | |
122 localized_strings->SetString("autologinEnabled", | |
123 l10n_util::GetStringUTF16(IDS_OPTIONS_PASSWORDS_AUTOLOGIN)); | |
124 | |
125 localized_strings->SetString("autofill", | |
126 l10n_util::GetStringUTF16(IDS_AUTOFILL_SETTING_WINDOWS_GROUP_NAME)); | |
127 localized_strings->SetString("autofillEnabled", | |
128 l10n_util::GetStringUTF16(IDS_OPTIONS_AUTOFILL_ENABLE)); | |
129 localized_strings->SetString("manageAutofillSettings", | |
130 l10n_util::GetStringUTF16(IDS_OPTIONS_MANAGE_AUTOFILL_SETTINGS)); | |
131 | |
132 localized_strings->SetString("browsingData", | |
133 l10n_util::GetStringUTF16(IDS_OPTIONS_BROWSING_DATA_GROUP_NAME)); | |
134 localized_strings->SetString("importData", | |
135 l10n_util::GetStringUTF16(IDS_OPTIONS_IMPORT_DATA_BUTTON)); | |
136 | |
137 localized_strings->SetString("themesGallery", | |
138 l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_BUTTON)); | |
139 localized_strings->SetString("themesGalleryURL", | |
140 l10n_util::GetStringUTF16(IDS_THEMES_GALLERY_URL)); | |
141 | |
142 #if defined(TOOLKIT_GTK) | |
143 localized_strings->SetString("appearance", | |
144 l10n_util::GetStringUTF16(IDS_APPEARANCE_GROUP_NAME)); | |
145 localized_strings->SetString("themesGTKButton", | |
146 l10n_util::GetStringUTF16(IDS_THEMES_GTK_BUTTON)); | |
147 localized_strings->SetString("themesSetClassic", | |
148 l10n_util::GetStringUTF16(IDS_THEMES_SET_CLASSIC)); | |
149 localized_strings->SetString("showWindowDecorations", | |
150 l10n_util::GetStringUTF16(IDS_SHOW_WINDOW_DECORATIONS_RADIO)); | |
151 localized_strings->SetString("hideWindowDecorations", | |
152 l10n_util::GetStringUTF16(IDS_HIDE_WINDOW_DECORATIONS_RADIO)); | |
153 #else | |
154 localized_strings->SetString("themes", | |
155 l10n_util::GetStringUTF16(IDS_THEMES_GROUP_NAME)); | |
156 localized_strings->SetString("themesReset", | |
157 l10n_util::GetStringUTF16(IDS_THEMES_RESET_BUTTON)); | |
158 #endif | |
159 | |
160 // Sync select control. | |
161 ListValue* sync_select_list = new ListValue; | |
162 ListValue* datatypes = new ListValue; | |
163 datatypes->Append(Value::CreateBooleanValue(false)); | |
164 datatypes->Append( | |
165 Value::CreateStringValue( | |
166 l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_DATATYPES))); | |
167 sync_select_list->Append(datatypes); | |
168 ListValue* everything = new ListValue; | |
169 everything->Append(Value::CreateBooleanValue(true)); | |
170 everything->Append( | |
171 Value::CreateStringValue( | |
172 l10n_util::GetStringUTF8(IDS_SYNC_OPTIONS_SELECT_EVERYTHING))); | |
173 sync_select_list->Append(everything); | |
174 localized_strings->Set("syncSelectList", sync_select_list); | |
175 | |
176 // Sync page. | |
177 localized_strings->SetString("syncPage", | |
178 l10n_util::GetStringUTF16(IDS_SYNC_NTP_SYNC_SECTION_TITLE)); | |
179 localized_strings->SetString("sync_title", | |
180 l10n_util::GetStringUTF16(IDS_CUSTOMIZE_SYNC_DESCRIPTION)); | |
181 localized_strings->SetString("syncsettings", | |
182 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PREFERENCES)); | |
183 localized_strings->SetString("syncbookmarks", | |
184 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_BOOKMARKS)); | |
185 localized_strings->SetString("synctypedurls", | |
186 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TYPED_URLS)); | |
187 localized_strings->SetString("syncpasswords", | |
188 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_PASSWORDS)); | |
189 localized_strings->SetString("syncextensions", | |
190 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_EXTENSIONS)); | |
191 localized_strings->SetString("syncautofill", | |
192 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_AUTOFILL)); | |
193 localized_strings->SetString("syncthemes", | |
194 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_THEMES)); | |
195 localized_strings->SetString("syncapps", | |
196 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_APPS)); | |
197 localized_strings->SetString("syncsessions", | |
198 l10n_util::GetStringUTF16(IDS_SYNC_DATATYPE_TABS)); | |
199 | |
200 #if defined(OS_CHROMEOS) | |
201 localized_strings->SetString("account", | |
202 l10n_util::GetStringUTF16(IDS_OPTIONS_PERSONAL_ACCOUNT_GROUP_NAME)); | |
203 localized_strings->SetString("enableScreenlock", | |
204 l10n_util::GetStringUTF16(IDS_OPTIONS_ENABLE_SCREENLOCKER_CHECKBOX)); | |
205 localized_strings->SetString("changePicture", | |
206 l10n_util::GetStringUTF16(IDS_OPTIONS_CHANGE_PICTURE)); | |
207 if (chromeos::UserManager::Get()->user_is_logged_in()) { | |
208 localized_strings->SetString("username", | |
209 chromeos::UserManager::Get()->logged_in_user().email()); | |
210 } | |
211 #endif | |
212 } | |
213 | |
214 void PersonalOptionsHandler::RegisterMessages() { | |
215 DCHECK(web_ui_); | |
216 web_ui_->RegisterMessageCallback( | |
217 "themesReset", | |
218 base::Bind(&PersonalOptionsHandler::ThemesReset, | |
219 base::Unretained(this))); | |
220 #if defined(TOOLKIT_GTK) | |
221 web_ui_->RegisterMessageCallback( | |
222 "themesSetGTK", | |
223 base::Bind(&PersonalOptionsHandler::ThemesSetGTK, | |
224 base::Unretained(this))); | |
225 #endif | |
226 web_ui_->RegisterMessageCallback( | |
227 "createProfile", | |
228 base::Bind(&PersonalOptionsHandler::CreateProfile, | |
229 base::Unretained(this))); | |
230 } | |
231 | |
232 void PersonalOptionsHandler::Observe( | |
233 int type, | |
234 const content::NotificationSource& source, | |
235 const content::NotificationDetails& details) { | |
236 if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) { | |
237 ObserveThemeChanged(); | |
238 } else if (multiprofile_ && | |
239 type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) { | |
240 SendProfilesInfo(); | |
241 #if defined(OS_CHROMEOS) | |
242 } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) { | |
243 UpdateAccountPicture(); | |
244 #endif | |
245 } else { | |
246 OptionsPage2UIHandler::Observe(type, source, details); | |
247 } | |
248 } | |
249 | |
250 void PersonalOptionsHandler::OnStateChanged() { | |
251 string16 status_label; | |
252 string16 link_label; | |
253 ProfileSyncService* service = | |
254 Profile::FromWebUI(web_ui_)->GetProfileSyncService(); | |
255 DCHECK(service); | |
256 bool managed = service->IsManaged(); | |
257 bool sync_setup_completed = service->HasSyncSetupCompleted(); | |
258 bool status_has_error = sync_ui_util::GetStatusLabels( | |
259 service, sync_ui_util::WITH_HTML, &status_label, &link_label) == | |
260 sync_ui_util::SYNC_ERROR; | |
261 | |
262 string16 start_stop_button_label; | |
263 bool is_start_stop_button_visible = false; | |
264 bool is_start_stop_button_enabled = false; | |
265 if (sync_setup_completed) { | |
266 start_stop_button_label = | |
267 l10n_util::GetStringUTF16(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL); | |
268 #if defined(OS_CHROMEOS) | |
269 is_start_stop_button_visible = false; | |
270 #else | |
271 is_start_stop_button_visible = true; | |
272 #endif // defined(OS_CHROMEOS) | |
273 is_start_stop_button_enabled = !managed; | |
274 } else if (service->SetupInProgress()) { | |
275 start_stop_button_label = | |
276 l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS); | |
277 is_start_stop_button_visible = true; | |
278 is_start_stop_button_enabled = false; | |
279 } else { | |
280 start_stop_button_label = | |
281 l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL, | |
282 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)); | |
283 is_start_stop_button_visible = true; | |
284 is_start_stop_button_enabled = !managed; | |
285 } | |
286 | |
287 scoped_ptr<Value> completed(Value::CreateBooleanValue(sync_setup_completed)); | |
288 web_ui_->CallJavascriptFunction("PersonalOptions.setSyncSetupCompleted", | |
289 *completed); | |
290 | |
291 scoped_ptr<Value> label(Value::CreateStringValue(status_label)); | |
292 web_ui_->CallJavascriptFunction("PersonalOptions.setSyncStatus", *label); | |
293 | |
294 scoped_ptr<Value> enabled( | |
295 Value::CreateBooleanValue(is_start_stop_button_enabled)); | |
296 web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonEnabled", | |
297 *enabled); | |
298 | |
299 scoped_ptr<Value> visible( | |
300 Value::CreateBooleanValue(is_start_stop_button_visible)); | |
301 web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonVisible", | |
302 *visible); | |
303 | |
304 label.reset(Value::CreateStringValue(start_stop_button_label)); | |
305 web_ui_->CallJavascriptFunction("PersonalOptions.setStartStopButtonLabel", | |
306 *label); | |
307 | |
308 label.reset(Value::CreateStringValue(link_label)); | |
309 web_ui_->CallJavascriptFunction("PersonalOptions.setSyncActionLinkLabel", | |
310 *label); | |
311 | |
312 enabled.reset(Value::CreateBooleanValue(!managed)); | |
313 web_ui_->CallJavascriptFunction("PersonalOptions.setSyncActionLinkEnabled", | |
314 *enabled); | |
315 | |
316 visible.reset(Value::CreateBooleanValue(status_has_error)); | |
317 web_ui_->CallJavascriptFunction("PersonalOptions.setSyncStatusErrorVisible", | |
318 *visible); | |
319 | |
320 enabled.reset(Value::CreateBooleanValue( | |
321 !service->unrecoverable_error_detected())); | |
322 web_ui_->CallJavascriptFunction( | |
323 "PersonalOptions.setCustomizeSyncButtonEnabled", | |
324 *enabled); | |
325 | |
326 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAutologin)) { | |
327 visible.reset(Value::CreateBooleanValue( | |
328 service->AreCredentialsAvailable())); | |
329 web_ui_->CallJavascriptFunction("PersonalOptions.setAutoLoginVisible", | |
330 *visible); | |
331 } | |
332 | |
333 // Set profile creation text and button if multi-profiles switch is on. | |
334 visible.reset(Value::CreateBooleanValue(multiprofile_)); | |
335 web_ui_->CallJavascriptFunction("PersonalOptions.setProfilesSectionVisible", | |
336 *visible); | |
337 if (multiprofile_) | |
338 SendProfilesInfo(); | |
339 } | |
340 | |
341 void PersonalOptionsHandler::ObserveThemeChanged() { | |
342 Profile* profile = Profile::FromWebUI(web_ui_); | |
343 #if defined(TOOLKIT_GTK) | |
344 GtkThemeService* theme_service = GtkThemeService::GetFrom(profile); | |
345 bool is_gtk_theme = theme_service->UsingNativeTheme(); | |
346 base::FundamentalValue gtk_enabled(!is_gtk_theme); | |
347 web_ui_->CallJavascriptFunction( | |
348 "options.PersonalOptions.setGtkThemeButtonEnabled", gtk_enabled); | |
349 #else | |
350 ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile); | |
351 bool is_gtk_theme = false; | |
352 #endif | |
353 | |
354 bool is_classic_theme = !is_gtk_theme && theme_service->UsingDefaultTheme(); | |
355 base::FundamentalValue enabled(!is_classic_theme); | |
356 web_ui_->CallJavascriptFunction( | |
357 "options.PersonalOptions.setThemesResetButtonEnabled", enabled); | |
358 } | |
359 | |
360 void PersonalOptionsHandler::Initialize() { | |
361 Profile* profile = Profile::FromWebUI(web_ui_); | |
362 | |
363 // Listen for theme installation. | |
364 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, | |
365 content::Source<ThemeService>( | |
366 ThemeServiceFactory::GetForProfile(profile))); | |
367 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, | |
368 content::NotificationService::AllSources()); | |
369 ObserveThemeChanged(); | |
370 | |
371 ProfileSyncService* sync_service = profile->GetProfileSyncService(); | |
372 if (sync_service) { | |
373 sync_service->AddObserver(this); | |
374 OnStateChanged(); | |
375 } else { | |
376 web_ui_->CallJavascriptFunction("options.PersonalOptions.hideSyncSection"); | |
377 } | |
378 } | |
379 | |
380 void PersonalOptionsHandler::ThemesReset(const ListValue* args) { | |
381 UserMetrics::RecordAction(UserMetricsAction("Options_ThemesReset")); | |
382 Profile* profile = Profile::FromWebUI(web_ui_); | |
383 ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme(); | |
384 } | |
385 | |
386 #if defined(TOOLKIT_GTK) | |
387 void PersonalOptionsHandler::ThemesSetGTK(const ListValue* args) { | |
388 UserMetrics::RecordAction(UserMetricsAction("Options_GtkThemeSet")); | |
389 Profile* profile = Profile::FromWebUI(web_ui_); | |
390 ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme(); | |
391 } | |
392 #endif | |
393 | |
394 #if defined(OS_CHROMEOS) | |
395 void PersonalOptionsHandler::UpdateAccountPicture() { | |
396 std::string email = chromeos::UserManager::Get()->logged_in_user().email(); | |
397 if (!email.empty()) { | |
398 web_ui_->CallJavascriptFunction("PersonalOptions.updateAccountPicture"); | |
399 base::StringValue email_value(email); | |
400 web_ui_->CallJavascriptFunction("AccountsOptions.updateAccountPicture", | |
401 email_value); | |
402 } | |
403 } | |
404 #endif | |
405 | |
406 void PersonalOptionsHandler::SendProfilesInfo() { | |
407 ProfileInfoCache& cache = | |
408 g_browser_process->profile_manager()->GetProfileInfoCache(); | |
409 ListValue profile_info_list; | |
410 FilePath current_profile_path = | |
411 web_ui_->tab_contents()->browser_context()->GetPath(); | |
412 for (size_t i = 0, e = cache.GetNumberOfProfiles(); i < e; ++i) { | |
413 DictionaryValue* profile_value = new DictionaryValue(); | |
414 FilePath profile_path = cache.GetPathOfProfileAtIndex(i); | |
415 profile_value->SetString("name", cache.GetNameOfProfileAtIndex(i)); | |
416 profile_value->Set("filePath", base::CreateFilePathValue(profile_path)); | |
417 profile_value->SetBoolean("isCurrentProfile", | |
418 profile_path == current_profile_path); | |
419 | |
420 bool is_gaia_picture = | |
421 cache.IsUsingGAIAPictureOfProfileAtIndex(i) && | |
422 cache.GetGAIAPictureOfProfileAtIndex(i); | |
423 if (is_gaia_picture) { | |
424 gfx::Image icon = profiles::GetAvatarIconForWebUI( | |
425 cache.GetAvatarIconOfProfileAtIndex(i), true); | |
426 profile_value->SetString("iconURL", web_ui_util::GetImageDataUrl(icon)); | |
427 } else { | |
428 size_t icon_index = cache.GetAvatarIconIndexOfProfileAtIndex(i); | |
429 profile_value->SetString("iconURL", | |
430 cache.GetDefaultAvatarIconUrl(icon_index)); | |
431 } | |
432 | |
433 profile_info_list.Append(profile_value); | |
434 } | |
435 | |
436 web_ui_->CallJavascriptFunction("PersonalOptions.setProfilesInfo", | |
437 profile_info_list); | |
438 } | |
439 | |
440 void PersonalOptionsHandler::CreateProfile(const ListValue* args) { | |
441 ProfileManager::CreateMultiProfileAsync(); | |
442 } | |
OLD | NEW |