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