profile_chooser_view.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2014 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/views/profiles/profile_chooser_view.h"
6
7#include "base/prefs/pref_service.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/browser_process.h"
10#include "chrome/browser/lifetime/application_lifetime.h"
11#include "chrome/browser/prefs/incognito_mode_prefs.h"
12#include "chrome/browser/profiles/profile_avatar_icon_util.h"
13#include "chrome/browser/profiles/profile_info_cache.h"
14#include "chrome/browser/profiles/profile_manager.h"
15#include "chrome/browser/profiles/profile_metrics.h"
16#include "chrome/browser/profiles/profile_window.h"
17#include "chrome/browser/profiles/profiles_state.h"
18#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19#include "chrome/browser/signin/signin_header_helper.h"
20#include "chrome/browser/signin/signin_manager_factory.h"
21#include "chrome/browser/signin/signin_promo.h"
22#include "chrome/browser/signin/signin_ui_util.h"
23#include "chrome/browser/ui/browser.h"
24#include "chrome/browser/ui/browser_commands.h"
25#include "chrome/browser/ui/browser_dialogs.h"
26#include "chrome/browser/ui/chrome_pages.h"
27#include "chrome/browser/ui/singleton_tabs.h"
28#include "chrome/browser/ui/views/profiles/user_manager_view.h"
29#include "chrome/browser/ui/webui/signin/login_ui_service.h"
30#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
31#include "chrome/common/pref_names.h"
32#include "chrome/common/url_constants.h"
33#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
34#include "components/signin/core/browser/profile_oauth2_token_service.h"
35#include "components/signin/core/browser/signin_error_controller.h"
36#include "components/signin/core/browser/signin_manager.h"
37#include "components/signin/core/common/profile_management_switches.h"
38#include "grit/chromium_strings.h"
39#include "grit/generated_resources.h"
40#include "grit/theme_resources.h"
41#include "third_party/skia/include/core/SkColor.h"
42#include "ui/base/l10n/l10n_util.h"
43#include "ui/base/resource/resource_bundle.h"
44#include "ui/gfx/canvas.h"
45#include "ui/gfx/image/image.h"
46#include "ui/gfx/image/image_skia.h"
47#include "ui/gfx/path.h"
48#include "ui/gfx/skia_util.h"
49#include "ui/gfx/text_elider.h"
50#include "ui/native_theme/native_theme.h"
51#include "ui/views/controls/button/blue_button.h"
52#include "ui/views/controls/button/image_button.h"
53#include "ui/views/controls/button/label_button.h"
54#include "ui/views/controls/button/menu_button.h"
55#include "ui/views/controls/label.h"
56#include "ui/views/controls/link.h"
57#include "ui/views/controls/separator.h"
58#include "ui/views/controls/styled_label.h"
59#include "ui/views/controls/textfield/textfield.h"
60#include "ui/views/controls/webview/webview.h"
61#include "ui/views/layout/grid_layout.h"
62#include "ui/views/layout/layout_constants.h"
63#include "ui/views/widget/widget.h"
64
65namespace {
66
67// Helpers --------------------------------------------------------------------
68
69const int kFixedMenuWidth = 250;
70const int kButtonHeight = 32;
71const int kFixedGaiaViewHeight = 440;
72const int kFixedGaiaViewWidth = 360;
73const int kFixedAccountRemovalViewWidth = 280;
74const int kFixedSwitchUserViewWidth = 280;
75const int kLargeImageSide = 88;
76
77// Creates a GridLayout with a single column. This ensures that all the child
78// views added get auto-expanded to fill the full width of the bubble.
79views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
80  views::GridLayout* layout = new views::GridLayout(view);
81  view->SetLayoutManager(layout);
82
83  views::ColumnSet* columns = layout->AddColumnSet(0);
84  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
85                     views::GridLayout::FIXED, width, width);
86  return layout;
87}
88
89views::Link* CreateLink(const base::string16& link_text,
90                        views::LinkListener* listener) {
91  views::Link* link_button = new views::Link(link_text);
92  link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
93  link_button->SetUnderline(false);
94  link_button->set_listener(listener);
95  return link_button;
96}
97
98gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
99  SkBitmap bitmap;
100  bitmap.allocPixels(SkImageInfo::MakeA8(size, size));
101  bitmap.eraseARGB(0, 0, 0, 0);
102  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
103}
104
105bool HasAuthError(Profile* profile) {
106  const SigninErrorController* error =
107      profiles::GetSigninErrorController(profile);
108  return error && error->HasError();
109}
110
111std::string GetAuthErrorAccountId(Profile* profile) {
112  const SigninErrorController* error =
113      profiles::GetSigninErrorController(profile);
114  if (!error)
115    return std::string();
116
117  return error->error_account_id();
118}
119
120std::string GetAuthErrorUsername(Profile* profile) {
121  const SigninErrorController* error =
122      profiles::GetSigninErrorController(profile);
123  if (!error)
124    return std::string();
125
126  return error->error_username();
127}
128
129// BackgroundColorHoverButton -------------------------------------------------
130
131// A custom button that allows for setting a background color when hovered over.
132class BackgroundColorHoverButton : public views::LabelButton {
133 public:
134  BackgroundColorHoverButton(views::ButtonListener* listener,
135                             const base::string16& text,
136                             const gfx::ImageSkia& icon)
137      : views::LabelButton(listener, text) {
138    SetImageLabelSpacing(views::kItemLabelSpacing);
139    SetBorder(views::Border::CreateEmptyBorder(
140        0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew));
141    SetMinSize(gfx::Size(0,
142        kButtonHeight + views::kRelatedControlVerticalSpacing));
143    SetImage(STATE_NORMAL, icon);
144    SetFocusable(true);
145  }
146
147  virtual ~BackgroundColorHoverButton() {}
148
149 private:
150  // views::LabelButton:
151  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
152    if ((state() == STATE_PRESSED) ||
153        (state() == STATE_HOVERED) ||
154        HasFocus()) {
155      canvas->DrawColor(GetNativeTheme()->GetSystemColor(
156          ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
157    }
158    LabelButton::OnPaint(canvas);
159  }
160
161  DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
162};
163
164// SizedContainer -------------------------------------------------
165
166// A simple container view that takes an explicit preferred size.
167class SizedContainer : public views::View {
168 public:
169  explicit SizedContainer(const gfx::Size& preferred_size)
170      : preferred_size_(preferred_size) {}
171
172  virtual gfx::Size GetPreferredSize() const OVERRIDE {
173    return preferred_size_;
174  }
175
176 private:
177  gfx::Size preferred_size_;
178};
179
180}  // namespace
181
182// RightAlignedIconLabelButton -------------------------------------------------
183
184// A custom LabelButton that has a centered text and right aligned icon.
185class RightAlignedIconLabelButton : public views::LabelButton {
186 public:
187  RightAlignedIconLabelButton(views::ButtonListener* listener,
188                              const base::string16& text)
189      : views::LabelButton(listener, text) {
190  }
191
192 protected:
193  virtual void Layout() OVERRIDE {
194    // This layout trick keeps the text left-aligned and the icon right-aligned.
195    SetHorizontalAlignment(gfx::ALIGN_RIGHT);
196    views::LabelButton::Layout();
197    label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
198  }
199
200  DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton);
201};
202
203// EditableProfilePhoto -------------------------------------------------
204
205// A custom Image control that shows a "change" button when moused over.
206class EditableProfilePhoto : public views::LabelButton {
207 public:
208  EditableProfilePhoto(views::ButtonListener* listener,
209                       const gfx::Image& icon,
210                       bool is_editing_allowed,
211                       const gfx::Rect& bounds)
212      : views::LabelButton(listener, base::string16()),
213        photo_overlay_(NULL) {
214    gfx::Image image = profiles::GetSizedAvatarIcon(
215        icon, true, kLargeImageSide, kLargeImageSide);
216    SetImage(views::LabelButton::STATE_NORMAL, *image.ToImageSkia());
217    SetBorder(views::Border::NullBorder());
218    SetBoundsRect(bounds);
219
220    // Calculate the circular mask that will be used to display the photo.
221    circular_mask_.addCircle(SkIntToScalar(bounds.width() / 2),
222                             SkIntToScalar(bounds.height() / 2),
223                             SkIntToScalar(bounds.width() / 2));
224
225    if (!is_editing_allowed) {
226      SetEnabled(false);
227      return;
228    }
229
230    SetFocusable(true);
231    set_notify_enter_exit_on_child(true);
232
233    // Photo overlay that appears when hovering over the button.
234    photo_overlay_ = new views::ImageView();
235
236    const SkColor kBackgroundColor = SkColorSetARGB(65, 255, 255, 255);
237    photo_overlay_->set_background(
238        views::Background::CreateSolidBackground(kBackgroundColor));
239    photo_overlay_->SetImage(*ui::ResourceBundle::GetSharedInstance().
240        GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_CAMERA));
241
242    photo_overlay_->SetSize(bounds.size());
243    photo_overlay_->SetVisible(false);
244    AddChildView(photo_overlay_);
245  }
246
247  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
248    // Display the profile picture as a circle.
249    canvas->ClipPath(circular_mask_, true);
250    views::LabelButton::OnPaint(canvas);
251  }
252
253  virtual void PaintChildren(gfx::Canvas* canvas,
254                             const views::CullSet& cull_set) OVERRIDE {
255    // Display any children (the "change photo" overlay) as a circle.
256    canvas->ClipPath(circular_mask_, true);
257    View::PaintChildren(canvas, cull_set);
258  }
259
260 private:
261  // views::CustomButton:
262  virtual void StateChanged() OVERRIDE {
263    bool show_overlay =
264        (state() == STATE_PRESSED || state() == STATE_HOVERED || HasFocus());
265    if (photo_overlay_)
266      photo_overlay_->SetVisible(show_overlay);
267  }
268
269  virtual void OnFocus() OVERRIDE {
270    views::LabelButton::OnFocus();
271    if (photo_overlay_)
272      photo_overlay_->SetVisible(true);
273  }
274
275  virtual void OnBlur() OVERRIDE {
276    views::LabelButton::OnBlur();
277    // Don't hide the overlay if it's being shown as a result of a mouseover.
278    if (photo_overlay_ && state() != STATE_HOVERED)
279      photo_overlay_->SetVisible(false);
280  }
281
282  gfx::Path circular_mask_;
283
284  // Image that is shown when hovering over the image button. Can be NULL if
285  // the photo isn't allowed to be edited (e.g. for guest profiles).
286  views::ImageView* photo_overlay_;
287
288  DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
289};
290
291// EditableProfileName -------------------------------------------------
292
293// A custom text control that turns into a textfield for editing when clicked.
294class EditableProfileName : public RightAlignedIconLabelButton,
295                            public views::ButtonListener {
296 public:
297  EditableProfileName(views::TextfieldController* controller,
298                      const base::string16& text,
299                      bool is_editing_allowed)
300      : RightAlignedIconLabelButton(this, text),
301        profile_name_textfield_(NULL) {
302    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
303    const gfx::FontList& medium_font_list =
304        rb->GetFontList(ui::ResourceBundle::MediumFont);
305    SetFontList(medium_font_list);
306    SetHorizontalAlignment(gfx::ALIGN_CENTER);
307
308    if (!is_editing_allowed) {
309      SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
310      return;
311    }
312
313    SetFocusable(true);
314    // Show an "edit" pencil icon when hovering over. In the default state,
315    // we need to create an empty placeholder of the correct size, so that
316    // the text doesn't jump around when the hovered icon appears.
317    gfx::ImageSkia hover_image =
318        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
319    SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
320    SetImage(STATE_HOVERED, hover_image);
321    SetImage(STATE_PRESSED,
322             *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
323    // To center the text, we need to offest it by the width of the icon we
324    // are adding and its padding. We need to also add a small top/bottom
325    // padding to account for the textfield's border.
326    const int kIconTextLabelButtonSpacing = 5;
327    SetBorder(views::Border::CreateEmptyBorder(
328        2, hover_image.width() + kIconTextLabelButtonSpacing, 2, 0));
329
330    // Textfield that overlaps the button.
331    profile_name_textfield_ = new views::Textfield();
332    profile_name_textfield_->set_controller(controller);
333    profile_name_textfield_->SetFontList(medium_font_list);
334    profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
335
336    profile_name_textfield_->SetVisible(false);
337    AddChildView(profile_name_textfield_);
338  }
339
340  views::Textfield* profile_name_textfield() {
341    return profile_name_textfield_;
342  }
343
344  // Hide the editable textfield to show the profile name button instead.
345  void ShowReadOnlyView() {
346    if (profile_name_textfield_)
347      profile_name_textfield_->SetVisible(false);
348  }
349
350 private:
351  // views::ButtonListener:
352  virtual void ButtonPressed(views::Button* sender,
353                            const ui::Event& event) OVERRIDE {
354    if (profile_name_textfield_) {
355      profile_name_textfield_->SetVisible(true);
356      profile_name_textfield_->SetText(GetText());
357      profile_name_textfield_->SelectAll(false);
358      profile_name_textfield_->RequestFocus();
359    }
360  }
361
362  // views::LabelButton:
363  virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
364    // Override CustomButton's implementation, which presses the button when
365    // you press space and clicks it when you release space, as the space can be
366    // part of the new profile name typed in the textfield.
367    return false;
368  }
369
370  virtual void Layout() OVERRIDE {
371    if (profile_name_textfield_)
372      profile_name_textfield_->SetBounds(0, 0, width(), height());
373    RightAlignedIconLabelButton::Layout();
374  }
375
376  virtual void OnFocus() OVERRIDE {
377    RightAlignedIconLabelButton::OnFocus();
378    SetState(STATE_HOVERED);
379  }
380
381  virtual void OnBlur() OVERRIDE {
382    RightAlignedIconLabelButton::OnBlur();
383    SetState(STATE_NORMAL);
384  }
385
386  // Textfield that is shown when editing the profile name. Can be NULL if
387  // the profile name isn't allowed to be edited (e.g. for guest profiles).
388  views::Textfield* profile_name_textfield_;
389
390  DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
391};
392
393// A title card with one back button right aligned and one label center aligned.
394class TitleCard : public views::View {
395 public:
396  TitleCard(const base::string16& message, views::ButtonListener* listener,
397            views::ImageButton** back_button) {
398    back_button_ = new views::ImageButton(listener);
399    back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
400                                    views::ImageButton::ALIGN_MIDDLE);
401    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
402    back_button_->SetImage(views::ImageButton::STATE_NORMAL,
403                           rb->GetImageSkiaNamed(IDR_BACK));
404    back_button_->SetImage(views::ImageButton::STATE_HOVERED,
405                           rb->GetImageSkiaNamed(IDR_BACK_H));
406    back_button_->SetImage(views::ImageButton::STATE_PRESSED,
407                           rb->GetImageSkiaNamed(IDR_BACK_P));
408    back_button_->SetImage(views::ImageButton::STATE_DISABLED,
409                           rb->GetImageSkiaNamed(IDR_BACK_D));
410    back_button_->SetFocusable(true);
411    *back_button = back_button_;
412
413    title_label_ = new views::Label(message);
414    title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
415    const gfx::FontList& medium_font_list =
416        rb->GetFontList(ui::ResourceBundle::MediumFont);
417    title_label_->SetFontList(medium_font_list);
418
419    AddChildView(back_button_);
420    AddChildView(title_label_);
421  }
422
423  // Creates a new view that has the |title_card| with padding at the top, an
424  // edge-to-edge separator below, and the specified |view| at the bottom.
425  static views::View* AddPaddedTitleCard(views::View* view,
426                                         TitleCard* title_card,
427                                         int width) {
428    views::View* titled_view = new views::View();
429    views::GridLayout* layout = new views::GridLayout(titled_view);
430    titled_view->SetLayoutManager(layout);
431
432    // Column set 0 is a single column layout with horizontal padding at left
433    // and right, and column set 1 is a single column layout with no padding.
434    views::ColumnSet* columns = layout->AddColumnSet(0);
435    columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
436    int available_width = width - 2 * views::kButtonHEdgeMarginNew;
437    columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
438        views::GridLayout::FIXED, available_width, available_width);
439    columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
440    layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
441        views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
442
443    layout->StartRowWithPadding(1, 0, 0, views::kButtonVEdgeMarginNew);
444    layout->AddView(title_card);
445    layout->StartRowWithPadding(1, 1, 0, views::kRelatedControlVerticalSpacing);
446    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
447
448    layout->StartRow(1, 1);
449    layout->AddView(view);
450
451    return titled_view;
452  }
453
454 private:
455  virtual void Layout() OVERRIDE{
456    int back_button_width = back_button_->GetPreferredSize().width();
457    back_button_->SetBounds(0, 0, back_button_width, height());
458    int label_padding = back_button_width + views::kButtonHEdgeMarginNew;
459    int label_width = width() - 2 * label_padding;
460    DCHECK_GT(label_width, 0);
461    title_label_->SetBounds(label_padding, 0, label_width, height());
462  }
463
464  virtual gfx::Size GetPreferredSize() const OVERRIDE{
465    int height = std::max(title_label_->GetPreferredSize().height(),
466        back_button_->GetPreferredSize().height());
467    return gfx::Size(width(), height);
468  }
469
470  views::ImageButton* back_button_;
471  views::Label* title_label_;
472
473  DISALLOW_COPY_AND_ASSIGN(TitleCard);
474};
475
476// ProfileChooserView ---------------------------------------------------------
477
478// static
479ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
480bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
481
482// static
483void ProfileChooserView::ShowBubble(
484    profiles::BubbleViewMode view_mode,
485    profiles::TutorialMode tutorial_mode,
486    const signin::ManageAccountsParams& manage_accounts_params,
487    views::View* anchor_view,
488    views::BubbleBorder::Arrow arrow,
489    views::BubbleBorder::BubbleAlignment border_alignment,
490    Browser* browser) {
491  if (IsShowing()) {
492    if (tutorial_mode != profiles::TUTORIAL_MODE_NONE) {
493      profile_bubble_->tutorial_mode_ = tutorial_mode;
494      profile_bubble_->ShowView(view_mode, profile_bubble_->avatar_menu_.get());
495    }
496    return;
497  }
498
499  profile_bubble_ = new ProfileChooserView(anchor_view, arrow, browser,
500      view_mode, tutorial_mode, manage_accounts_params.service_type);
501  views::BubbleDelegateView::CreateBubble(profile_bubble_);
502  profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
503  profile_bubble_->SetAlignment(border_alignment);
504  profile_bubble_->GetWidget()->Show();
505  profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
506}
507
508// static
509bool ProfileChooserView::IsShowing() {
510  return profile_bubble_ != NULL;
511}
512
513// static
514void ProfileChooserView::Hide() {
515  if (IsShowing())
516    profile_bubble_->GetWidget()->Close();
517}
518
519ProfileChooserView::ProfileChooserView(views::View* anchor_view,
520                                       views::BubbleBorder::Arrow arrow,
521                                       Browser* browser,
522                                       profiles::BubbleViewMode view_mode,
523                                       profiles::TutorialMode tutorial_mode,
524                                       signin::GAIAServiceType service_type)
525    : BubbleDelegateView(anchor_view, arrow),
526      browser_(browser),
527      view_mode_(view_mode),
528      tutorial_mode_(tutorial_mode),
529      gaia_service_type_(service_type) {
530  // Reset the default margins inherited from the BubbleDelegateView.
531  // Add a small bottom inset so that the bubble's rounded corners show up.
532  set_margins(gfx::Insets(0, 0, 1, 0));
533  set_background(views::Background::CreateSolidBackground(
534      GetNativeTheme()->GetSystemColor(
535          ui::NativeTheme::kColorId_DialogBackground)));
536  ResetView();
537
538  avatar_menu_.reset(new AvatarMenu(
539      &g_browser_process->profile_manager()->GetProfileInfoCache(),
540      this,
541      browser_));
542  avatar_menu_->RebuildMenu();
543
544  ProfileOAuth2TokenService* oauth2_token_service =
545      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
546  if (oauth2_token_service)
547    oauth2_token_service->AddObserver(this);
548}
549
550ProfileChooserView::~ProfileChooserView() {
551  ProfileOAuth2TokenService* oauth2_token_service =
552      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
553  if (oauth2_token_service)
554    oauth2_token_service->RemoveObserver(this);
555}
556
557void ProfileChooserView::ResetView() {
558  open_other_profile_indexes_map_.clear();
559  delete_account_button_map_.clear();
560  reauth_account_button_map_.clear();
561  manage_accounts_link_ = NULL;
562  signin_current_profile_link_ = NULL;
563  auth_error_email_button_ = NULL;
564  current_profile_photo_ = NULL;
565  current_profile_name_ = NULL;
566  users_button_ = NULL;
567  go_incognito_button_ = NULL;
568  lock_button_ = NULL;
569  add_account_link_ = NULL;
570  gaia_signin_cancel_button_ = NULL;
571  remove_account_button_ = NULL;
572  account_removal_cancel_button_ = NULL;
573  add_person_button_ = NULL;
574  disconnect_button_ = NULL;
575  switch_user_cancel_button_ = NULL;
576  tutorial_sync_settings_ok_button_ = NULL;
577  tutorial_close_button_ = NULL;
578  tutorial_sync_settings_link_ = NULL;
579  tutorial_see_whats_new_button_ = NULL;
580  tutorial_not_you_link_ = NULL;
581  tutorial_learn_more_link_ = NULL;
582}
583
584void ProfileChooserView::Init() {
585  // If view mode is PROFILE_CHOOSER but there is an auth error, force
586  // ACCOUNT_MANAGEMENT mode.
587  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER &&
588      HasAuthError(browser_->profile()) &&
589      switches::IsEnableAccountConsistency() &&
590      avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex()).
591          signed_in) {
592    view_mode_ = profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
593  }
594
595  ShowView(view_mode_, avatar_menu_.get());
596}
597
598void ProfileChooserView::OnAvatarMenuChanged(
599    AvatarMenu* avatar_menu) {
600  // Do not refresh the avatar menu if the user is on a signin related view.
601  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
602      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
603      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
604    return;
605  }
606
607  // Refresh the view with the new menu. We can't just update the local copy
608  // as this may have been triggered by a sign out action, in which case
609  // the view is being destroyed.
610  ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu);
611}
612
613void ProfileChooserView::OnRefreshTokenAvailable(
614    const std::string& account_id) {
615  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
616      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
617      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
618    // The account management UI is only available through the
619    // --enable-account-consistency flag.
620    ShowView(switches::IsEnableAccountConsistency() ?
621        profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
622        profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
623  }
624}
625
626void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
627  // Refresh the account management view when an account is removed from the
628  // profile.
629  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
630    ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
631}
632
633void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display,
634                                  AvatarMenu* avatar_menu) {
635  // The account management view should only be displayed if the active profile
636  // is signed in.
637  if (view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
638    DCHECK(switches::IsEnableAccountConsistency());
639    const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
640        avatar_menu->GetActiveProfileIndex());
641    DCHECK(active_item.signed_in);
642  }
643
644  if (browser_->profile()->IsSupervised() &&
645      (view_to_display == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
646       view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL)) {
647    LOG(WARNING) << "Supervised user attempted to add/remove account";
648    return;
649  }
650
651  ResetView();
652  RemoveAllChildViews(true);
653  view_mode_ = view_to_display;
654
655  views::GridLayout* layout;
656  views::View* sub_view;
657  switch (view_mode_) {
658    case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
659    case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
660    case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH:
661      layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
662      sub_view = CreateGaiaSigninView();
663      break;
664    case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
665      layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
666      sub_view = CreateAccountRemovalView();
667      break;
668    case profiles::BUBBLE_VIEW_MODE_SWITCH_USER:
669      layout = CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth);
670      sub_view = CreateSwitchUserView();
671      ProfileMetrics::LogProfileNewAvatarMenuNotYou(
672          ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW);
673      break;
674    default:
675      layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
676      sub_view = CreateProfileChooserView(avatar_menu);
677  }
678  // Clears tutorial mode for all non-profile-chooser views.
679  if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER)
680    tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
681
682  layout->StartRow(1, 0);
683  layout->AddView(sub_view);
684  Layout();
685  if (GetBubbleFrameView())
686    SizeToContents();
687}
688
689void ProfileChooserView::WindowClosing() {
690  DCHECK_EQ(profile_bubble_, this);
691  profile_bubble_ = NULL;
692
693  if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) {
694    LoginUIServiceFactory::GetForProfile(browser_->profile())->
695        SyncConfirmationUIClosed(false /* configure_sync_first */);
696  }
697}
698
699void ProfileChooserView::ButtonPressed(views::Button* sender,
700                                       const ui::Event& event) {
701  // Disable button after clicking so that it doesn't get clicked twice and
702  // start a second action... which can crash Chrome.  But don't disable if it
703  // has no parent (like in tests) because that will also crash.
704  if (sender->parent())
705    sender->SetEnabled(false);
706
707  if (sender == users_button_) {
708    // If this is a guest session, also close all the guest browser windows.
709    if (browser_->profile()->IsGuestSession()) {
710      chrome::ShowUserManager(base::FilePath());
711      profiles::CloseGuestProfileWindows();
712    } else {
713      chrome::ShowUserManager(browser_->profile()->GetPath());
714    }
715    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER);
716  } else if (sender == go_incognito_button_) {
717    DCHECK(ShouldShowGoIncognito());
718    chrome::NewIncognitoWindow(browser_);
719  } else if (sender == lock_button_) {
720    profiles::LockProfile(browser_->profile());
721    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK);
722  } else if (sender == auth_error_email_button_) {
723    ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
724  } else if (sender == tutorial_sync_settings_ok_button_) {
725    LoginUIServiceFactory::GetForProfile(browser_->profile())->
726        SyncConfirmationUIClosed(false /* configure_sync_first */);
727    DismissTutorial();
728    ProfileMetrics::LogProfileNewAvatarMenuSignin(
729        ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK);
730  } else if (sender == tutorial_close_button_) {
731    DCHECK(tutorial_mode_ != profiles::TUTORIAL_MODE_NONE &&
732           tutorial_mode_ != profiles::TUTORIAL_MODE_CONFIRM_SIGNIN);
733    DismissTutorial();
734  } else if (sender == tutorial_see_whats_new_button_) {
735    ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
736        ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW);
737    chrome::ShowUserManagerWithTutorial(
738        profiles::USER_MANAGER_TUTORIAL_OVERVIEW);
739  } else if (sender == remove_account_button_) {
740    RemoveAccount();
741  } else if (sender == account_removal_cancel_button_) {
742    account_id_to_remove_.clear();
743    ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
744  } else if (sender == gaia_signin_cancel_button_) {
745    std::string primary_account =
746        SigninManagerFactory::GetForProfile(browser_->profile())->
747        GetAuthenticatedUsername();
748    // The account management view is only available with the
749    // --enable-account-consistency flag.
750    bool account_management_available = !primary_account.empty() &&
751        switches::IsEnableAccountConsistency();
752    ShowView(account_management_available ?
753        profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
754        profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
755  } else if (sender == current_profile_photo_) {
756    avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
757    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE);
758  } else if (sender == signin_current_profile_link_) {
759    ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
760  } else if (sender == add_person_button_) {
761    ProfileMetrics::LogProfileNewAvatarMenuNotYou(
762        ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON);
763    chrome::ShowUserManager(browser_->profile()->GetPath());
764  } else if (sender == disconnect_button_) {
765    ProfileMetrics::LogProfileNewAvatarMenuNotYou(
766        ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT);
767    chrome::ShowSettings(browser_);
768  } else if (sender == switch_user_cancel_button_) {
769    ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
770    ProfileMetrics::LogProfileNewAvatarMenuNotYou(
771        ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK);
772  } else {
773    // Either one of the "other profiles", or one of the profile accounts
774    // buttons was pressed.
775    ButtonIndexes::const_iterator profile_match =
776        open_other_profile_indexes_map_.find(sender);
777    if (profile_match != open_other_profile_indexes_map_.end()) {
778      avatar_menu_->SwitchToProfile(
779          profile_match->second,
780          ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
781          ProfileMetrics::SWITCH_PROFILE_ICON);
782    } else {
783      // This was a profile accounts button.
784      AccountButtonIndexes::const_iterator account_match =
785          delete_account_button_map_.find(sender);
786      if (account_match != delete_account_button_map_.end()) {
787        account_id_to_remove_ = account_match->second;
788        ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL,
789            avatar_menu_.get());
790      } else {
791        account_match = reauth_account_button_map_.find(sender);
792        DCHECK(account_match != reauth_account_button_map_.end());
793        ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
794      }
795    }
796  }
797}
798
799void ProfileChooserView::RemoveAccount() {
800  DCHECK(!account_id_to_remove_.empty());
801  MutableProfileOAuth2TokenService* oauth2_token_service =
802      ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
803      browser_->profile());
804  if (oauth2_token_service) {
805    oauth2_token_service->RevokeCredentials(account_id_to_remove_);
806    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT);
807  }
808  account_id_to_remove_.clear();
809
810  ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
811}
812
813void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
814  if (sender == manage_accounts_link_) {
815    // This link can either mean show/hide the account management view,
816    // depending on which view it is displayed. ShowView() will DCHECK if
817    // the account management view is displayed for non signed-in users.
818    ShowView(
819        view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
820            profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
821            profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
822        avatar_menu_.get());
823  } else if (sender == add_account_link_) {
824    ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
825    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT);
826  } else if (sender == tutorial_sync_settings_link_) {
827    LoginUIServiceFactory::GetForProfile(browser_->profile())->
828        SyncConfirmationUIClosed(true /* configure_sync_first */);
829    tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
830    ProfileMetrics::LogProfileNewAvatarMenuSignin(
831        ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS);
832  } else if (sender == tutorial_not_you_link_){
833    ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
834        ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU);
835    ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER, avatar_menu_.get());
836  } else {
837    DCHECK(sender == tutorial_learn_more_link_);
838    signin_ui_util::ShowSigninErrorLearnMorePage(browser_->profile());
839  }
840}
841
842void ProfileChooserView::StyledLabelLinkClicked(
843    const gfx::Range& range, int event_flags) {
844  chrome::ShowSettings(browser_);
845}
846
847bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
848                                        const ui::KeyEvent& key_event) {
849  views::Textfield* name_textfield =
850      current_profile_name_->profile_name_textfield();
851  DCHECK(sender == name_textfield);
852
853  if (key_event.key_code() == ui::VKEY_RETURN ||
854      key_event.key_code() == ui::VKEY_TAB) {
855    // Pressing Tab/Enter commits the new profile name, unless it's empty.
856    base::string16 new_profile_name = name_textfield->text();
857    base::TrimWhitespace(new_profile_name, base::TRIM_ALL, &new_profile_name);
858    if (new_profile_name.empty())
859      return true;
860
861    const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
862        avatar_menu_->GetActiveProfileIndex());
863    Profile* profile = g_browser_process->profile_manager()->GetProfile(
864        active_item.profile_path);
865    DCHECK(profile);
866
867    if (profile->IsSupervised())
868      return true;
869
870    profiles::UpdateProfileName(profile, new_profile_name);
871    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
872    current_profile_name_->ShowReadOnlyView();
873    return true;
874  }
875  return false;
876}
877
878views::View* ProfileChooserView::CreateProfileChooserView(
879    AvatarMenu* avatar_menu) {
880  views::View* view = new views::View();
881  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
882  // Separate items into active and alternatives.
883  Indexes other_profiles;
884  views::View* tutorial_view = NULL;
885  views::View* current_profile_view = NULL;
886  views::View* current_profile_accounts = NULL;
887  views::View* option_buttons_view = NULL;
888  for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
889    const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
890    if (item.active) {
891      option_buttons_view = CreateOptionsView(
892          switches::IsNewProfileManagement() && item.signed_in);
893      current_profile_view = CreateCurrentProfileView(item, false);
894      if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
895        switch (tutorial_mode_) {
896          case profiles::TUTORIAL_MODE_NONE:
897          case profiles::TUTORIAL_MODE_WELCOME_UPGRADE:
898            tutorial_view = CreateWelcomeUpgradeTutorialViewIfNeeded(
899                tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE,
900                item);
901            break;
902          case profiles::TUTORIAL_MODE_CONFIRM_SIGNIN:
903            tutorial_view = CreateSigninConfirmationView();
904            break;
905          case profiles::TUTORIAL_MODE_SHOW_ERROR:
906            tutorial_view = CreateSigninErrorView();
907            break;
908        }
909      } else {
910        current_profile_accounts = CreateCurrentProfileAccountsView(item);
911      }
912    } else {
913      other_profiles.push_back(i);
914    }
915  }
916
917  if (tutorial_view) {
918    // TODO(mlerman): update UMA stats for the new tutorial.
919    layout->StartRow(1, 0);
920    layout->AddView(tutorial_view);
921  } else {
922    tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
923  }
924
925  if (!current_profile_view) {
926    // Guest windows don't have an active profile.
927    current_profile_view = CreateGuestProfileView();
928    option_buttons_view = CreateOptionsView(false);
929  }
930
931  layout->StartRow(1, 0);
932  layout->AddView(current_profile_view);
933
934  if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
935    DCHECK(current_profile_accounts);
936    layout->StartRow(0, 0);
937    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
938    layout->StartRow(1, 0);
939    layout->AddView(current_profile_accounts);
940  }
941
942  if (browser_->profile()->IsSupervised()) {
943    layout->StartRow(0, 0);
944    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
945    layout->StartRow(1, 0);
946    layout->AddView(CreateSupervisedUserDisclaimerView());
947  }
948
949  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
950    layout->StartRow(1, 0);
951    if (switches::IsFastUserSwitching())
952      layout->AddView(CreateOtherProfilesView(other_profiles));
953  }
954
955  layout->StartRow(0, 0);
956  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
957
958  if (option_buttons_view) {
959    layout->StartRow(0, 0);
960    layout->AddView(option_buttons_view);
961  }
962
963  return view;
964}
965
966void ProfileChooserView::DismissTutorial() {
967  // Never shows the upgrade tutorial again if manually closed.
968  if (tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) {
969    browser_->profile()->GetPrefs()->SetInteger(
970        prefs::kProfileAvatarTutorialShown,
971        signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1);
972  }
973
974  tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
975  ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
976}
977
978views::View* ProfileChooserView::CreateTutorialView(
979    profiles::TutorialMode tutorial_mode,
980    const base::string16& title_text,
981    const base::string16& content_text,
982    const base::string16& link_text,
983    const base::string16& button_text,
984    bool stack_button,
985    views::Link** link,
986    views::LabelButton** button,
987    views::ImageButton** close_button) {
988  tutorial_mode_ = tutorial_mode;
989
990  views::View* view = new views::View();
991  view->set_background(views::Background::CreateSolidBackground(
992      profiles::kAvatarTutorialBackgroundColor));
993  views::GridLayout* layout = CreateSingleColumnLayout(view,
994      kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
995  // Creates a second column set for buttons and links.
996  views::ColumnSet* button_columns = layout->AddColumnSet(1);
997  button_columns->AddColumn(views::GridLayout::LEADING,
998      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
999  button_columns->AddPaddingColumn(
1000      1, views::kUnrelatedControlHorizontalSpacing);
1001  button_columns->AddColumn(views::GridLayout::TRAILING,
1002      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1003  layout->SetInsets(views::kButtonVEdgeMarginNew,
1004                    views::kButtonHEdgeMarginNew,
1005                    views::kButtonVEdgeMarginNew,
1006                    views::kButtonHEdgeMarginNew);
1007
1008  // Adds title and close button if needed.
1009  views::Label* title_label = new views::Label(title_text);
1010  title_label->SetMultiLine(true);
1011  title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1012  title_label->SetAutoColorReadabilityEnabled(false);
1013  title_label->SetEnabledColor(SK_ColorWHITE);
1014  title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1015      ui::ResourceBundle::MediumFont));
1016
1017  if (close_button) {
1018    layout->StartRow(1, 1);
1019    layout->AddView(title_label);
1020    *close_button = new views::ImageButton(this);
1021    (*close_button)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1022                                       views::ImageButton::ALIGN_MIDDLE);
1023    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1024    (*close_button)->SetImage(views::ImageButton::STATE_NORMAL,
1025                              rb->GetImageSkiaNamed(IDR_CLOSE_1));
1026    (*close_button)->SetImage(views::ImageButton::STATE_HOVERED,
1027                              rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1028    (*close_button)->SetImage(views::ImageButton::STATE_PRESSED,
1029                              rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1030    layout->AddView(*close_button);
1031  } else {
1032    layout->StartRow(1, 0);
1033    layout->AddView(title_label);
1034  }
1035
1036  // Adds body content.
1037  views::Label* content_label = new views::Label(content_text);
1038  content_label->SetMultiLine(true);
1039  content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1040  content_label->SetAutoColorReadabilityEnabled(false);
1041  content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
1042  layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
1043  layout->AddView(content_label);
1044
1045  // Adds links and buttons.
1046  bool has_button = !button_text.empty();
1047  if (has_button) {
1048    *button = new views::LabelButton(this, button_text);
1049    (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1050    (*button)->SetStyle(views::Button::STYLE_BUTTON);
1051  }
1052
1053  bool has_link = !link_text.empty();
1054  if (has_link) {
1055    *link = CreateLink(link_text, this);
1056    (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1057    (*link)->SetAutoColorReadabilityEnabled(false);
1058    (*link)->SetEnabledColor(SK_ColorWHITE);
1059  }
1060
1061  if (stack_button) {
1062    DCHECK(has_button);
1063    layout->StartRowWithPadding(
1064        1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1065    layout->AddView(*button);
1066    if (has_link) {
1067      layout->StartRowWithPadding(
1068          1, 0, 0, views::kRelatedControlVerticalSpacing);
1069      (*link)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1070      layout->AddView(*link);
1071    }
1072  } else {
1073    DCHECK(has_link || has_button);
1074    layout->StartRowWithPadding(
1075        1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1076    if (has_link)
1077      layout->AddView(*link);
1078    else
1079      layout->SkipColumns(1);
1080    if (has_button)
1081      layout->AddView(*button);
1082    else
1083      layout->SkipColumns(1);
1084  }
1085
1086  return view;
1087}
1088
1089views::View* ProfileChooserView::CreateCurrentProfileView(
1090    const AvatarMenu::Item& avatar_item,
1091    bool is_guest) {
1092  views::View* view = new views::View();
1093  int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
1094  views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
1095  layout->SetInsets(views::kButtonVEdgeMarginNew,
1096                    views::kButtonHEdgeMarginNew,
1097                    views::kUnrelatedControlVerticalSpacing,
1098                    views::kButtonHEdgeMarginNew);
1099
1100  // Profile icon, centered.
1101  int x_offset = (column_width - kLargeImageSide) / 2;
1102  current_profile_photo_ = new EditableProfilePhoto(
1103      this, avatar_item.icon, !is_guest,
1104      gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
1105  SizedContainer* profile_icon_container =
1106      new SizedContainer(gfx::Size(column_width, kLargeImageSide));
1107  profile_icon_container->AddChildView(current_profile_photo_);
1108
1109  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1110  if (browser_->profile()->IsSupervised()) {
1111    views::ImageView* supervised_icon = new views::ImageView();
1112    supervised_icon->SetImage(
1113        rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_SUPERVISED));
1114    gfx::Size preferred_size = supervised_icon->GetPreferredSize();
1115    gfx::Rect parent_bounds = current_profile_photo_->bounds();
1116    supervised_icon->SetBounds(
1117        parent_bounds.right() - preferred_size.width(),
1118        parent_bounds.bottom() - preferred_size.height(),
1119        preferred_size.width(),
1120        preferred_size.height());
1121    profile_icon_container->AddChildView(supervised_icon);
1122  }
1123
1124  layout->StartRow(1, 0);
1125  layout->AddView(profile_icon_container);
1126
1127  // Profile name, centered.
1128  bool editing_allowed = !is_guest && !browser_->profile()->IsSupervised();
1129  current_profile_name_ = new EditableProfileName(
1130      this,
1131      profiles::GetAvatarNameForProfile(browser_->profile()->GetPath()),
1132      editing_allowed);
1133  layout->StartRowWithPadding(1, 0, 0,
1134                              views::kRelatedControlSmallVerticalSpacing);
1135  layout->StartRow(1, 0);
1136  layout->AddView(current_profile_name_);
1137
1138  if (is_guest)
1139    return view;
1140
1141  // The available links depend on the type of profile that is active.
1142  if (avatar_item.signed_in) {
1143    layout->StartRow(1, 0);
1144    if (switches::IsEnableAccountConsistency()) {
1145      base::string16 link_title = l10n_util::GetStringUTF16(
1146          view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ?
1147              IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
1148              IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
1149      manage_accounts_link_ = CreateLink(link_title, this);
1150      manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1151      layout->AddView(manage_accounts_link_);
1152    } else {
1153      // Add a small padding between the email button and the profile name.
1154      layout->StartRowWithPadding(1, 0, 0, 2);
1155      // Badge the email address if there's an authentication error.
1156      if (HasAuthError(browser_->profile())) {
1157        const gfx::ImageSkia warning_image = *rb->GetImageNamed(
1158            IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia();
1159        auth_error_email_button_ =
1160            new RightAlignedIconLabelButton(this, avatar_item.sync_state);
1161        auth_error_email_button_->SetElideBehavior(gfx::ELIDE_EMAIL);
1162        auth_error_email_button_->SetBorder(views::Border::NullBorder());
1163        auth_error_email_button_->SetImage(
1164            views::LabelButton::STATE_NORMAL, warning_image);
1165        auth_error_email_button_->SetTextColor(
1166            views::LabelButton::STATE_NORMAL,
1167            views::Link::GetDefaultEnabledColor());
1168        auth_error_email_button_->SetFocusable(true);
1169        layout->AddView(auth_error_email_button_);
1170      } else {
1171        views::Label* email_label = new views::Label(avatar_item.sync_state);
1172        email_label->SetElideBehavior(gfx::ELIDE_EMAIL);
1173        email_label->SetEnabled(false);
1174        layout->AddView(email_label);
1175      }
1176    }
1177  } else {
1178    SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(
1179        browser_->profile()->GetOriginalProfile());
1180    if (signin_manager->IsSigninAllowed()) {
1181      views::Label* promo = new views::Label(
1182          l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO));
1183      promo->SetMultiLine(true);
1184      promo->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1185      layout->StartRowWithPadding(1, 0, 0,
1186                                  views::kRelatedControlSmallVerticalSpacing);
1187      layout->StartRow(1, 0);
1188      layout->AddView(promo);
1189
1190      signin_current_profile_link_ = new views::BlueButton(
1191        this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
1192            l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
1193      layout->StartRowWithPadding(1, 0, 0,
1194                                  views::kRelatedControlVerticalSpacing);
1195      layout->StartRow(1, 0);
1196      layout->AddView(signin_current_profile_link_);
1197    }
1198  }
1199
1200  return view;
1201}
1202
1203views::View* ProfileChooserView::CreateGuestProfileView() {
1204  gfx::Image guest_icon =
1205      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1206          profiles::GetPlaceholderAvatarIconResourceID());
1207  AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
1208  guest_avatar_item.active = true;
1209  guest_avatar_item.name = l10n_util::GetStringUTF16(
1210      IDS_PROFILES_GUEST_PROFILE_NAME);
1211  guest_avatar_item.signed_in = false;
1212
1213  return CreateCurrentProfileView(guest_avatar_item, true);
1214}
1215
1216views::View* ProfileChooserView::CreateOtherProfilesView(
1217    const Indexes& avatars_to_show) {
1218  views::View* view = new views::View();
1219  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1220
1221  int num_avatars_to_show = avatars_to_show.size();
1222  for (int i = 0; i < num_avatars_to_show; ++i) {
1223    const size_t index = avatars_to_show[i];
1224    const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
1225    const int kSmallImageSide = 32;
1226
1227    gfx::Image image = profiles::GetSizedAvatarIcon(
1228        item.icon, true, kSmallImageSide, kSmallImageSide);
1229
1230    views::LabelButton* button = new BackgroundColorHoverButton(
1231        this,
1232        item.name,
1233        *image.ToImageSkia());
1234    open_other_profile_indexes_map_[button] = index;
1235
1236    layout->StartRow(1, 0);
1237    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1238    layout->StartRow(1, 0);
1239    layout->AddView(button);
1240  }
1241
1242  return view;
1243}
1244
1245views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) {
1246  views::View* view = new views::View();
1247  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1248
1249  base::string16 text = browser_->profile()->IsGuestSession() ?
1250      l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1251      l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON);
1252  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1253  users_button_ = new BackgroundColorHoverButton(
1254      this,
1255      text,
1256      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1257  layout->StartRow(1, 0);
1258  layout->AddView(users_button_);
1259
1260  if (ShouldShowGoIncognito()) {
1261    layout->StartRow(1, 0);
1262    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1263
1264    go_incognito_button_ = new BackgroundColorHoverButton(
1265        this,
1266        l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON),
1267        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO));
1268    layout->StartRow(1, 0);
1269    layout->AddView(go_incognito_button_);
1270  }
1271
1272  if (enable_lock) {
1273    layout->StartRow(1, 0);
1274    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1275
1276    lock_button_ = new BackgroundColorHoverButton(
1277        this,
1278        l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON),
1279        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1280    layout->StartRow(1, 0);
1281    layout->AddView(lock_button_);
1282  }
1283  return view;
1284}
1285
1286views::View* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1287  views::View* view = new views::View();
1288  views::GridLayout* layout = CreateSingleColumnLayout(
1289      view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1290  layout->SetInsets(views::kRelatedControlVerticalSpacing,
1291                    views::kButtonHEdgeMarginNew,
1292                    views::kRelatedControlVerticalSpacing,
1293                    views::kButtonHEdgeMarginNew);
1294  views::Label* disclaimer = new views::Label(
1295      avatar_menu_->GetSupervisedUserInformation());
1296  disclaimer->SetMultiLine(true);
1297  disclaimer->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1298  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1299  disclaimer->SetFontList(rb->GetFontList(ui::ResourceBundle::SmallFont));
1300  layout->StartRow(1, 0);
1301  layout->AddView(disclaimer);
1302
1303  return view;
1304}
1305
1306views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1307    const AvatarMenu::Item& avatar_item) {
1308  DCHECK(avatar_item.signed_in);
1309  views::View* view = new views::View();
1310  view->set_background(views::Background::CreateSolidBackground(
1311      profiles::kAvatarBubbleAccountsBackgroundColor));
1312  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1313
1314  Profile* profile = browser_->profile();
1315  std::string primary_account =
1316      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
1317  DCHECK(!primary_account.empty());
1318  std::vector<std::string>accounts =
1319      profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1320
1321  // Get state of authentication error, if any.
1322  std::string error_account_id = GetAuthErrorAccountId(profile);
1323
1324  // The primary account should always be listed first.
1325  // TODO(rogerta): we still need to further differentiate the primary account
1326  // from the others in the UI, so more work is likely required here:
1327  // crbug.com/311124.
1328  CreateAccountButton(layout, primary_account, true,
1329                      error_account_id == primary_account, kFixedMenuWidth);
1330  for (size_t i = 0; i < accounts.size(); ++i)
1331    CreateAccountButton(layout, accounts[i], false,
1332                        error_account_id == accounts[i], kFixedMenuWidth);
1333
1334  if (!profile->IsSupervised()) {
1335    layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1336
1337    add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1338        IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1339    add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1340        0, views::kButtonVEdgeMarginNew,
1341        views::kRelatedControlVerticalSpacing, 0));
1342    layout->StartRow(1, 0);
1343    layout->AddView(add_account_link_);
1344  }
1345
1346  return view;
1347}
1348
1349void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1350                                             const std::string& account,
1351                                             bool is_primary_account,
1352                                             bool reauth_required,
1353                                             int width) {
1354  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1355  const gfx::ImageSkia* delete_default_image =
1356      rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1357  const int kDeleteButtonWidth = delete_default_image->width();
1358  const gfx::ImageSkia warning_default_image = reauth_required ?
1359      *rb->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia() :
1360      gfx::ImageSkia();
1361  const int kWarningButtonWidth = reauth_required ?
1362      warning_default_image.width() + views::kRelatedButtonHSpacing : 0;
1363  int available_width = width - 2 * views::kButtonHEdgeMarginNew
1364      - kDeleteButtonWidth - kWarningButtonWidth;
1365  views::LabelButton* email_button = new BackgroundColorHoverButton(
1366      reauth_required ? this : NULL,
1367      base::UTF8ToUTF16(account),
1368      warning_default_image);
1369  email_button->SetElideBehavior(gfx::ELIDE_EMAIL);
1370  email_button->SetMinSize(gfx::Size(0, kButtonHeight));
1371  email_button->SetMaxSize(gfx::Size(available_width, kButtonHeight));
1372  layout->StartRow(1, 0);
1373  layout->AddView(email_button);
1374
1375  if (reauth_required)
1376    reauth_account_button_map_[email_button] = account;
1377
1378  // Delete button.
1379  if (!browser_->profile()->IsSupervised()) {
1380    views::ImageButton* delete_button = new views::ImageButton(this);
1381    delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1382                                     views::ImageButton::ALIGN_MIDDLE);
1383    delete_button->SetImage(views::ImageButton::STATE_NORMAL,
1384                            delete_default_image);
1385    delete_button->SetImage(views::ImageButton::STATE_HOVERED,
1386                            rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1387    delete_button->SetImage(views::ImageButton::STATE_PRESSED,
1388                            rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1389    delete_button->SetBounds(
1390        width - views::kButtonHEdgeMarginNew - kDeleteButtonWidth,
1391        0, kDeleteButtonWidth, kButtonHeight);
1392
1393    email_button->set_notify_enter_exit_on_child(true);
1394    email_button->AddChildView(delete_button);
1395
1396    // Save the original email address, as the button text could be elided.
1397    delete_account_button_map_[delete_button] = account;
1398  }
1399}
1400
1401views::View* ProfileChooserView::CreateGaiaSigninView() {
1402  GURL url;
1403  int message_id;
1404
1405  switch (view_mode_) {
1406    case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
1407      url = signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_SIGN_IN,
1408                                false /* auto_close */,
1409                                true /* is_constrained */);
1410      message_id = IDS_PROFILES_GAIA_SIGNIN_TITLE;
1411      break;
1412    case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
1413      url = signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT,
1414                                false /* auto_close */,
1415                                true /* is_constrained */);
1416      message_id = IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE;
1417      break;
1418    case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: {
1419      DCHECK(HasAuthError(browser_->profile()));
1420      url = signin::GetReauthURL(browser_->profile(),
1421                                 GetAuthErrorUsername(browser_->profile()));
1422      message_id = IDS_PROFILES_GAIA_REAUTH_TITLE;
1423      break;
1424    }
1425    default:
1426      NOTREACHED() << "Called with invalid mode=" << view_mode_;
1427      return NULL;
1428  }
1429
1430  // Adds Gaia signin webview
1431  Profile* profile = browser_->profile();
1432  views::WebView* web_view = new views::WebView(profile);
1433  web_view->LoadInitialURL(url);
1434  web_view->SetPreferredSize(
1435      gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1436
1437  TitleCard* title_card = new TitleCard(l10n_util::GetStringUTF16(message_id),
1438                                        this,
1439                                        &gaia_signin_cancel_button_);
1440  return TitleCard::AddPaddedTitleCard(
1441      web_view, title_card, kFixedGaiaViewWidth);
1442}
1443
1444views::View* ProfileChooserView::CreateAccountRemovalView() {
1445  views::View* view = new views::View();
1446  views::GridLayout* layout = CreateSingleColumnLayout(
1447      view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1448  layout->SetInsets(0,
1449                    views::kButtonHEdgeMarginNew,
1450                    views::kButtonVEdgeMarginNew,
1451                    views::kButtonHEdgeMarginNew);
1452
1453  const std::string& primary_account = SigninManagerFactory::GetForProfile(
1454      browser_->profile())->GetAuthenticatedUsername();
1455  bool is_primary_account = primary_account == account_id_to_remove_;
1456
1457  // Adds main text.
1458  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1459  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1460  const gfx::FontList& small_font_list =
1461      rb->GetFontList(ui::ResourceBundle::SmallFont);
1462
1463  if (is_primary_account) {
1464    std::vector<size_t> offsets;
1465    const base::string16 settings_text =
1466        l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1467    const base::string16 primary_account_removal_text =
1468        l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1469            base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets);
1470    views::StyledLabel* primary_account_removal_label =
1471        new views::StyledLabel(primary_account_removal_text, this);
1472    primary_account_removal_label->AddStyleRange(
1473        gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1474        views::StyledLabel::RangeStyleInfo::CreateForLink());
1475    primary_account_removal_label->SetBaseFontList(small_font_list);
1476    layout->AddView(primary_account_removal_label);
1477  } else {
1478    views::Label* content_label = new views::Label(
1479        l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1480    content_label->SetMultiLine(true);
1481    content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1482    content_label->SetFontList(small_font_list);
1483    layout->AddView(content_label);
1484  }
1485
1486  // Adds button.
1487  if (!is_primary_account) {
1488    remove_account_button_ = new views::BlueButton(
1489        this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1490    remove_account_button_->SetHorizontalAlignment(
1491        gfx::ALIGN_CENTER);
1492    layout->StartRowWithPadding(
1493        1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1494    layout->AddView(remove_account_button_);
1495  } else {
1496    layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1497  }
1498
1499  TitleCard* title_card = new TitleCard(
1500      l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE),
1501      this, &account_removal_cancel_button_);
1502  return TitleCard::AddPaddedTitleCard(view, title_card,
1503      kFixedAccountRemovalViewWidth);
1504}
1505
1506views::View* ProfileChooserView::CreateWelcomeUpgradeTutorialViewIfNeeded(
1507    bool tutorial_shown, const AvatarMenu::Item& avatar_item){
1508  Profile* profile = browser_->profile();
1509
1510  const int show_count = profile->GetPrefs()->GetInteger(
1511      prefs::kProfileAvatarTutorialShown);
1512  // Do not show the tutorial if user has dismissed it.
1513  if (show_count > signin_ui_util::kUpgradeWelcomeTutorialShowMax)
1514    return NULL;
1515
1516  if (!tutorial_shown) {
1517    if (show_count == signin_ui_util::kUpgradeWelcomeTutorialShowMax)
1518      return NULL;
1519    profile->GetPrefs()->SetInteger(
1520        prefs::kProfileAvatarTutorialShown, show_count + 1);
1521  }
1522  ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1523      ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW);
1524
1525  // For local profiles, the "Not you" link doesn't make sense.
1526  base::string16 link_message = avatar_item.signed_in ?
1527      l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name) :
1528      base::string16();
1529
1530  return CreateTutorialView(
1531      profiles::TUTORIAL_MODE_WELCOME_UPGRADE,
1532      l10n_util::GetStringUTF16(
1533          IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE),
1534      l10n_util::GetStringUTF16(
1535          IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT),
1536      link_message,
1537      l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON),
1538      true /* stack_button */,
1539      &tutorial_not_you_link_,
1540      &tutorial_see_whats_new_button_,
1541      &tutorial_close_button_);
1542}
1543
1544views::View* ProfileChooserView::CreateSigninConfirmationView() {
1545  ProfileMetrics::LogProfileNewAvatarMenuSignin(
1546      ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW);
1547
1548  return CreateTutorialView(
1549      profiles::TUTORIAL_MODE_CONFIRM_SIGNIN,
1550      l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE),
1551      l10n_util::GetStringUTF16(
1552          IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT),
1553      l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK),
1554      l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
1555      false /* stack_button */,
1556      &tutorial_sync_settings_link_,
1557      &tutorial_sync_settings_ok_button_,
1558      NULL /* close_button*/);
1559}
1560
1561views::View* ProfileChooserView::CreateSigninErrorView() {
1562  LoginUIService* login_ui_service =
1563      LoginUIServiceFactory::GetForProfile(browser_->profile());
1564  base::string16 last_login_result(login_ui_service->GetLastLoginResult());
1565  return CreateTutorialView(
1566      profiles::TUTORIAL_MODE_SHOW_ERROR,
1567      l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE),
1568      last_login_result,
1569      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1570      base::string16(),
1571      false /* stack_button */,
1572      &tutorial_learn_more_link_,
1573      NULL,
1574      &tutorial_close_button_);
1575}
1576
1577views::View* ProfileChooserView::CreateSwitchUserView() {
1578  views::View* view = new views::View();
1579  views::GridLayout* layout = CreateSingleColumnLayout(
1580      view, kFixedSwitchUserViewWidth);
1581  views::ColumnSet* columns = layout->AddColumnSet(1);
1582  columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1583  int label_width =
1584      kFixedSwitchUserViewWidth - 2 * views::kButtonHEdgeMarginNew;
1585  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1586                     views::GridLayout::FIXED, label_width, label_width);
1587  columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1588
1589  // Adds main text.
1590  layout->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1591  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1592  const gfx::FontList& small_font_list =
1593      rb->GetFontList(ui::ResourceBundle::SmallFont);
1594  const AvatarMenu::Item& avatar_item =
1595      avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex());
1596  views::Label* content_label = new views::Label(
1597      l10n_util::GetStringFUTF16(
1598          IDS_PROFILES_NOT_YOU_CONTENT_TEXT, avatar_item.name));
1599  content_label->SetMultiLine(true);
1600  content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1601  content_label->SetFontList(small_font_list);
1602  layout->AddView(content_label);
1603
1604  // Adds "Add person" button.
1605  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1606  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1607
1608  add_person_button_ = new BackgroundColorHoverButton(
1609      this,
1610      l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON),
1611      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1612  layout->StartRow(1, 0);
1613  layout->AddView(add_person_button_);
1614
1615  // Adds "Disconnect your Google Account" button.
1616  layout->StartRow(1, 0);
1617  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1618
1619  disconnect_button_ = new BackgroundColorHoverButton(
1620      this,
1621      l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON),
1622      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT));
1623  layout->StartRow(1, 0);
1624  layout->AddView(disconnect_button_);
1625
1626  TitleCard* title_card = new TitleCard(
1627      l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name),
1628      this, &switch_user_cancel_button_);
1629  return TitleCard::AddPaddedTitleCard(view, title_card,
1630      kFixedSwitchUserViewWidth);
1631}
1632
1633bool ProfileChooserView::ShouldShowGoIncognito() const {
1634  bool incognito_available =
1635      IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) !=
1636          IncognitoModePrefs::DISABLED;
1637  return incognito_available && !browser_->profile()->IsGuestSession();
1638}
1639
1640void ProfileChooserView::PostActionPerformed(
1641    ProfileMetrics::ProfileDesktopMenu action_performed) {
1642  ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_);
1643  gaia_service_type_ = signin::GAIA_SERVICE_TYPE_NONE;
1644}
1645