manage_profile_handler.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/ui/webui/options/manage_profile_handler.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/command_line.h" 10#include "base/prefs/pref_service.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/value_conversions.h" 14#include "base/values.h" 15#include "chrome/browser/browser_process.h" 16#include "chrome/browser/profiles/gaia_info_update_service.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/browser/profiles/profile_info_cache.h" 19#include "chrome/browser/profiles/profile_info_util.h" 20#include "chrome/browser/profiles/profile_manager.h" 21#include "chrome/browser/profiles/profile_metrics.h" 22#include "chrome/browser/profiles/profile_shortcut_manager.h" 23#include "chrome/browser/signin/signin_manager.h" 24#include "chrome/browser/signin/signin_manager_factory.h" 25#include "chrome/browser/ui/browser_finder.h" 26#include "chrome/common/chrome_notification_types.h" 27#include "chrome/common/chrome_switches.h" 28#include "chrome/common/pref_names.h" 29#include "content/public/browser/browser_thread.h" 30#include "content/public/browser/notification_service.h" 31#include "content/public/browser/web_ui.h" 32#include "grit/generated_resources.h" 33#include "ui/base/l10n/l10n_util.h" 34#include "ui/webui/web_ui_util.h" 35 36#if defined(ENABLE_MANAGED_USERS) 37#include "chrome/browser/managed_mode/managed_user_service.h" 38#include "chrome/browser/managed_mode/managed_user_service_factory.h" 39#endif 40 41#if defined(ENABLE_SETTINGS_APP) 42#include "chrome/browser/ui/app_list/app_list_service.h" 43#include "content/public/browser/web_contents.h" 44#endif 45 46namespace options { 47 48namespace { 49 50const char kCreateProfileIconGridName[] = "create-profile-icon-grid"; 51const char kManageProfileIconGridName[] = "manage-profile-icon-grid"; 52 53// Given |args| from the WebUI, parses value 0 as a FilePath |profile_file_path| 54// and returns true on success. 55bool GetProfilePathFromArgs(const ListValue* args, 56 base::FilePath* profile_file_path) { 57 const Value* file_path_value; 58 if (!args->Get(0, &file_path_value)) 59 return false; 60 return base::GetValueAsFilePath(*file_path_value, profile_file_path); 61} 62 63void OnNewDefaultProfileCreated( 64 chrome::HostDesktopType desktop_type, 65 Profile* profile, 66 Profile::CreateStatus status) { 67 if (status == Profile::CREATE_STATUS_INITIALIZED) { 68 ProfileManager::FindOrCreateNewWindowForProfile( 69 profile, 70 chrome::startup::IS_PROCESS_STARTUP, 71 chrome::startup::IS_FIRST_RUN, 72 desktop_type, 73 false); 74 } 75} 76 77} // namespace 78 79ManageProfileHandler::ManageProfileHandler() 80 : weak_factory_(this) { 81} 82 83ManageProfileHandler::~ManageProfileHandler() { 84} 85 86void ManageProfileHandler::GetLocalizedValues( 87 DictionaryValue* localized_strings) { 88 DCHECK(localized_strings); 89 90 static OptionsStringResource resources[] = { 91 { "manageProfilesNameLabel", IDS_PROFILES_MANAGE_NAME_LABEL }, 92 { "manageProfilesDuplicateNameError", 93 IDS_PROFILES_MANAGE_DUPLICATE_NAME_ERROR }, 94 { "manageProfilesIconLabel", IDS_PROFILES_MANAGE_ICON_LABEL }, 95 { "manageProfilesManagedSignedInLabel", 96 IDS_PROFILES_CREATE_MANAGED_SIGNED_IN_LABEL }, 97 { "manageProfilesManagedNotSignedInLabel", 98 IDS_PROFILES_CREATE_MANAGED_NOT_SIGNED_IN_LABEL }, 99 { "manageProfilesManagedNotSignedInLink", 100 IDS_PROFILES_CREATE_MANAGED_NOT_SIGNED_IN_LINK }, 101 { "deleteProfileTitle", IDS_PROFILES_DELETE_TITLE }, 102 { "deleteProfileOK", IDS_PROFILES_DELETE_OK_BUTTON_LABEL }, 103 { "deleteProfileMessage", IDS_PROFILES_DELETE_MESSAGE }, 104 { "deleteManagedProfileAddendum", IDS_PROFILES_DELETE_MANAGED_ADDENDUM }, 105 { "createProfileTitle", IDS_PROFILES_CREATE_TITLE }, 106 { "createProfileInstructions", IDS_PROFILES_CREATE_INSTRUCTIONS }, 107 { "createProfileConfirm", IDS_PROFILES_CREATE_CONFIRM }, 108 { "createProfileLocalError", IDS_PROFILES_CREATE_LOCAL_ERROR }, 109 { "createProfileRemoteError", IDS_PROFILES_CREATE_REMOTE_ERROR }, 110 { "createProfileShortcutCheckbox", IDS_PROFILES_CREATE_SHORTCUT_CHECKBOX }, 111 { "createProfileShortcutButton", IDS_PROFILES_CREATE_SHORTCUT_BUTTON }, 112 { "removeProfileShortcutButton", IDS_PROFILES_REMOVE_SHORTCUT_BUTTON }, 113 }; 114 115 RegisterStrings(localized_strings, resources, arraysize(resources)); 116 RegisterTitle(localized_strings, "manageProfile", 117 IDS_PROFILES_MANAGE_TITLE); 118 RegisterTitle(localized_strings, "createProfile", 119 IDS_PROFILES_CREATE_TITLE); 120 121 localized_strings->SetBoolean("profileShortcutsEnabled", 122 ProfileShortcutManager::IsFeatureEnabled()); 123 localized_strings->SetBoolean("managedUsersEnabled", 124 ManagedUserService::AreManagedUsersEnabled()); 125} 126 127void ManageProfileHandler::InitializeHandler() { 128 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, 129 content::NotificationService::AllSources()); 130 131 pref_change_registrar_.Init(Profile::FromWebUI(web_ui())->GetPrefs()); 132 pref_change_registrar_.Add( 133 prefs::kManagedUserCreationAllowed, 134 base::Bind(&ManageProfileHandler::OnCreateManagedUserPrefChange, 135 base::Unretained(this))); 136} 137 138void ManageProfileHandler::InitializePage() { 139 SendProfileNames(); 140 OnCreateManagedUserPrefChange(); 141} 142 143void ManageProfileHandler::RegisterMessages() { 144 web_ui()->RegisterMessageCallback("setProfileNameAndIcon", 145 base::Bind(&ManageProfileHandler::SetProfileNameAndIcon, 146 base::Unretained(this))); 147 web_ui()->RegisterMessageCallback("requestDefaultProfileIcons", 148 base::Bind(&ManageProfileHandler::RequestDefaultProfileIcons, 149 base::Unretained(this))); 150 web_ui()->RegisterMessageCallback("requestNewProfileDefaults", 151 base::Bind(&ManageProfileHandler::RequestNewProfileDefaults, 152 base::Unretained(this))); 153 web_ui()->RegisterMessageCallback("requestHasProfileShortcuts", 154 base::Bind(&ManageProfileHandler::RequestHasProfileShortcuts, 155 base::Unretained(this))); 156 web_ui()->RegisterMessageCallback("requestCreateProfileUpdate", 157 base::Bind(&ManageProfileHandler::RequestCreateProfileUpdate, 158 base::Unretained(this))); 159 web_ui()->RegisterMessageCallback("profileIconSelectionChanged", 160 base::Bind(&ManageProfileHandler::ProfileIconSelectionChanged, 161 base::Unretained(this))); 162#if defined(ENABLE_SETTINGS_APP) 163 web_ui()->RegisterMessageCallback("switchAppListProfile", 164 base::Bind(&ManageProfileHandler::SwitchAppListProfile, 165 base::Unretained(this))); 166#endif 167 web_ui()->RegisterMessageCallback("addProfileShortcut", 168 base::Bind(&ManageProfileHandler::AddProfileShortcut, 169 base::Unretained(this))); 170 web_ui()->RegisterMessageCallback("removeProfileShortcut", 171 base::Bind(&ManageProfileHandler::RemoveProfileShortcut, 172 base::Unretained(this))); 173} 174 175void ManageProfileHandler::Observe( 176 int type, 177 const content::NotificationSource& source, 178 const content::NotificationDetails& details) { 179 if (type == chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED) { 180 SendProfileNames(); 181 base::StringValue value(kManageProfileIconGridName); 182 SendProfileIcons(value); 183 } else { 184 OptionsPageUIHandler::Observe(type, source, details); 185 } 186} 187 188void ManageProfileHandler::RequestDefaultProfileIcons(const ListValue* args) { 189 base::StringValue create_value(kCreateProfileIconGridName); 190 base::StringValue manage_value(kManageProfileIconGridName); 191 SendProfileIcons(manage_value); 192 SendProfileIcons(create_value); 193} 194 195void ManageProfileHandler::RequestNewProfileDefaults(const ListValue* args) { 196 const ProfileInfoCache& cache = 197 g_browser_process->profile_manager()->GetProfileInfoCache(); 198 const size_t icon_index = cache.ChooseAvatarIconIndexForNewProfile(); 199 200 DictionaryValue profile_info; 201 profile_info.SetString("name", cache.ChooseNameForNewProfile(icon_index)); 202 profile_info.SetString("iconURL", cache.GetDefaultAvatarIconUrl(icon_index)); 203 204 web_ui()->CallJavascriptFunction( 205 "ManageProfileOverlay.receiveNewProfileDefaults", profile_info); 206} 207 208void ManageProfileHandler::SendProfileIcons( 209 const base::StringValue& icon_grid) { 210 ListValue image_url_list; 211 212 // First add the GAIA picture if it's available. 213 const ProfileInfoCache& cache = 214 g_browser_process->profile_manager()->GetProfileInfoCache(); 215 Profile* profile = Profile::FromWebUI(web_ui()); 216 size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath()); 217 if (profile_index != std::string::npos) { 218 const gfx::Image* icon = 219 cache.GetGAIAPictureOfProfileAtIndex(profile_index); 220 if (icon) { 221 gfx::Image icon2 = profiles::GetAvatarIconForWebUI(*icon, true); 222 gaia_picture_url_ = webui::GetBitmapDataUrl(icon2.AsBitmap()); 223 image_url_list.Append(new base::StringValue(gaia_picture_url_)); 224 } 225 } 226 227 // Next add the default avatar icons. 228 for (size_t i = 0; i < ProfileInfoCache::GetDefaultAvatarIconCount(); i++) { 229 std::string url = ProfileInfoCache::GetDefaultAvatarIconUrl(i); 230 image_url_list.Append(new base::StringValue(url)); 231 } 232 233 web_ui()->CallJavascriptFunction( 234 "ManageProfileOverlay.receiveDefaultProfileIcons", icon_grid, 235 image_url_list); 236} 237 238void ManageProfileHandler::SendProfileNames() { 239 const ProfileInfoCache& cache = 240 g_browser_process->profile_manager()->GetProfileInfoCache(); 241 DictionaryValue profile_name_dict; 242 for (size_t i = 0, e = cache.GetNumberOfProfiles(); i < e; ++i) 243 profile_name_dict.SetBoolean(UTF16ToUTF8(cache.GetNameOfProfileAtIndex(i)), 244 true); 245 246 web_ui()->CallJavascriptFunction("ManageProfileOverlay.receiveProfileNames", 247 profile_name_dict); 248} 249 250void ManageProfileHandler::SetProfileNameAndIcon(const ListValue* args) { 251 DCHECK(args); 252 253 base::FilePath profile_file_path; 254 if (!GetProfilePathFromArgs(args, &profile_file_path)) 255 return; 256 257 ProfileInfoCache& cache = 258 g_browser_process->profile_manager()->GetProfileInfoCache(); 259 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); 260 if (profile_index == std::string::npos) 261 return; 262 263 Profile* profile = 264 g_browser_process->profile_manager()->GetProfile(profile_file_path); 265 if (!profile) 266 return; 267 268 string16 new_profile_name; 269 if (!args->GetString(1, &new_profile_name)) 270 return; 271 if (new_profile_name == cache.GetGAIANameOfProfileAtIndex(profile_index)) { 272 // Set the profile to use the GAIA name as the profile name. Note, this 273 // is a little weird if the user typed their GAIA name manually but 274 // it's not a big deal. 275 cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, true); 276 // Using the GAIA name as the profile name can invalidate the profile index. 277 profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); 278 if (profile_index == std::string::npos) 279 return; 280 } else { 281 PrefService* pref_service = profile->GetPrefs(); 282 // Updating the profile preference will cause the cache to be updated for 283 // this preference. 284 pref_service->SetString(prefs::kProfileName, UTF16ToUTF8(new_profile_name)); 285 286 // Changing the profile name can invalidate the profile index. 287 profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); 288 if (profile_index == std::string::npos) 289 return; 290 291 cache.SetIsUsingGAIANameOfProfileAtIndex(profile_index, false); 292 // Unsetting the GAIA name as the profile name can invalidate the profile 293 // index. 294 profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); 295 if (profile_index == std::string::npos) 296 return; 297 } 298 299 std::string icon_url; 300 if (!args->GetString(2, &icon_url)) 301 return; 302 303 // Metrics logging variable. 304 bool previously_using_gaia_icon = 305 cache.IsUsingGAIANameOfProfileAtIndex(profile_index); 306 307 size_t new_icon_index; 308 if (icon_url == gaia_picture_url_) { 309 cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, true); 310 if (!previously_using_gaia_icon) { 311 // Only log if they changed to the GAIA photo. 312 // Selection of GAIA photo as avatar is logged as part of the function 313 // below. 314 ProfileMetrics::LogProfileSwitchGaia(ProfileMetrics::GAIA_OPT_IN); 315 } 316 } else if (cache.IsDefaultAvatarIconUrl(icon_url, &new_icon_index)) { 317 ProfileMetrics::LogProfileAvatarSelection(new_icon_index); 318 PrefService* pref_service = profile->GetPrefs(); 319 // Updating the profile preference will cause the cache to be updated for 320 // this preference. 321 pref_service->SetInteger(prefs::kProfileAvatarIndex, new_icon_index); 322 cache.SetIsUsingGAIAPictureOfProfileAtIndex(profile_index, false); 323 } 324 ProfileMetrics::LogProfileUpdate(profile_file_path); 325} 326 327#if defined(ENABLE_SETTINGS_APP) 328void ManageProfileHandler::SwitchAppListProfile(const ListValue* args) { 329 DCHECK(args); 330 DCHECK(ProfileManager::IsMultipleProfilesEnabled()); 331 332 const Value* file_path_value; 333 base::FilePath profile_file_path; 334 if (!args->Get(0, &file_path_value) || 335 !base::GetValueAsFilePath(*file_path_value, &profile_file_path)) 336 return; 337 338 AppListService::Get()->SetAppListProfile(profile_file_path); 339 // Close the settings app, since it will now be for the wrong profile. 340 web_ui()->GetWebContents()->Close(); 341} 342#endif // defined(ENABLE_SETTINGS_APP) 343 344void ManageProfileHandler::ProfileIconSelectionChanged( 345 const base::ListValue* args) { 346 DCHECK(args); 347 348 base::FilePath profile_file_path; 349 if (!GetProfilePathFromArgs(args, &profile_file_path)) 350 return; 351 352 // Currently this only supports editing the current profile's info. 353 if (profile_file_path != Profile::FromWebUI(web_ui())->GetPath()) 354 return; 355 356 std::string icon_url; 357 if (!args->GetString(1, &icon_url)) 358 return; 359 360 if (icon_url != gaia_picture_url_) 361 return; 362 363 // If the selection is the GAIA picture then also show the GAIA name in the 364 // text field. 365 ProfileInfoCache& cache = 366 g_browser_process->profile_manager()->GetProfileInfoCache(); 367 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); 368 if (profile_index == std::string::npos) 369 return; 370 string16 gaia_name = cache.GetGAIANameOfProfileAtIndex(profile_index); 371 if (gaia_name.empty()) 372 return; 373 374 StringValue gaia_name_value(gaia_name); 375 web_ui()->CallJavascriptFunction("ManageProfileOverlay.setProfileName", 376 gaia_name_value); 377} 378 379void ManageProfileHandler::RequestHasProfileShortcuts(const ListValue* args) { 380 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 381 DCHECK(ProfileShortcutManager::IsFeatureEnabled()); 382 383 base::FilePath profile_file_path; 384 if (!GetProfilePathFromArgs(args, &profile_file_path)) 385 return; 386 387 const ProfileInfoCache& cache = 388 g_browser_process->profile_manager()->GetProfileInfoCache(); 389 size_t profile_index = cache.GetIndexOfProfileWithPath(profile_file_path); 390 if (profile_index == std::string::npos) 391 return; 392 393 const base::FilePath profile_path = 394 cache.GetPathOfProfileAtIndex(profile_index); 395 ProfileShortcutManager* shortcut_manager = 396 g_browser_process->profile_manager()->profile_shortcut_manager(); 397 shortcut_manager->HasProfileShortcuts( 398 profile_path, base::Bind(&ManageProfileHandler::OnHasProfileShortcuts, 399 weak_factory_.GetWeakPtr())); 400} 401 402void ManageProfileHandler::RequestCreateProfileUpdate( 403 const base::ListValue* args) { 404 SigninManagerBase* manager = 405 SigninManagerFactory::GetForProfile(Profile::FromWebUI(web_ui())); 406 string16 username = UTF8ToUTF16(manager->GetAuthenticatedUsername()); 407 StringValue username_value(username); 408 web_ui()->CallJavascriptFunction("CreateProfileOverlay.updateSignedInStatus", 409 username_value); 410 411 OnCreateManagedUserPrefChange(); 412} 413 414void ManageProfileHandler::OnCreateManagedUserPrefChange() { 415 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); 416 base::FundamentalValue allowed( 417 prefs->GetBoolean(prefs::kManagedUserCreationAllowed)); 418 web_ui()->CallJavascriptFunction( 419 "CreateProfileOverlay.updateManagedUsersAllowed", allowed); 420} 421 422void ManageProfileHandler::OnHasProfileShortcuts(bool has_shortcuts) { 423 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 424 425 const base::FundamentalValue has_shortcuts_value(has_shortcuts); 426 web_ui()->CallJavascriptFunction( 427 "ManageProfileOverlay.receiveHasProfileShortcuts", has_shortcuts_value); 428} 429 430void ManageProfileHandler::AddProfileShortcut(const base::ListValue* args) { 431 base::FilePath profile_file_path; 432 if (!GetProfilePathFromArgs(args, &profile_file_path)) 433 return; 434 435 DCHECK(ProfileShortcutManager::IsFeatureEnabled()); 436 ProfileShortcutManager* shortcut_manager = 437 g_browser_process->profile_manager()->profile_shortcut_manager(); 438 DCHECK(shortcut_manager); 439 440 shortcut_manager->CreateProfileShortcut(profile_file_path); 441 442 // Update the UI buttons. 443 OnHasProfileShortcuts(true); 444} 445 446void ManageProfileHandler::RemoveProfileShortcut(const base::ListValue* args) { 447 base::FilePath profile_file_path; 448 if (!GetProfilePathFromArgs(args, &profile_file_path)) 449 return; 450 451 DCHECK(ProfileShortcutManager::IsFeatureEnabled()); 452 ProfileShortcutManager* shortcut_manager = 453 g_browser_process->profile_manager()->profile_shortcut_manager(); 454 DCHECK(shortcut_manager); 455 456 shortcut_manager->RemoveProfileShortcuts(profile_file_path); 457 458 // Update the UI buttons. 459 OnHasProfileShortcuts(false); 460} 461 462} // namespace options 463