Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / profile_chooser_view.cc
index b7c827d..efdd4b8 100644 (file)
@@ -4,20 +4,22 @@
 
 #include "chrome/browser/ui/views/profile_chooser_view.h"
 
-#include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_info_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/signin/mutable_profile_oauth2_token_service.h"
 #include "chrome/browser/signin/profile_oauth2_token_service.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/views/user_manager_view.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/text_elider.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/controls/button/blue_button.h"
+#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/menu_button.h"
-#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/separator.h"
+#include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/webview/webview.h"
-#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(USE_AURA)
-#include "ui/native_theme/native_theme_aura.h"
-#endif
-
 namespace {
 
 // Helpers --------------------------------------------------------------------
 
-const int kLargeImageSide = 64;
-const int kSmallImageSide = 32;
-const int kMinMenuWidth = 250;
+const int kFixedMenuWidth = 250;
 const int kButtonHeight = 29;
-const int kArrowHeight = 10;
-
-// Current profile avatar image.
-views::View* CreateProfileImageView(const gfx::Image& icon) {
-  views::ImageView* view = new views::ImageView();
-
-  gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
-      icon, true,
-      kLargeImageSide + profiles::kAvatarIconPadding,
-      kLargeImageSide + profiles::kAvatarIconPadding);
-  view->SetImage(image.ToImageSkia());
-
-  return view;
-}
 
 // Creates a GridLayout with a single column. This ensures that all the child
 // views added get auto-expanded to fill the full width of the bubble.
-views::GridLayout* CreateSingleColumnLayout(views::View* view) {
+views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
   views::GridLayout* layout = new views::GridLayout(view);
   view->SetLayoutManager(layout);
 
   views::ColumnSet* columns = layout->AddColumnSet(0);
-  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
-                     views::GridLayout::USE_PREF, 0, 0);
+  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
+                     views::GridLayout::FIXED, width, width);
   return layout;
 }
 
@@ -87,12 +72,12 @@ views::GridLayout* CreateDoubleColumnLayout(views::View* view) {
   columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                      views::GridLayout::USE_PREF, 0, 0);
   columns->AddPaddingColumn(0, views::kUnrelatedControlLargeHorizontalSpacing);
-  columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::TRAILING, 1,
+  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                      views::GridLayout::USE_PREF, 0, 0);
   return layout;
 }
 
-views::Link* CreateLink(const string16& link_text,
+views::Link* CreateLink(const base::string16& link_text,
                         views::LinkListener* listener) {
   views::Link* link_button = new views::Link(link_text);
   link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -102,89 +87,205 @@ views::Link* CreateLink(const string16& link_text,
 }
 
 
-// HorizontalPaddingButtonBorder ----------------------------------------------
+// BackgroundColorHoverButton -------------------------------------------------
 
-// A button border that adds padding before the icon and after the text. This
-// is needed so that the button looks like it is spanning the entire parent
-// view (especially when hovered over), but has the icon indented and aligned
-// with the other items in the parent view.
-class HorizontalPaddingButtonBorder : public views::TextButtonBorder {
+// A custom button that allows for setting a background color when hovered over.
+class BackgroundColorHoverButton : public views::LabelButton {
  public:
-  HorizontalPaddingButtonBorder() : views::TextButtonBorder() {
-    SetInsets(gfx::Insets(0, views::kButtonHEdgeMarginNew,
-                          0, views::kButtonHEdgeMarginNew));
-  };
-
-  virtual ~HorizontalPaddingButtonBorder() {
-  };
+  BackgroundColorHoverButton(views::ButtonListener* listener,
+                             const base::string16& text,
+                             const gfx::ImageSkia& normal_icon,
+                             const gfx::ImageSkia& hover_icon);
+  virtual ~BackgroundColorHoverButton();
 
  private:
-  // This function is pure virtual in the parent, so we must provide an
-  // implementation.
-  virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE {
-  };
+  // views::LabelButton:
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
 
-  DISALLOW_COPY_AND_ASSIGN(HorizontalPaddingButtonBorder);
+  DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
 };
 
+BackgroundColorHoverButton::BackgroundColorHoverButton(
+    views::ButtonListener* listener,
+    const base::string16& text,
+    const gfx::ImageSkia& normal_icon,
+    const gfx::ImageSkia& hover_icon)
+    : views::LabelButton(listener, text) {
+  SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew,
+                                             0, views::kButtonHEdgeMarginNew));
+  set_min_size(gfx::Size(0, kButtonHeight));
+  SetImage(STATE_NORMAL, normal_icon);
+  SetImage(STATE_HOVERED, hover_icon);
+  SetImage(STATE_PRESSED, hover_icon);
+  SetTextColor(STATE_HOVERED, GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor));
+}
 
-// BackgroundColorHoverButton -------------------------------------------------
+BackgroundColorHoverButton::~BackgroundColorHoverButton() {}
 
-// A custom button that allows for setting a background color when hovered over.
-class BackgroundColorHoverButton : public views::TextButton {
+void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) {
+  if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) {
+    canvas->DrawColor(GetNativeTheme()->GetSystemColor(
+        ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor));
+  }
+  LabelButton::OnPaint(canvas);
+}
+
+}  // namespace
+
+
+// EditableProfilePhoto -------------------------------------------------
+
+// A custom Image control that shows a "change" button when moused over.
+class EditableProfilePhoto : public views::ImageView {
  public:
-  BackgroundColorHoverButton(views::ButtonListener* listener,
-                             const string16& text,
-                             const gfx::ImageSkia& normal_icon,
-                             const gfx::ImageSkia& hover_icon)
-      : views::TextButton(listener, text) {
-    set_border(new HorizontalPaddingButtonBorder);
-    set_min_height(kButtonHeight);
-    set_icon_text_spacing(views::kItemLabelSpacing);
-    SetIcon(normal_icon);
-    SetHoverIcon(hover_icon);
-    SetPushedIcon(hover_icon);
-    SetHoverColor(GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_SelectedMenuItemForegroundColor));
-    OnHighlightStateChanged();
-  };
-
-  virtual ~BackgroundColorHoverButton(){
-  };
+  EditableProfilePhoto(views::ButtonListener* listener,
+                       const gfx::Image& icon,
+                       bool is_editing_allowed)
+      : views::ImageView(),
+        change_photo_button_(NULL) {
+    const int kLargeImageSide = 64;
+    gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
+        icon, true,
+        kLargeImageSide + profiles::kAvatarIconPadding,
+        kLargeImageSide + profiles::kAvatarIconPadding);
+    SetImage(image.ToImageSkia());
+
+    if (!is_editing_allowed)
+      return;
+
+    set_notify_enter_exit_on_child(true);
+
+    // Button overlay that appears when hovering over the image.
+    change_photo_button_ = new views::LabelButton(listener,
+        l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON));
+    change_photo_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
+    change_photo_button_->SetBorder(views::Border::NullBorder());
+    const SkColor color = SK_ColorWHITE;
+    change_photo_button_->SetTextColor(views::Button::STATE_NORMAL, color);
+    change_photo_button_->SetTextColor(views::Button::STATE_HOVERED, color);
+
+    const SkColor kBackgroundColor = SkColorSetARGB(125, 0, 0, 0);
+    change_photo_button_->set_background(
+        views::Background::CreateSolidBackground(kBackgroundColor));
+    // Need to take into account the border padding on the avatar.
+    const int kOverlayHeight = 20;
+    change_photo_button_->SetBounds(
+        profiles::kAvatarIconPadding,
+        kLargeImageSide - kOverlayHeight,
+        kLargeImageSide - profiles::kAvatarIconPadding,
+        kOverlayHeight);
+    change_photo_button_->SetVisible(false);
+    AddChildView(change_photo_button_);
+  }
+
+  views::LabelButton* change_photo_button() { return change_photo_button_; }
 
  private:
+  // views::View:
   virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
-    views::TextButton::OnMouseEntered(event);
-    OnHighlightStateChanged();
-  };
+    if (change_photo_button_)
+      change_photo_button_->SetVisible(true);
+  }
 
   virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
-    views::TextButton::OnMouseExited(event);
-    OnHighlightStateChanged();
-  };
-
-  void OnHighlightStateChanged() {
-    bool is_highlighted = (state() == views::TextButton::STATE_PRESSED) ||
-        (state() == views::TextButton::STATE_HOVERED) || HasFocus();
-    ui::NativeTheme::ColorId color_id = is_highlighted ?
-        ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor :
-        ui::NativeTheme::kColorId_MenuBackgroundColor;
-    set_background(views::Background::CreateSolidBackground(
-        GetNativeTheme()->GetSystemColor(color_id)));
-    SchedulePaint();
-  };
+    if (change_photo_button_)
+      change_photo_button_->SetVisible(false);
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
+  // Button that is shown when hovering over the image view. Can be NULL if
+  // the photo isn't allowed to be edited (e.g. for guest profiles).
+  views::LabelButton* change_photo_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
 };
 
-}  // namespace
+
+// EditableProfileName -------------------------------------------------
+
+// A custom text control that turns into a textfield for editing when clicked.
+class EditableProfileName : public views::LabelButton,
+                            public views::ButtonListener {
+ public:
+  EditableProfileName(views::TextfieldController* controller,
+                      const base::string16& text,
+                      bool is_editing_allowed)
+      : views::LabelButton(this, text),
+        profile_name_textfield_(NULL) {
+    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+    const gfx::FontList& medium_font_list =
+        rb->GetFontList(ui::ResourceBundle::MediumFont);
+    SetFontList(medium_font_list);
+    SetBorder(views::Border::NullBorder());
+
+    if (!is_editing_allowed)
+      return;
+
+    SetImage(STATE_HOVERED,
+             *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER));
+    SetImage(STATE_PRESSED,
+             *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
+
+    // Textfield that overlaps the button.
+    profile_name_textfield_ = new views::Textfield();
+    profile_name_textfield_->set_controller(controller);
+    profile_name_textfield_->SetFontList(medium_font_list);
+    profile_name_textfield_->SetVisible(false);
+    AddChildView(profile_name_textfield_);
+  }
+
+  views::Textfield* profile_name_textfield() {
+    return profile_name_textfield_;
+  }
+
+  // Hide the editable textfield to show the profile name button instead.
+  void ShowReadOnlyView() {
+    if (profile_name_textfield_)
+      profile_name_textfield_->SetVisible(false);
+  }
+
+ private:
+  // views::ButtonListener:
+  virtual void ButtonPressed(views::Button* sender,
+                            const ui::Event& event) OVERRIDE {
+    if (profile_name_textfield_) {
+      profile_name_textfield_->SetVisible(true);
+      profile_name_textfield_->SetText(GetText());
+      profile_name_textfield_->SelectAll(false);
+      profile_name_textfield_->RequestFocus();
+    }
+  }
+
+  // views::LabelButton:
+  virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
+    // Override CustomButton's implementation, which presses the button when
+    // you press space and clicks it when you release space, as the space can be
+    // part of the new profile name typed in the textfield.
+    return false;
+  }
+
+  virtual void Layout() OVERRIDE {
+    if (profile_name_textfield_)
+      profile_name_textfield_->SetBounds(0, 0, width(), height());
+    // This layout trick keeps the text left-aligned and the icon right-aligned.
+    SetHorizontalAlignment(gfx::ALIGN_RIGHT);
+    views::LabelButton::Layout();
+    label()->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  }
+
+  // Button that is shown when hovering over the image view. Can be NULL if
+  // the profile name isn't allowed to be edited (e.g. for guest profiles).
+  views::Textfield* profile_name_textfield_;
+
+  DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
+};
 
 
 // ProfileChooserView ---------------------------------------------------------
 
 // static
 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
-bool ProfileChooserView::close_on_deactivate_ = true;
+bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
 
 // static
 void ProfileChooserView::ShowBubble(
@@ -200,7 +301,7 @@ void ProfileChooserView::ShowBubble(
   profile_bubble_ = new ProfileChooserView(
       anchor_view, arrow, anchor_rect, browser);
   views::BubbleDelegateView::CreateBubble(profile_bubble_);
-  profile_bubble_->set_close_on_deactivate(close_on_deactivate_);
+  profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
   profile_bubble_->SetAlignment(border_alignment);
   profile_bubble_->GetWidget()->Show();
   profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
@@ -222,35 +323,45 @@ ProfileChooserView::ProfileChooserView(views::View* anchor_view,
                                        const gfx::Rect& anchor_rect,
                                        Browser* browser)
     : BubbleDelegateView(anchor_view, arrow),
-      browser_(browser) {
+      browser_(browser),
+      view_mode_(PROFILE_CHOOSER_VIEW) {
   // Reset the default margins inherited from the BubbleDelegateView.
   set_margins(gfx::Insets());
-  // Compensate for built-in vertical padding in the anchor view's image.
-  set_anchor_view_insets(gfx::Insets(kArrowHeight, 0, kArrowHeight, 0));
 
-  ResetLinksAndButtons();
+  ResetView();
 
   avatar_menu_.reset(new AvatarMenu(
       &g_browser_process->profile_manager()->GetProfileInfoCache(),
       this,
       browser_));
   avatar_menu_->RebuildMenu();
+
+  ProfileOAuth2TokenService* oauth2_token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
+  if (oauth2_token_service)
+    oauth2_token_service->AddObserver(this);
 }
 
 ProfileChooserView::~ProfileChooserView() {
+  ProfileOAuth2TokenService* oauth2_token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
+  if (oauth2_token_service)
+    oauth2_token_service->RemoveObserver(this);
 }
 
-void ProfileChooserView::ResetLinksAndButtons() {
+void ProfileChooserView::ResetView() {
   manage_accounts_link_ = NULL;
   signout_current_profile_link_ = NULL;
   signin_current_profile_link_ = NULL;
-  change_photo_link_ = NULL;
   guest_button_ = NULL;
   end_guest_button_ = NULL;
   users_button_ = NULL;
   add_user_button_ = NULL;
   add_account_button_ = NULL;
+  current_profile_photo_ = NULL;
+  current_profile_name_ = NULL;
   open_other_profile_indexes_map_.clear();
+  current_profile_accounts_map_.clear();
 }
 
 void ProfileChooserView::Init() {
@@ -265,6 +376,24 @@ void ProfileChooserView::OnAvatarMenuChanged(
   ShowView(PROFILE_CHOOSER_VIEW, avatar_menu);
 }
 
+void ProfileChooserView::OnRefreshTokenAvailable(
+    const std::string& account_id) {
+  // Refresh the account management view when a new account is added to the
+  // profile.
+  if (view_mode_ == ACCOUNT_MANAGEMENT_VIEW ||
+      view_mode_ == GAIA_SIGNIN_VIEW ||
+      view_mode_ == GAIA_ADD_ACCOUNT_VIEW) {
+    ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
+  }
+}
+
+void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
+  // Refresh the account management view when an account is removed from the
+  // profile.
+  if (view_mode_ == ACCOUNT_MANAGEMENT_VIEW)
+    ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
+}
+
 void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
                                   AvatarMenu* avatar_menu) {
   // The account management view should only be displayed if the active profile
@@ -275,23 +404,25 @@ void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
     DCHECK(active_item.signed_in);
   }
 
-  ResetLinksAndButtons();
+  ResetView();
   RemoveAllChildViews(true);
-
-  views::GridLayout* layout = CreateSingleColumnLayout(this);
-  layout->set_minimum_size(gfx::Size(kMinMenuWidth, 0));
+  view_mode_ = view_to_display;
 
   if (view_to_display == GAIA_SIGNIN_VIEW ||
       view_to_display == GAIA_ADD_ACCOUNT_VIEW) {
     // Minimum size for embedded sign in pages as defined in Gaia.
     const int kMinGaiaViewWidth = 320;
-    const int kMinGaiaViewHeight = 500;
+    const int kMinGaiaViewHeight = 440;
     Profile* profile = browser_->profile();
     views::WebView* web_view = new views::WebView(profile);
     signin::Source source = (view_to_display == GAIA_SIGNIN_VIEW) ?
         signin::SOURCE_AVATAR_BUBBLE_SIGN_IN :
         signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT;
-    web_view->LoadInitialURL(GURL(signin::GetPromoURL(source, false)));
+    GURL url(signin::GetPromoURL(
+        source, false /* auto_close */, true /* is_constrained */));
+    web_view->LoadInitialURL(url);
+    views::GridLayout* layout =
+        CreateSingleColumnLayout(this, kMinGaiaViewWidth);
     layout->StartRow(1, 0);
     layout->AddView(web_view);
     layout->set_minimum_size(
@@ -302,6 +433,7 @@ void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
     return;
   }
 
+  views::GridLayout* layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
   // Separate items into active and alternatives.
   Indexes other_profiles;
   bool is_guest_view = true;
@@ -381,9 +513,12 @@ void ProfileChooserView::ButtonPressed(views::Button* sender,
   } else if (sender == add_user_button_) {
     profiles::CreateAndSwitchToNewProfile(
         browser_->host_desktop_type(),
-        profiles::ProfileSwitchingDoneCallback());
+        profiles::ProfileSwitchingDoneCallback(),
+        ProfileMetrics::ADD_NEW_USER_ICON);
   } else if (sender == add_account_button_) {
     ShowView(GAIA_ADD_ACCOUNT_VIEW, avatar_menu_.get());
+  } else if (sender == current_profile_photo_->change_photo_button()) {
+    avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
   } else {
     // One of the "other profiles" buttons was pressed.
     ButtonIndexes::const_iterator match =
@@ -391,29 +526,63 @@ void ProfileChooserView::ButtonPressed(views::Button* sender,
     DCHECK(match != open_other_profile_indexes_map_.end());
     avatar_menu_->SwitchToProfile(
         match->second,
-        ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW);
+        ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
+        ProfileMetrics::SWITCH_PROFILE_ICON);
   }
 }
 
+void ProfileChooserView::OnMenuButtonClicked(views::View* source,
+                                             const gfx::Point& point) {
+  AccountButtonIndexes::const_iterator match =
+      current_profile_accounts_map_.find(source);
+  DCHECK(match != current_profile_accounts_map_.end());
+
+  MutableProfileOAuth2TokenService* oauth2_token_service =
+      ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
+          browser_->profile());
+  if (oauth2_token_service)
+    oauth2_token_service->RevokeCredentials(match->second);
+}
+
 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
   if (sender == manage_accounts_link_) {
     // ShowView() will DCHECK if this view is displayed for non signed-in users.
     ShowView(ACCOUNT_MANAGEMENT_VIEW, avatar_menu_.get());
   } else if (sender == signout_current_profile_link_) {
-    avatar_menu_->BeginSignOut();
-  } else if (sender == signin_current_profile_link_) {
-    if (CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kEnableInlineSignin)) {
-      ShowView(GAIA_SIGNIN_VIEW, avatar_menu_.get());
-    } else {
-      GURL page = signin::GetPromoURL(signin::SOURCE_MENU, false);
-      chrome::ShowSingletonTab(browser_, page);
-    }
+    profiles::LockProfile(browser_->profile());
   } else {
-    DCHECK(sender == change_photo_link_);
-    avatar_menu_->EditProfile(
+    DCHECK(sender == signin_current_profile_link_);
+    ShowView(GAIA_SIGNIN_VIEW, avatar_menu_.get());
+  }
+}
+
+bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
+                                        const ui::KeyEvent& key_event) {
+  views::Textfield* name_textfield =
+      current_profile_name_->profile_name_textfield();
+  DCHECK(sender == name_textfield);
+
+  if (key_event.key_code() == ui::VKEY_RETURN ||
+      key_event.key_code() == ui::VKEY_TAB) {
+    // Pressing Tab/Enter commits the new profile name, unless it's empty.
+    base::string16 new_profile_name = name_textfield->text();
+    if (new_profile_name.empty())
+      return true;
+
+    const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
         avatar_menu_->GetActiveProfileIndex());
+    Profile* profile = g_browser_process->profile_manager()->GetProfile(
+        active_item.profile_path);
+    DCHECK(profile);
+
+    if (profile->IsManaged())
+      return true;
+
+    profiles::UpdateProfileName(profile, new_profile_name);
+    current_profile_name_->ShowReadOnlyView();
+    return true;
   }
+  return false;
 }
 
 views::View* ProfileChooserView::CreateCurrentProfileView(
@@ -426,19 +595,15 @@ views::View* ProfileChooserView::CreateCurrentProfileView(
                     views::kButtonVEdgeMarginNew,
                     views::kButtonHEdgeMarginNew);
 
-  views::View* photo_image = CreateProfileImageView(avatar_item.icon);
-  view->SetBoundsRect(photo_image->bounds());
-
-  views::Label* name_label =
-      new views::Label(avatar_item.name,
-                       ui::ResourceBundle::GetSharedInstance().GetFont(
-                           ui::ResourceBundle::MediumFont));
-  name_label->SetElideBehavior(views::Label::ELIDE_AT_END);
-  name_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  current_profile_photo_ =
+      new EditableProfilePhoto(this, avatar_item.icon, !is_guest);
+  view->SetBoundsRect(current_profile_photo_->bounds());
+  current_profile_name_ =
+      new EditableProfileName(this, avatar_item.name, !is_guest);
 
   layout->StartRow(1, 0);
-  layout->AddView(photo_image, 1, 3);
-  layout->AddView(name_label);
+  layout->AddView(current_profile_photo_, 1, 3);
+  layout->AddView(current_profile_name_);
 
   if (is_guest) {
     layout->StartRow(1, 0);
@@ -483,28 +648,18 @@ views::View* ProfileChooserView::CreateCurrentProfileEditableView(
                     views::kButtonVEdgeMarginNew,
                     views::kButtonHEdgeMarginNew);
 
-  views::View* photo_image = CreateProfileImageView(avatar_item.icon);
-  view->SetBoundsRect(photo_image->bounds());
-
-  // TODO(noms): The name should actually be a textbox and not a label when
-  // we have the functionality to save changes.
-  views::Label* name_label =
-      new views::Label(avatar_item.name,
-                       ui::ResourceBundle::GetSharedInstance().GetFont(
-                           ui::ResourceBundle::MediumFont));
-  name_label->SetElideBehavior(views::Label::ELIDE_AT_END);
-  name_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  change_photo_link_ = CreateLink(
-      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON),
-      this);
+  current_profile_photo_ =
+      new EditableProfilePhoto(this, avatar_item.icon, true);
+  view->SetBoundsRect(current_profile_photo_->bounds());
+  current_profile_name_ =
+      new EditableProfileName(this, avatar_item.name, true);
 
   layout->StartRow(1, 0);
-  layout->AddView(photo_image, 1, 3);
-  layout->AddView(name_label);
+  layout->AddView(current_profile_photo_, 1, 3);
+  layout->AddView(current_profile_name_);
 
   layout->StartRow(1, 0);
   layout->SkipColumns(1);
-  layout->AddView(change_photo_link_);
 
   layout->StartRow(1, 0);
   layout->SkipColumns(1);
@@ -513,7 +668,7 @@ views::View* ProfileChooserView::CreateCurrentProfileEditableView(
 
 views::View* ProfileChooserView::CreateGuestProfileView() {
   gfx::Image guest_icon =
-      ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_GUEST_ICON);
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_LOGIN_GUEST);
   AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
   guest_avatar_item.active = true;
   guest_avatar_item.name = l10n_util::GetStringUTF16(
@@ -526,26 +681,27 @@ views::View* ProfileChooserView::CreateGuestProfileView() {
 views::View* ProfileChooserView::CreateOtherProfilesView(
     const Indexes& avatars_to_show) {
   views::View* view = new views::View();
-  views::GridLayout* layout = CreateSingleColumnLayout(view);
+  views::GridLayout* layout = CreateSingleColumnLayout(
+      view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
   layout->SetInsets(0, views::kButtonHEdgeMarginNew,
                     views::kButtonVEdgeMarginNew, views::kButtonHEdgeMarginNew);
   int num_avatars_to_show = avatars_to_show.size();
   for (int i = 0; i < num_avatars_to_show; ++i) {
     const size_t index = avatars_to_show[i];
     const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
+    const int kSmallImageSide = 32;
 
     gfx::Image image = profiles::GetSizedAvatarIconWithBorder(
         item.icon, true,
         kSmallImageSide + profiles::kAvatarIconPadding,
         kSmallImageSide + profiles::kAvatarIconPadding);
 
-    views::TextButton* button = new views::TextButton(this, item.name);
+    views::LabelButton* button = new views::LabelButton(this, item.name);
     open_other_profile_indexes_map_[button] = index;
-    button->SetIcon(*image.ToImageSkia());
-    button->set_icon_text_spacing(views::kItemLabelSpacing);
-    button->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
+    button->SetImage(views::Button::STATE_NORMAL, *image.ToImageSkia());
+    button->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
         ui::ResourceBundle::MediumFont));
-    button->set_border(NULL);
+    button->SetBorder(views::Border::NullBorder());
 
     layout->StartRow(1, 0);
     layout->AddView(button);
@@ -560,7 +716,7 @@ views::View* ProfileChooserView::CreateOtherProfilesView(
 
 views::View* ProfileChooserView::CreateOptionsView(bool is_guest_view) {
   views::View* view = new views::View();
-  views::GridLayout* layout = CreateSingleColumnLayout(view);
+  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
   // The horizontal padding will be set by each button individually, so that
   // in the hovered state the button spans the entire parent view.
   layout->SetInsets(views::kRelatedControlVerticalSpacing, 0,
@@ -608,29 +764,27 @@ views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
     const AvatarMenu::Item& avatar_item) {
   DCHECK(avatar_item.signed_in);
   views::View* view = new views::View();
-  views::GridLayout* layout = CreateSingleColumnLayout(view);
+  int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
+  views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
   layout->SetInsets(views::kButtonVEdgeMarginNew,
                     views::kButtonHEdgeMarginNew,
                     views::kButtonVEdgeMarginNew,
                     views::kButtonHEdgeMarginNew);
 
   Profile* profile = browser_->profile();
-  std::vector<std::string> accounts(
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile)->GetAccounts());
-  for (size_t i = 0; i < accounts.size(); ++i) {
-    if (i != 0)
-      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
-
-    views::Label* email_label = new views::Label(UTF8ToUTF16(accounts[i]));
-    email_label->SetElideBehavior(views::Label::ELIDE_AS_EMAIL);
-    email_label->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont(
-        ui::ResourceBundle::SmallFont));
-    email_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-
-    layout->StartRow(1, 0);
-    layout->AddView(email_label);
-  }
-
+  std::string primary_account =
+      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
+  DCHECK(!primary_account.empty());
+  std::vector<std::string>accounts =
+      profiles::GetSecondaryAccountsForProfile(profile, primary_account);
+
+  // The primary account should always be listed first.
+  // TODO(rogerta): we still need to further differentiate the primary account
+  // from the others in the UI, so more work is likely required here:
+  // crbug.com/311124.
+  CreateAccountButton(layout, primary_account, true, column_width);
+  for (size_t i = 0; i < accounts.size(); ++i)
+    CreateAccountButton(layout, accounts[i], false, column_width);
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
   add_account_button_ = new views::BlueButton(
@@ -641,3 +795,32 @@ views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
   layout->AddView(add_account_button_);
   return view;
 }
+
+void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
+                                             const std::string& account,
+                                             bool is_primary_account,
+                                             int width) {
+  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+  const gfx::ImageSkia* menu_marker =
+      rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
+  // Use a MenuButtonListener and not a regular ButtonListener to be
+  // able to distinguish between the unnamed "other profile" buttons and the
+  // unnamed "multiple accounts" buttons.
+  views::MenuButton* email_button = new views::MenuButton(
+      NULL,
+      gfx::ElideEmail(base::UTF8ToUTF16(account),
+                      rb->GetFontList(ui::ResourceBundle::BaseFont),
+                      width - menu_marker->width()),
+      is_primary_account ? NULL : this,  // Cannot delete the primary account.
+      !is_primary_account);
+  email_button->SetBorder(views::Border::CreateEmptyBorder(0, 0, 0, 0));
+  if (!is_primary_account) {
+    email_button->set_menu_marker(menu_marker);
+    layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+  }
+  layout->StartRow(1, 0);
+  layout->AddView(email_button);
+
+  // Save the original email address, as the button text could be elided.
+  current_profile_accounts_map_[email_button] = account;
+}