Home | History | Annotate | Download | only in signin
      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