Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / profiles / profile_chooser_view.cc
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
65 namespace {
66
67 // Helpers --------------------------------------------------------------------
68
69 const int kFixedMenuWidth = 250;
70 const int kButtonHeight = 32;
71 const int kFixedGaiaViewHeight = 440;
72 const int kFixedGaiaViewWidth = 360;
73 const int kFixedAccountRemovalViewWidth = 280;
74 const int kFixedSwitchUserViewWidth = 280;
75 const 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.
79 views::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
89 views::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
98 gfx::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
105 bool HasAuthError(Profile* profile) {
106   const SigninErrorController* error =
107       profiles::GetSigninErrorController(profile);
108   return error && error->HasError();
109 }
110
111 std::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
120 std::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.
132 class 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.
167 class 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.
185 class 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.
206 class 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.
294 class 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.
394 class 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
479 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
480 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
481
482 // static
483 void 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
509 bool ProfileChooserView::IsShowing() {
510   return profile_bubble_ != NULL;
511 }
512
513 // static
514 void ProfileChooserView::Hide() {
515   if (IsShowing())
516     profile_bubble_->GetWidget()->Close();
517 }
518
519 ProfileChooserView::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
550 ProfileChooserView::~ProfileChooserView() {
551   ProfileOAuth2TokenService* oauth2_token_service =
552       ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
553   if (oauth2_token_service)
554     oauth2_token_service->RemoveObserver(this);
555 }
556
557 void 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
584 void 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
598 void 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
613 void 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
626 void 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
633 void 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
689 void 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
699 void 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
799 void 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
813 void 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
842 void ProfileChooserView::StyledLabelLinkClicked(
843     const gfx::Range& range, int event_flags) {
844   chrome::ShowSettings(browser_);
845 }
846
847 bool 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
878 views::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
966 void 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
978 views::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
1089 views::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
1203 views::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
1216 views::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
1245 views::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
1286 views::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
1306 views::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
1349 void 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
1401 views::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
1444 views::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
1506 views::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
1544 views::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
1561 views::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
1577 views::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
1633 bool 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
1640 void 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 }