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