1 // Copyright 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/signin/user_manager_screen_handler.h" 6 7 #include "base/bind.h" 8 #include "base/value_conversions.h" 9 #include "base/values.h" 10 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/profiles/avatar_menu_model.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/profiles/profile_info_cache.h" 14 #include "chrome/browser/profiles/profile_info_cache_observer.h" 15 #include "chrome/browser/profiles/profile_info_util.h" 16 #include "chrome/browser/profiles/profile_manager.h" 17 #include "chrome/browser/profiles/profile_window.h" 18 #include "chrome/browser/profiles/profiles_state.h" 19 #include "chrome/browser/ui/browser_finder.h" 20 #include "chrome/browser/ui/singleton_tabs.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_ui.h" 23 #include "grit/browser_resources.h" 24 #include "grit/chromium_strings.h" 25 #include "grit/generated_resources.h" 26 #include "third_party/skia/include/core/SkBitmap.h" 27 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/gfx/image/image_util.h" 29 #include "ui/webui/web_ui_util.h" 30 31 #if defined(ENABLE_MANAGED_USERS) 32 #include "chrome/browser/managed_mode/managed_user_service.h" 33 #endif 34 35 namespace { 36 // User dictionary keys. 37 const char kKeyUsername[] = "username"; 38 const char kKeyDisplayName[]= "displayName"; 39 const char kKeyEmailAddress[] = "emailAddress"; 40 const char kKeyProfilePath[] = "profilePath"; 41 const char kKeyPublicAccount[] = "publicAccount"; 42 const char kKeyLocallyManagedUser[] = "locallyManagedUser"; 43 const char kKeySignedIn[] = "signedIn"; 44 const char kKeyCanRemove[] = "canRemove"; 45 const char kKeyIsOwner[] = "isOwner"; 46 const char kKeyIsDesktop[] = "isDesktopUser"; 47 const char kKeyAvatarUrl[] = "userImage"; 48 const char kKeyNeedsSignin[] = "needsSignin"; 49 const char kGAIAPictureFileNameKey[] = "gaia_picture_file_name"; 50 51 // Max number of users to show. 52 const size_t kMaxUsers = 18; 53 54 // Type of the login screen UI that is currently presented to user. 55 const char kSourceGaiaSignin[] = "gaia-signin"; 56 const char kSourceAccountPicker[] = "account-picker"; 57 58 // JS API callback names. 59 const char kJsApiUserManagerInitialize[] = "userManagerInitialize"; 60 const char kJsApiUserManagerAddUser[] = "addUser"; 61 const char kJsApiUserManagerLaunchGuest[] = "launchGuest"; 62 const char kJsApiUserManagerLaunchUser[] = "launchUser"; 63 const char kJsApiUserManagerRemoveUser[] = "removeUser"; 64 65 const size_t kAvatarIconSize = 160; 66 67 void HandleAndDoNothing(const base::ListValue* args) { 68 } 69 70 // This callback is run if the only profile has been deleted, and a new 71 // profile has been created to replace it. 72 void OpenNewWindowForProfile( 73 chrome::HostDesktopType desktop_type, 74 Profile* profile, 75 Profile::CreateStatus status) { 76 if (status != Profile::CREATE_STATUS_INITIALIZED) 77 return; 78 profiles::FindOrCreateNewWindowForProfile( 79 profile, 80 chrome::startup::IS_PROCESS_STARTUP, 81 chrome::startup::IS_FIRST_RUN, 82 desktop_type, 83 false); 84 } 85 86 std::string GetAvatarImageAtIndex( 87 size_t index, const ProfileInfoCache& info_cache) { 88 bool is_gaia_picture = 89 info_cache.IsUsingGAIAPictureOfProfileAtIndex(index) && 90 info_cache.GetGAIAPictureOfProfileAtIndex(index); 91 92 gfx::Image icon = profiles::GetSizedAvatarIconWithBorder( 93 info_cache.GetAvatarIconOfProfileAtIndex(index), 94 is_gaia_picture, kAvatarIconSize, kAvatarIconSize); 95 return webui::GetBitmapDataUrl(icon.AsBitmap()); 96 } 97 98 } // namespace 99 100 // ProfileUpdateObserver ------------------------------------------------------ 101 102 class UserManagerScreenHandler::ProfileUpdateObserver 103 : public ProfileInfoCacheObserver { 104 public: 105 ProfileUpdateObserver( 106 ProfileManager* profile_manager, UserManagerScreenHandler* handler) 107 : profile_manager_(profile_manager), 108 user_manager_handler_(handler) { 109 DCHECK(profile_manager_); 110 DCHECK(user_manager_handler_); 111 profile_manager_->GetProfileInfoCache().AddObserver(this); 112 } 113 114 virtual ~ProfileUpdateObserver() { 115 DCHECK(profile_manager_); 116 profile_manager_->GetProfileInfoCache().RemoveObserver(this); 117 } 118 119 private: 120 // ProfileInfoCacheObserver implementation: 121 // If any change has been made to a profile, propagate it to all the 122 // visible user manager screens. 123 virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE { 124 user_manager_handler_->SendUserList(); 125 } 126 127 virtual void OnProfileWasRemoved(const base::FilePath& profile_path, 128 const string16& profile_name) OVERRIDE { 129 user_manager_handler_->SendUserList(); 130 } 131 132 virtual void OnProfileWillBeRemoved( 133 const base::FilePath& profile_path) OVERRIDE { 134 // No-op. When the profile is actually removed, OnProfileWasRemoved 135 // will be called. 136 } 137 138 virtual void OnProfileNameChanged(const base::FilePath& profile_path, 139 const string16& old_profile_name) OVERRIDE { 140 user_manager_handler_->SendUserList(); 141 } 142 143 virtual void OnProfileAvatarChanged( 144 const base::FilePath& profile_path) OVERRIDE { 145 user_manager_handler_->SendUserList(); 146 } 147 148 ProfileManager* profile_manager_; 149 150 UserManagerScreenHandler* user_manager_handler_; // Weak; owns us. 151 152 DISALLOW_COPY_AND_ASSIGN(ProfileUpdateObserver); 153 }; 154 155 // UserManagerScreenHandler --------------------------------------------------- 156 157 UserManagerScreenHandler::UserManagerScreenHandler() { 158 profileInfoCacheObserver_.reset( 159 new UserManagerScreenHandler::ProfileUpdateObserver( 160 g_browser_process->profile_manager(), this)); 161 } 162 163 UserManagerScreenHandler::~UserManagerScreenHandler() { 164 } 165 166 void UserManagerScreenHandler::HandleInitialize(const base::ListValue* args) { 167 SendUserList(); 168 web_ui()->CallJavascriptFunction("cr.ui.Oobe.showUserManagerScreen"); 169 } 170 171 void UserManagerScreenHandler::HandleAddUser(const base::ListValue* args) { 172 // TODO(noms): Should redirect to a sign in page. 173 chrome::ShowSingletonTab(chrome::FindBrowserWithWebContents( 174 web_ui()->GetWebContents()), 175 GURL("chrome://settings/createProfile")); 176 } 177 178 void UserManagerScreenHandler::HandleRemoveUser(const base::ListValue* args) { 179 DCHECK(args); 180 const Value* profile_path_value; 181 if (!args->Get(0, &profile_path_value)) 182 return; 183 184 base::FilePath profile_path; 185 if (!base::GetValueAsFilePath(*profile_path_value, &profile_path)) 186 return; 187 188 // This handler could have been called in managed mode, for example because 189 // the user fiddled with the web inspector. Silently return in this case. 190 if (Profile::FromWebUI(web_ui())->IsManaged()) 191 return; 192 193 if (!profiles::IsMultipleProfilesEnabled()) 194 return; 195 196 Browser* browser = 197 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); 198 DCHECK(browser); 199 200 chrome::HostDesktopType desktop_type = browser->host_desktop_type(); 201 g_browser_process->profile_manager()->ScheduleProfileForDeletion( 202 profile_path, 203 base::Bind(&OpenNewWindowForProfile, desktop_type)); 204 } 205 206 void UserManagerScreenHandler::HandleLaunchGuest(const base::ListValue* args) { 207 AvatarMenuModel::SwitchToGuestProfileWindow( 208 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents())); 209 } 210 211 void UserManagerScreenHandler::HandleLaunchUser(const base::ListValue* args) { 212 string16 emailAddress; 213 string16 displayName; 214 215 if (!args->GetString(0, &emailAddress) || 216 !args->GetString(1, &displayName)) { 217 NOTREACHED(); 218 return; 219 } 220 221 ProfileInfoCache& info_cache = 222 g_browser_process->profile_manager()->GetProfileInfoCache(); 223 chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); 224 225 for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) { 226 if (info_cache.GetUserNameOfProfileAtIndex(i) == emailAddress && 227 info_cache.GetNameOfProfileAtIndex(i) == displayName) { 228 base::FilePath path = info_cache.GetPathOfProfileAtIndex(i); 229 profiles::SwitchToProfile(path, desktop_type, true); 230 break; 231 } 232 } 233 } 234 235 void UserManagerScreenHandler::RegisterMessages() { 236 web_ui()->RegisterMessageCallback(kJsApiUserManagerInitialize, 237 base::Bind(&UserManagerScreenHandler::HandleInitialize, 238 base::Unretained(this))); 239 web_ui()->RegisterMessageCallback(kJsApiUserManagerAddUser, 240 base::Bind(&UserManagerScreenHandler::HandleAddUser, 241 base::Unretained(this))); 242 web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchGuest, 243 base::Bind(&UserManagerScreenHandler::HandleLaunchGuest, 244 base::Unretained(this))); 245 web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchUser, 246 base::Bind(&UserManagerScreenHandler::HandleLaunchUser, 247 base::Unretained(this))); 248 web_ui()->RegisterMessageCallback(kJsApiUserManagerRemoveUser, 249 base::Bind(&UserManagerScreenHandler::HandleRemoveUser, 250 base::Unretained(this))); 251 252 const content::WebUI::MessageCallback& kDoNothingCallback = 253 base::Bind(&HandleAndDoNothing); 254 255 // Unused callbacks from screen_account_picker.js 256 web_ui()->RegisterMessageCallback("accountPickerReady", kDoNothingCallback); 257 web_ui()->RegisterMessageCallback("loginUIStateChanged", kDoNothingCallback); 258 web_ui()->RegisterMessageCallback("hideCaptivePortal", kDoNothingCallback); 259 // Unused callbacks from display_manager.js 260 web_ui()->RegisterMessageCallback("showAddUser", kDoNothingCallback); 261 web_ui()->RegisterMessageCallback("loadWallpaper", kDoNothingCallback); 262 web_ui()->RegisterMessageCallback("updateCurrentScreen", kDoNothingCallback); 263 web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback); 264 } 265 266 void UserManagerScreenHandler::GetLocalizedValues( 267 base::DictionaryValue* localized_strings) { 268 // For Control Bar. 269 localized_strings->SetString("signedIn", 270 l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_ACTIVE_USER)); 271 localized_strings->SetString("signinButton", 272 l10n_util::GetStringUTF16(IDS_LOGIN_BUTTON)); 273 localized_strings->SetString("addUser", 274 l10n_util::GetStringUTF16(IDS_ADD_USER_BUTTON)); 275 localized_strings->SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); 276 localized_strings->SetString("browseAsGuest", 277 l10n_util::GetStringUTF16(IDS_GO_INCOGNITO_BUTTON)); 278 localized_strings->SetString("signOutUser", 279 l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT)); 280 281 // For AccountPickerScreen. 282 localized_strings->SetString("screenType", "login-add-user"); 283 localized_strings->SetString("highlightStrength", "normal"); 284 localized_strings->SetString("title", 285 l10n_util::GetStringUTF16(IDS_USER_MANAGER_SCREEN_TITLE)); 286 localized_strings->SetString("passwordHint", 287 l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT)); 288 localized_strings->SetString("podMenuButtonAccessibleName", 289 l10n_util::GetStringUTF16(IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME)); 290 localized_strings->SetString("podMenuRemoveItemAccessibleName", 291 l10n_util::GetStringUTF16( 292 IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME)); 293 localized_strings->SetString("removeUser", 294 l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON)); 295 localized_strings->SetString("passwordFieldAccessibleName", 296 l10n_util::GetStringUTF16(IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME)); 297 localized_strings->SetString("bootIntoWallpaper", "off"); 298 299 // For AccountPickerScreen, the remove user warning overlay. 300 localized_strings->SetString("removeUserWarningButtonTitle", 301 l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON)); 302 localized_strings->SetString("removeUserWarningText", 303 l10n_util::GetStringUTF16( 304 IDS_LOGIN_POD_USER_REMOVE_WARNING)); 305 306 // Strings needed for the user_pod_template public account div, but not ever 307 // actually displayed for desktop users. 308 localized_strings->SetString("publicAccountReminder", string16()); 309 localized_strings->SetString("publicAccountEnter", string16()); 310 localized_strings->SetString("publicAccountEnterAccessibleName", string16()); 311 } 312 313 void UserManagerScreenHandler::SendUserList() { 314 ListValue users_list; 315 base::FilePath active_profile_path = 316 web_ui()->GetWebContents()->GetBrowserContext()->GetPath(); 317 const ProfileInfoCache& info_cache = 318 g_browser_process->profile_manager()->GetProfileInfoCache(); 319 320 // If the active user is a managed user, then they may not perform 321 // certain actions (i.e. delete another user). 322 bool active_user_is_managed = Profile::FromWebUI(web_ui())->IsManaged(); 323 for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) { 324 DictionaryValue* profile_value = new DictionaryValue(); 325 326 base::FilePath profile_path = info_cache.GetPathOfProfileAtIndex(i); 327 bool is_active_user = (profile_path == active_profile_path); 328 329 profile_value->SetString( 330 kKeyUsername, info_cache.GetUserNameOfProfileAtIndex(i)); 331 profile_value->SetString( 332 kKeyEmailAddress, info_cache.GetUserNameOfProfileAtIndex(i)); 333 profile_value->SetString( 334 kKeyDisplayName, info_cache.GetNameOfProfileAtIndex(i)); 335 profile_value->SetString(kKeyProfilePath, profile_path.MaybeAsASCII()); 336 profile_value->SetBoolean(kKeyPublicAccount, false); 337 profile_value->SetBoolean(kKeyLocallyManagedUser, false); 338 profile_value->SetBoolean(kKeySignedIn, is_active_user); 339 profile_value->SetBoolean( 340 kKeyNeedsSignin, info_cache.ProfileIsSigninRequiredAtIndex(i)); 341 profile_value->SetBoolean(kKeyIsOwner, false); 342 profile_value->SetBoolean(kKeyCanRemove, !active_user_is_managed); 343 profile_value->SetBoolean(kKeyIsDesktop, true); 344 profile_value->SetString( 345 kKeyAvatarUrl, GetAvatarImageAtIndex(i, info_cache)); 346 347 // The row of user pods should display the active user first. 348 if (is_active_user) 349 users_list.Insert(0, profile_value); 350 else 351 users_list.Append(profile_value); 352 } 353 354 web_ui()->CallJavascriptFunction("login.AccountPickerScreen.loadUsers", 355 users_list, base::FundamentalValue(false), base::FundamentalValue(true)); 356 } 357