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/prefs/pref_service.h"
9#include "base/strings/utf_string_conversions.h"
10#include "base/value_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/chrome_notification_types.h"
14#include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/browser/profiles/profile_avatar_icon_util.h"
17#include "chrome/browser/profiles/profile_info_cache.h"
18#include "chrome/browser/profiles/profile_info_cache_observer.h"
19#include "chrome/browser/profiles/profile_manager.h"
20#include "chrome/browser/profiles/profile_metrics.h"
21#include "chrome/browser/profiles/profile_window.h"
22#include "chrome/browser/profiles/profiles_state.h"
23#include "chrome/browser/signin/local_auth.h"
24#include "chrome/browser/ui/browser_dialogs.h"
25#include "chrome/browser/ui/browser_finder.h"
26#include "chrome/browser/ui/browser_list.h"
27#include "chrome/browser/ui/chrome_pages.h"
28#include "chrome/browser/ui/singleton_tabs.h"
29#include "chrome/browser/ui/user_manager.h"
30#include "chrome/common/pref_names.h"
31#include "chrome/common/url_constants.h"
32#include "chrome/grit/chromium_strings.h"
33#include "chrome/grit/generated_resources.h"
34#include "content/public/browser/notification_service.h"
35#include "content/public/browser/web_contents.h"
36#include "content/public/browser/web_ui.h"
37#include "google_apis/gaia/gaia_auth_fetcher.h"
38#include "google_apis/gaia/gaia_constants.h"
39#include "third_party/skia/include/core/SkBitmap.h"
40#include "ui/base/l10n/l10n_util.h"
41#include "ui/base/resource/resource_bundle.h"
42#include "ui/base/webui/web_ui_util.h"
43#include "ui/gfx/image/image.h"
44#include "ui/gfx/image/image_skia.h"
45#include "ui/gfx/image/image_util.h"
46
47namespace {
48// User dictionary keys.
49const char kKeyUsername[] = "username";
50const char kKeyDisplayName[]= "displayName";
51const char kKeyEmailAddress[] = "emailAddress";
52const char kKeyProfilePath[] = "profilePath";
53const char kKeyPublicAccount[] = "publicAccount";
54const char kKeySupervisedUser[] = "supervisedUser";
55const char kKeySignedIn[] = "signedIn";
56const char kKeyCanRemove[] = "canRemove";
57const char kKeyIsOwner[] = "isOwner";
58const char kKeyIsDesktop[] = "isDesktopUser";
59const char kKeyAvatarUrl[] = "userImage";
60const char kKeyNeedsSignin[] = "needsSignin";
61
62// JS API callback names.
63const char kJsApiUserManagerInitialize[] = "userManagerInitialize";
64const char kJsApiUserManagerAddUser[] = "addUser";
65const char kJsApiUserManagerAuthLaunchUser[] = "authenticatedLaunchUser";
66const char kJsApiUserManagerLaunchGuest[] = "launchGuest";
67const char kJsApiUserManagerLaunchUser[] = "launchUser";
68const char kJsApiUserManagerRemoveUser[] = "removeUser";
69const char kJsApiUserManagerAttemptUnlock[] = "attemptUnlock";
70
71const size_t kAvatarIconSize = 180;
72
73void HandleAndDoNothing(const base::ListValue* args) {
74}
75
76// This callback is run if the only profile has been deleted, and a new
77// profile has been created to replace it.
78void OpenNewWindowForProfile(
79    chrome::HostDesktopType desktop_type,
80    Profile* profile,
81    Profile::CreateStatus status) {
82  if (status != Profile::CREATE_STATUS_INITIALIZED)
83    return;
84  profiles::FindOrCreateNewWindowForProfile(
85    profile,
86    chrome::startup::IS_PROCESS_STARTUP,
87    chrome::startup::IS_FIRST_RUN,
88    desktop_type,
89    false);
90}
91
92std::string GetAvatarImageAtIndex(
93    size_t index, const ProfileInfoCache& info_cache) {
94  bool is_gaia_picture =
95      info_cache.IsUsingGAIAPictureOfProfileAtIndex(index) &&
96      info_cache.GetGAIAPictureOfProfileAtIndex(index);
97
98  // If the avatar is too small (i.e. the old-style low resolution avatar),
99  // it will be pixelated when displayed in the User Manager, so we should
100  // return the placeholder avatar instead.
101  gfx::Image avatar_image = info_cache.GetAvatarIconOfProfileAtIndex(index);
102  if (avatar_image.Width() <= profiles::kAvatarIconWidth ||
103      avatar_image.Height() <= profiles::kAvatarIconHeight ) {
104    avatar_image = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
105        profiles::GetPlaceholderAvatarIconResourceID());
106  }
107  gfx::Image resized_image = profiles::GetSizedAvatarIcon(
108      avatar_image, is_gaia_picture, kAvatarIconSize, kAvatarIconSize);
109  return webui::GetBitmapDataUrl(resized_image.AsBitmap());
110}
111
112size_t GetIndexOfProfileWithEmailAndName(const ProfileInfoCache& info_cache,
113                                         const base::string16& email,
114                                         const base::string16& name) {
115  for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
116    if (info_cache.GetUserNameOfProfileAtIndex(i) == email &&
117        (name.empty() ||
118         profiles::GetAvatarNameForProfile(
119             info_cache.GetPathOfProfileAtIndex(i)) == name)) {
120      return i;
121    }
122  }
123  return std::string::npos;
124}
125
126extensions::ScreenlockPrivateEventRouter* GetScreenlockRouter(
127    const std::string& email) {
128  ProfileInfoCache& info_cache =
129      g_browser_process->profile_manager()->GetProfileInfoCache();
130  const size_t profile_index = GetIndexOfProfileWithEmailAndName(
131      info_cache, base::UTF8ToUTF16(email), base::string16());
132  Profile* profile = g_browser_process->profile_manager()
133      ->GetProfileByPath(info_cache.GetPathOfProfileAtIndex(profile_index));
134  return extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get(
135      profile);
136}
137
138bool IsGuestModeEnabled() {
139  PrefService* service = g_browser_process->local_state();
140  DCHECK(service);
141  return service->GetBoolean(prefs::kBrowserGuestModeEnabled);
142}
143
144bool IsAddPersonEnabled() {
145  PrefService* service = g_browser_process->local_state();
146  DCHECK(service);
147  return service->GetBoolean(prefs::kBrowserAddPersonEnabled);
148}
149
150}  // namespace
151
152// ProfileUpdateObserver ------------------------------------------------------
153
154class UserManagerScreenHandler::ProfileUpdateObserver
155    : public ProfileInfoCacheObserver {
156 public:
157  ProfileUpdateObserver(
158      ProfileManager* profile_manager, UserManagerScreenHandler* handler)
159      : profile_manager_(profile_manager),
160        user_manager_handler_(handler) {
161    DCHECK(profile_manager_);
162    DCHECK(user_manager_handler_);
163    profile_manager_->GetProfileInfoCache().AddObserver(this);
164  }
165
166  virtual ~ProfileUpdateObserver() {
167    DCHECK(profile_manager_);
168    profile_manager_->GetProfileInfoCache().RemoveObserver(this);
169  }
170
171 private:
172  // ProfileInfoCacheObserver implementation:
173  // If any change has been made to a profile, propagate it to all the
174  // visible user manager screens.
175  virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE {
176    user_manager_handler_->SendUserList();
177  }
178
179  virtual void OnProfileWasRemoved(
180      const base::FilePath& profile_path,
181      const base::string16& profile_name) OVERRIDE {
182    // TODO(noms): Change 'SendUserList' to 'removeUser' JS-call when
183    // UserManager is able to find pod belonging to removed user.
184    user_manager_handler_->SendUserList();
185  }
186
187  virtual void OnProfileNameChanged(
188      const base::FilePath& profile_path,
189      const base::string16& old_profile_name) OVERRIDE {
190    user_manager_handler_->SendUserList();
191  }
192
193  virtual void OnProfileAvatarChanged(
194      const base::FilePath& profile_path) OVERRIDE {
195    user_manager_handler_->SendUserList();
196  }
197
198  virtual void OnProfileSigninRequiredChanged(
199      const base::FilePath& profile_path) OVERRIDE {
200    user_manager_handler_->SendUserList();
201  }
202
203  ProfileManager* profile_manager_;
204
205  UserManagerScreenHandler* user_manager_handler_;  // Weak; owns us.
206
207  DISALLOW_COPY_AND_ASSIGN(ProfileUpdateObserver);
208};
209
210// UserManagerScreenHandler ---------------------------------------------------
211
212UserManagerScreenHandler::UserManagerScreenHandler()
213    : desktop_type_(chrome::GetActiveDesktop()),
214      weak_ptr_factory_(this) {
215  profileInfoCacheObserver_.reset(
216      new UserManagerScreenHandler::ProfileUpdateObserver(
217          g_browser_process->profile_manager(), this));
218}
219
220UserManagerScreenHandler::~UserManagerScreenHandler() {
221  ScreenlockBridge::Get()->SetLockHandler(NULL);
222}
223
224void UserManagerScreenHandler::ShowBannerMessage(
225    const base::string16& message) {
226  web_ui()->CallJavascriptFunction(
227      "login.AccountPickerScreen.showBannerMessage",
228      base::StringValue(message));
229}
230
231void UserManagerScreenHandler::ShowUserPodCustomIcon(
232    const std::string& user_email,
233    const ScreenlockBridge::UserPodCustomIconOptions& icon_options) {
234  scoped_ptr<base::DictionaryValue> icon = icon_options.ToDictionaryValue();
235  if (!icon || icon->empty())
236    return;
237  web_ui()->CallJavascriptFunction(
238      "login.AccountPickerScreen.showUserPodCustomIcon",
239      base::StringValue(user_email),
240      *icon);
241}
242
243void UserManagerScreenHandler::HideUserPodCustomIcon(
244    const std::string& user_email) {
245  web_ui()->CallJavascriptFunction(
246      "login.AccountPickerScreen.hideUserPodCustomIcon",
247      base::StringValue(user_email));
248}
249
250void UserManagerScreenHandler::EnableInput() {
251  // Nothing here because UI is not disabled when starting to authenticate.
252}
253
254void UserManagerScreenHandler::SetAuthType(
255    const std::string& user_email,
256    ScreenlockBridge::LockHandler::AuthType auth_type,
257    const base::string16& auth_value) {
258  if (GetAuthType(user_email) ==
259          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
260    return;
261
262  user_auth_type_map_[user_email] = auth_type;
263  web_ui()->CallJavascriptFunction(
264      "login.AccountPickerScreen.setAuthType",
265      base::StringValue(user_email),
266      base::FundamentalValue(auth_type),
267      base::StringValue(auth_value));
268}
269
270ScreenlockBridge::LockHandler::AuthType UserManagerScreenHandler::GetAuthType(
271      const std::string& user_email) const {
272  UserAuthTypeMap::const_iterator it = user_auth_type_map_.find(user_email);
273  if (it == user_auth_type_map_.end())
274    return ScreenlockBridge::LockHandler::OFFLINE_PASSWORD;
275  return it->second;
276}
277
278void UserManagerScreenHandler::Unlock(const std::string& user_email) {
279  ProfileInfoCache& info_cache =
280      g_browser_process->profile_manager()->GetProfileInfoCache();
281  const size_t profile_index = GetIndexOfProfileWithEmailAndName(
282      info_cache, base::UTF8ToUTF16(user_email), base::string16());
283  DCHECK_LT(profile_index, info_cache.GetNumberOfProfiles());
284
285  authenticating_profile_index_ = profile_index;
286  ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
287}
288
289void UserManagerScreenHandler::AttemptEasySignin(
290    const std::string& user_email,
291    const std::string& secret,
292    const std::string& key_label) {
293  NOTREACHED();
294}
295
296void UserManagerScreenHandler::HandleInitialize(const base::ListValue* args) {
297  // If the URL has a hash parameter, store it for later.
298  args->GetString(0, &url_hash_);
299
300  SendUserList();
301  web_ui()->CallJavascriptFunction("cr.ui.Oobe.showUserManagerScreen",
302      base::FundamentalValue(IsGuestModeEnabled()),
303      base::FundamentalValue(IsAddPersonEnabled()));
304  desktop_type_ = chrome::GetHostDesktopTypeForNativeView(
305      web_ui()->GetWebContents()->GetNativeView());
306
307  ScreenlockBridge::Get()->SetLockHandler(this);
308}
309
310void UserManagerScreenHandler::HandleAddUser(const base::ListValue* args) {
311  if (!IsAddPersonEnabled()) {
312    // The 'Add User' UI should not be showing.
313    NOTREACHED();
314    return;
315  }
316  profiles::CreateAndSwitchToNewProfile(
317      desktop_type_,
318      base::Bind(&UserManagerScreenHandler::OnSwitchToProfileComplete,
319                 weak_ptr_factory_.GetWeakPtr()),
320      ProfileMetrics::ADD_NEW_USER_MANAGER);
321}
322
323void UserManagerScreenHandler::HandleAuthenticatedLaunchUser(
324    const base::ListValue* args) {
325  base::string16 email_address;
326  if (!args->GetString(0, &email_address))
327    return;
328
329  base::string16 display_name;
330  if (!args->GetString(1, &display_name))
331    return;
332
333  std::string password;
334  if (!args->GetString(2, &password))
335    return;
336
337  ProfileInfoCache& info_cache =
338      g_browser_process->profile_manager()->GetProfileInfoCache();
339  size_t profile_index = GetIndexOfProfileWithEmailAndName(
340      info_cache, email_address, display_name);
341  if (profile_index >= info_cache.GetNumberOfProfiles()) {
342    NOTREACHED();
343    return;
344  }
345
346  authenticating_profile_index_ = profile_index;
347  if (!chrome::ValidateLocalAuthCredentials(profile_index, password)) {
348    // Make a second attempt via an on-line authentication call.  This handles
349    // profiles that are missing sign-in credentials and also cases where the
350    // password has been changed externally.
351    client_login_.reset(new GaiaAuthFetcher(
352        this,
353        GaiaConstants::kChromeSource,
354        web_ui()->GetWebContents()->GetBrowserContext()->GetRequestContext()));
355    std::string email_string;
356    args->GetString(0, &email_string);
357    client_login_->StartClientLogin(
358        email_string,
359        password,
360        GaiaConstants::kSyncService,
361        std::string(),
362        std::string(),
363        GaiaAuthFetcher::HostedAccountsAllowed);
364    password_attempt_ = password;
365    return;
366  }
367
368  ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
369}
370
371void UserManagerScreenHandler::HandleRemoveUser(const base::ListValue* args) {
372  DCHECK(args);
373  const base::Value* profile_path_value;
374  if (!args->Get(0, &profile_path_value))
375    return;
376
377  base::FilePath profile_path;
378  if (!base::GetValueAsFilePath(*profile_path_value, &profile_path))
379    return;
380
381  // This handler could have been called for a supervised user, for example
382  // because the user fiddled with the web inspector. Silently return in this
383  // case.
384  if (Profile::FromWebUI(web_ui())->IsSupervised())
385    return;
386
387  if (!profiles::IsMultipleProfilesEnabled())
388    return;
389
390  g_browser_process->profile_manager()->ScheduleProfileForDeletion(
391      profile_path,
392      base::Bind(&OpenNewWindowForProfile, desktop_type_));
393  ProfileMetrics::LogProfileDeleteUser(
394      ProfileMetrics::DELETE_PROFILE_USER_MANAGER);
395}
396
397void UserManagerScreenHandler::HandleLaunchGuest(const base::ListValue* args) {
398  if (IsGuestModeEnabled()) {
399    ProfileMetrics::LogProfileSwitchUser(ProfileMetrics::SWITCH_PROFILE_GUEST);
400    profiles::SwitchToGuestProfile(
401        desktop_type_,
402        base::Bind(&UserManagerScreenHandler::OnSwitchToProfileComplete,
403                   weak_ptr_factory_.GetWeakPtr()));
404  } else {
405    // The UI should have prevented the user from allowing the selection of
406    // guest mode.
407    NOTREACHED();
408  }
409}
410
411void UserManagerScreenHandler::HandleLaunchUser(const base::ListValue* args) {
412  base::string16 email_address;
413  base::string16 display_name;
414
415  if (!args->GetString(0, &email_address) ||
416      !args->GetString(1, &display_name)) {
417    NOTREACHED();
418    return;
419  }
420
421  ProfileInfoCache& info_cache =
422      g_browser_process->profile_manager()->GetProfileInfoCache();
423  size_t profile_index = GetIndexOfProfileWithEmailAndName(
424      info_cache, email_address, display_name);
425
426  if (profile_index >= info_cache.GetNumberOfProfiles()) {
427    NOTREACHED();
428    return;
429  }
430
431  // It's possible that a user breaks into the user-manager page using the
432  // JavaScript Inspector and causes a "locked" profile to call this
433  // unauthenticated version of "launch" instead of the proper one.  Thus,
434  // we have to validate in (secure) C++ code that it really is a profile
435  // not needing authentication.  If it is, just ignore the "launch" request.
436  if (info_cache.ProfileIsSigninRequiredAtIndex(profile_index))
437    return;
438  ProfileMetrics::LogProfileAuthResult(ProfileMetrics::AUTH_UNNECESSARY);
439
440  base::FilePath path = info_cache.GetPathOfProfileAtIndex(profile_index);
441  profiles::SwitchToProfile(
442      path,
443      desktop_type_,
444      false,  /* reuse any existing windows */
445      base::Bind(&UserManagerScreenHandler::OnSwitchToProfileComplete,
446                 weak_ptr_factory_.GetWeakPtr()),
447      ProfileMetrics::SWITCH_PROFILE_MANAGER);
448}
449
450void UserManagerScreenHandler::HandleAttemptUnlock(
451    const base::ListValue* args) {
452  std::string email;
453  CHECK(args->GetString(0, &email));
454  GetScreenlockRouter(email)->OnAuthAttempted(GetAuthType(email), "");
455}
456
457void UserManagerScreenHandler::HandleHardlockUserPod(
458    const base::ListValue* args) {
459  std::string email;
460  CHECK(args->GetString(0, &email));
461  SetAuthType(email,
462              ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD,
463              base::string16());
464  HideUserPodCustomIcon(email);
465}
466
467void UserManagerScreenHandler::OnClientLoginSuccess(
468    const ClientLoginResult& result) {
469  chrome::SetLocalAuthCredentials(authenticating_profile_index_,
470                                  password_attempt_);
471  ReportAuthenticationResult(true, ProfileMetrics::AUTH_ONLINE);
472}
473
474void UserManagerScreenHandler::OnClientLoginFailure(
475    const GoogleServiceAuthError& error) {
476  const GoogleServiceAuthError::State state = error.state();
477  // Some "error" results mean the password was correct but some other action
478  // should be taken.  For our purposes, we only care that the password was
479  // correct so count those as a success.
480  bool success = (state == GoogleServiceAuthError::NONE ||
481                  state == GoogleServiceAuthError::CAPTCHA_REQUIRED ||
482                  state == GoogleServiceAuthError::TWO_FACTOR ||
483                  state == GoogleServiceAuthError::ACCOUNT_DELETED ||
484                  state == GoogleServiceAuthError::ACCOUNT_DISABLED);
485  bool offline = (state == GoogleServiceAuthError::CONNECTION_FAILED ||
486                  state == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
487                  state == GoogleServiceAuthError::REQUEST_CANCELED);
488  ProfileMetrics::ProfileAuth failure_metric =
489      offline ? ProfileMetrics::AUTH_FAILED_OFFLINE :
490                ProfileMetrics::AUTH_FAILED;
491  ReportAuthenticationResult(
492      success, success ? ProfileMetrics::AUTH_ONLINE : failure_metric);
493}
494
495void UserManagerScreenHandler::RegisterMessages() {
496  web_ui()->RegisterMessageCallback(kJsApiUserManagerInitialize,
497      base::Bind(&UserManagerScreenHandler::HandleInitialize,
498                 base::Unretained(this)));
499  web_ui()->RegisterMessageCallback(kJsApiUserManagerAddUser,
500      base::Bind(&UserManagerScreenHandler::HandleAddUser,
501                 base::Unretained(this)));
502  web_ui()->RegisterMessageCallback(kJsApiUserManagerAuthLaunchUser,
503      base::Bind(&UserManagerScreenHandler::HandleAuthenticatedLaunchUser,
504                 base::Unretained(this)));
505  web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchGuest,
506      base::Bind(&UserManagerScreenHandler::HandleLaunchGuest,
507                 base::Unretained(this)));
508  web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchUser,
509      base::Bind(&UserManagerScreenHandler::HandleLaunchUser,
510                 base::Unretained(this)));
511  web_ui()->RegisterMessageCallback(kJsApiUserManagerRemoveUser,
512      base::Bind(&UserManagerScreenHandler::HandleRemoveUser,
513                 base::Unretained(this)));
514  web_ui()->RegisterMessageCallback(kJsApiUserManagerAttemptUnlock,
515      base::Bind(&UserManagerScreenHandler::HandleAttemptUnlock,
516                 base::Unretained(this)));
517
518  const content::WebUI::MessageCallback& kDoNothingCallback =
519      base::Bind(&HandleAndDoNothing);
520
521  // Unused callbacks from screen_account_picker.js
522  web_ui()->RegisterMessageCallback("accountPickerReady", kDoNothingCallback);
523  web_ui()->RegisterMessageCallback("loginUIStateChanged", kDoNothingCallback);
524  web_ui()->RegisterMessageCallback("hideCaptivePortal", kDoNothingCallback);
525  web_ui()->RegisterMessageCallback("getTouchViewState", kDoNothingCallback);
526  // Unused callbacks from display_manager.js
527  web_ui()->RegisterMessageCallback("showAddUser", kDoNothingCallback);
528  web_ui()->RegisterMessageCallback("loadWallpaper", kDoNothingCallback);
529  web_ui()->RegisterMessageCallback("updateCurrentScreen", kDoNothingCallback);
530  web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback);
531  // Unused callbacks from user_pod_row.js
532  web_ui()->RegisterMessageCallback("focusPod", kDoNothingCallback);
533}
534
535void UserManagerScreenHandler::GetLocalizedValues(
536    base::DictionaryValue* localized_strings) {
537  // For Control Bar.
538  localized_strings->SetString("signedIn",
539      l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_ACTIVE_USER));
540  localized_strings->SetString("signinButton",
541      l10n_util::GetStringUTF16(IDS_LOGIN_BUTTON));
542  localized_strings->SetString("addUser",
543      l10n_util::GetStringUTF16(IDS_ADD_USER_BUTTON));
544  localized_strings->SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
545  localized_strings->SetString("browseAsGuest",
546      l10n_util::GetStringUTF16(IDS_GO_INCOGNITO_BUTTON));
547  localized_strings->SetString("signOutUser",
548      l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT));
549
550  // For AccountPickerScreen.
551  localized_strings->SetString("screenType", "login-add-user");
552  localized_strings->SetString("highlightStrength", "normal");
553  localized_strings->SetString("title",
554      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
555  localized_strings->SetString("passwordHint",
556      l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
557  localized_strings->SetString("signingIn",
558      l10n_util::GetStringUTF16(IDS_LOGIN_POD_SIGNING_IN));
559  localized_strings->SetString("podMenuButtonAccessibleName",
560      l10n_util::GetStringUTF16(IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME));
561  localized_strings->SetString("podMenuRemoveItemAccessibleName",
562      l10n_util::GetStringUTF16(
563          IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME));
564  localized_strings->SetString("removeUser",
565      l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON));
566  localized_strings->SetString("passwordFieldAccessibleName",
567      l10n_util::GetStringUTF16(IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME));
568  localized_strings->SetString("bootIntoWallpaper", "off");
569
570  // For AccountPickerScreen, the remove user warning overlay.
571  localized_strings->SetString("removeUserWarningButtonTitle",
572      l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON));
573  localized_strings->SetString("removeUserWarningText",
574      l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING));
575  localized_strings->SetString("removeSupervisedUserWarningText",
576      l10n_util::GetStringFUTF16(
577          IDS_LOGIN_POD_SUPERVISED_USER_REMOVE_WARNING,
578          base::UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL)));
579
580  // Strings needed for the User Manager tutorial slides.
581  localized_strings->SetString("tutorialNext",
582      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_NEXT));
583  localized_strings->SetString("tutorialDone",
584      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_DONE));
585  localized_strings->SetString("slideWelcomeTitle",
586      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_INTRO_TITLE));
587  localized_strings->SetString("slideWelcomeText",
588      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_INTRO_TEXT));
589  localized_strings->SetString("slideYourChromeTitle",
590      l10n_util::GetStringUTF16(
591          IDS_USER_MANAGER_TUTORIAL_SLIDE_YOUR_CHROME_TITLE));
592  localized_strings->SetString("slideYourChromeText", l10n_util::GetStringUTF16(
593      IDS_USER_MANAGER_TUTORIAL_SLIDE_YOUR_CHROME_TEXT));
594  localized_strings->SetString("slideGuestsTitle",
595      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_GUEST_TITLE));
596  localized_strings->SetString("slideGuestsText",
597      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_GUEST_TEXT));
598  localized_strings->SetString("slideFriendsTitle",
599      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_FRIENDS_TITLE));
600  localized_strings->SetString("slideFriendsText",
601      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_FRIENDS_TEXT));
602  localized_strings->SetString("slideCompleteTitle",
603      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_TITLE));
604  localized_strings->SetString("slideCompleteText",
605      l10n_util::GetStringUTF16(IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_TEXT));
606  localized_strings->SetString("slideCompleteUserNotFound",
607      l10n_util::GetStringUTF16(
608          IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_USER_NOT_FOUND));
609  localized_strings->SetString("slideCompleteAddUser",
610      l10n_util::GetStringUTF16(
611          IDS_USER_MANAGER_TUTORIAL_SLIDE_OUTRO_ADD_USER));
612
613  // Strings needed for the user_pod_template public account div, but not ever
614  // actually displayed for desktop users.
615  localized_strings->SetString("publicAccountReminder", base::string16());
616  localized_strings->SetString("publicSessionLanguageAndInput",
617                               base::string16());
618  localized_strings->SetString("publicAccountEnter", base::string16());
619  localized_strings->SetString("publicAccountEnterAccessibleName",
620                               base::string16());
621  localized_strings->SetString("publicSessionSelectLanguage", base::string16());
622  localized_strings->SetString("publicSessionSelectKeyboard", base::string16());
623  localized_strings->SetString("signinBannerText", base::string16());
624  localized_strings->SetString("launchAppButton", base::string16());
625  localized_strings->SetString("multiProfilesRestrictedPolicyTitle",
626                               base::string16());
627  localized_strings->SetString("multiProfilesNotAllowedPolicyMsg",
628                                base::string16());
629  localized_strings->SetString("multiProfilesPrimaryOnlyPolicyMsg",
630                                base::string16());
631  localized_strings->SetString("multiProfilesOwnerPrimaryOnlyMsg",
632                                base::string16());
633}
634
635void UserManagerScreenHandler::SendUserList() {
636  base::ListValue users_list;
637  base::FilePath active_profile_path =
638      web_ui()->GetWebContents()->GetBrowserContext()->GetPath();
639  const ProfileInfoCache& info_cache =
640      g_browser_process->profile_manager()->GetProfileInfoCache();
641
642  user_auth_type_map_.clear();
643
644  // If the active user is a supervised user, then they may not perform
645  // certain actions (i.e. delete another user).
646  bool active_user_is_supervised = Profile::FromWebUI(web_ui())->IsSupervised();
647  for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
648    base::DictionaryValue* profile_value = new base::DictionaryValue();
649
650    base::FilePath profile_path = info_cache.GetPathOfProfileAtIndex(i);
651    bool is_active_user = (profile_path == active_profile_path);
652
653    profile_value->SetString(
654        kKeyUsername, info_cache.GetUserNameOfProfileAtIndex(i));
655    profile_value->SetString(
656        kKeyEmailAddress, info_cache.GetUserNameOfProfileAtIndex(i));
657    // The profiles displayed in the User Manager are never guest profiles.
658    profile_value->SetString(
659        kKeyDisplayName,
660        profiles::GetAvatarNameForProfile(profile_path));
661    profile_value->SetString(kKeyProfilePath, profile_path.MaybeAsASCII());
662    profile_value->SetBoolean(kKeyPublicAccount, false);
663    profile_value->SetBoolean(
664        kKeySupervisedUser, info_cache.ProfileIsSupervisedAtIndex(i));
665    profile_value->SetBoolean(kKeySignedIn, is_active_user);
666    profile_value->SetBoolean(
667        kKeyNeedsSignin, info_cache.ProfileIsSigninRequiredAtIndex(i));
668    profile_value->SetBoolean(kKeyIsOwner, false);
669    profile_value->SetBoolean(kKeyCanRemove, !active_user_is_supervised);
670    profile_value->SetBoolean(kKeyIsDesktop, true);
671    profile_value->SetString(
672        kKeyAvatarUrl, GetAvatarImageAtIndex(i, info_cache));
673
674    // The row of user pods should display the active user first.
675    if (is_active_user)
676      users_list.Insert(0, profile_value);
677    else
678      users_list.Append(profile_value);
679  }
680
681  web_ui()->CallJavascriptFunction("login.AccountPickerScreen.loadUsers",
682      users_list, base::FundamentalValue(IsGuestModeEnabled()));
683}
684
685void UserManagerScreenHandler::ReportAuthenticationResult(
686    bool success,
687    ProfileMetrics::ProfileAuth auth) {
688  ProfileMetrics::LogProfileAuthResult(auth);
689  password_attempt_.clear();
690
691  if (success) {
692    ProfileInfoCache& info_cache =
693        g_browser_process->profile_manager()->GetProfileInfoCache();
694    info_cache.SetProfileSigninRequiredAtIndex(
695        authenticating_profile_index_, false);
696    base::FilePath path = info_cache.GetPathOfProfileAtIndex(
697        authenticating_profile_index_);
698    profiles::SwitchToProfile(
699        path,
700        desktop_type_,
701        true,
702        base::Bind(&UserManagerScreenHandler::OnSwitchToProfileComplete,
703                   weak_ptr_factory_.GetWeakPtr()),
704        ProfileMetrics::SWITCH_PROFILE_UNLOCK);
705  } else {
706    web_ui()->CallJavascriptFunction(
707        "cr.ui.Oobe.showSignInError",
708        base::FundamentalValue(0),
709        base::StringValue(l10n_util::GetStringUTF8(
710            auth == ProfileMetrics::AUTH_FAILED_OFFLINE ?
711                IDS_LOGIN_ERROR_AUTHENTICATING_OFFLINE :
712                IDS_LOGIN_ERROR_AUTHENTICATING)),
713        base::StringValue(""),
714        base::FundamentalValue(0));
715  }
716}
717
718void UserManagerScreenHandler::OnBrowserWindowReady(Browser* browser) {
719  DCHECK(browser);
720  DCHECK(browser->window());
721  if (url_hash_ == profiles::kUserManagerSelectProfileTaskManager) {
722     base::MessageLoop::current()->PostTask(
723         FROM_HERE, base::Bind(&chrome::ShowTaskManager, browser));
724  } else if (url_hash_ == profiles::kUserManagerSelectProfileAboutChrome) {
725     base::MessageLoop::current()->PostTask(
726         FROM_HERE, base::Bind(&chrome::ShowAboutChrome, browser));
727  }
728
729  // This call is last as it deletes this object.
730  UserManager::Hide();
731}
732
733void UserManagerScreenHandler::Observe(
734    int type,
735    const content::NotificationSource& source,
736    const content::NotificationDetails& details) {
737  switch (type) {
738    case chrome::NOTIFICATION_BROWSER_WINDOW_READY:
739      // Only respond to one Browser Window Ready event.
740      registrar_.Remove(this,
741                        chrome::NOTIFICATION_BROWSER_WINDOW_READY,
742                        content::NotificationService::AllSources());
743      OnBrowserWindowReady(content::Source<Browser>(source).ptr());
744    break;
745    default:
746      NOTREACHED();
747  }
748}
749
750// This callback is run after switching to a new profile has finished. This
751// means either a new browser has been created (but not the window), or an
752// existing one has been found. The HideUserManager task needs to be posted
753// since closing the User Manager before the window is created can flakily
754// cause Chrome to close.
755void UserManagerScreenHandler::OnSwitchToProfileComplete(
756    Profile* profile, Profile::CreateStatus profile_create_status) {
757  Browser* browser = chrome::FindAnyBrowser(profile, false, desktop_type_);
758  if (browser && browser->window()) {
759    OnBrowserWindowReady(browser);
760  } else {
761    registrar_.Add(this,
762                   chrome::NOTIFICATION_BROWSER_WINDOW_READY,
763                   content::NotificationService::AllSources());
764  }
765}
766