profile_chooser_view.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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/profiles/profile_avatar_icon_util.h"
12#include "chrome/browser/profiles/profile_info_cache.h"
13#include "chrome/browser/profiles/profile_manager.h"
14#include "chrome/browser/profiles/profile_window.h"
15#include "chrome/browser/profiles/profiles_state.h"
16#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17#include "chrome/browser/signin/signin_manager_factory.h"
18#include "chrome/browser/signin/signin_promo.h"
19#include "chrome/browser/ui/browser.h"
20#include "chrome/browser/ui/browser_commands.h"
21#include "chrome/browser/ui/browser_dialogs.h"
22#include "chrome/browser/ui/chrome_pages.h"
23#include "chrome/browser/ui/singleton_tabs.h"
24#include "chrome/browser/ui/views/profiles/user_manager_view.h"
25#include "chrome/common/pref_names.h"
26#include "chrome/common/url_constants.h"
27#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
28#include "components/signin/core/browser/profile_oauth2_token_service.h"
29#include "components/signin/core/browser/signin_manager.h"
30#include "components/signin/core/common/profile_management_switches.h"
31#include "grit/chromium_strings.h"
32#include "grit/generated_resources.h"
33#include "grit/theme_resources.h"
34#include "third_party/skia/include/core/SkColor.h"
35#include "ui/base/l10n/l10n_util.h"
36#include "ui/base/resource/resource_bundle.h"
37#include "ui/gfx/canvas.h"
38#include "ui/gfx/image/image.h"
39#include "ui/gfx/image/image_skia.h"
40#include "ui/gfx/text_elider.h"
41#include "ui/native_theme/native_theme.h"
42#include "ui/views/controls/button/blue_button.h"
43#include "ui/views/controls/button/image_button.h"
44#include "ui/views/controls/button/label_button.h"
45#include "ui/views/controls/button/menu_button.h"
46#include "ui/views/controls/label.h"
47#include "ui/views/controls/link.h"
48#include "ui/views/controls/separator.h"
49#include "ui/views/controls/styled_label.h"
50#include "ui/views/controls/textfield/textfield.h"
51#include "ui/views/controls/webview/webview.h"
52#include "ui/views/layout/grid_layout.h"
53#include "ui/views/layout/layout_constants.h"
54#include "ui/views/widget/widget.h"
55
56namespace {
57
58// Helpers --------------------------------------------------------------------
59
60const int kFixedMenuWidth = 250;
61const int kButtonHeight = 29;
62const int kProfileAvatarTutorialShowMax = 5;
63const int kFixedGaiaViewHeight = 400;
64const int kFixedGaiaViewWidth = 360;
65const int kFixedAccountRemovalViewWidth = 280;
66const int kFixedEndPreviewViewWidth = 280;
67const int kLargeImageSide = 88;
68
69// Creates a GridLayout with a single column. This ensures that all the child
70// views added get auto-expanded to fill the full width of the bubble.
71views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
72  views::GridLayout* layout = new views::GridLayout(view);
73  view->SetLayoutManager(layout);
74
75  views::ColumnSet* columns = layout->AddColumnSet(0);
76  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
77                     views::GridLayout::FIXED, width, width);
78  return layout;
79}
80
81views::Link* CreateLink(const base::string16& link_text,
82                        views::LinkListener* listener) {
83  views::Link* link_button = new views::Link(link_text);
84  link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
85  link_button->SetUnderline(false);
86  link_button->set_listener(listener);
87  return link_button;
88}
89
90gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
91  SkBitmap bitmap;
92  bitmap.setConfig(SkBitmap::kA8_Config, size, size);
93  bitmap.allocPixels();
94  bitmap.eraseARGB(0, 0, 0, 0);
95  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
96}
97
98// BackgroundColorHoverButton -------------------------------------------------
99
100// A custom button that allows for setting a background color when hovered over.
101class BackgroundColorHoverButton : public views::LabelButton {
102 public:
103  BackgroundColorHoverButton(views::ButtonListener* listener,
104                             const base::string16& text,
105                             const gfx::ImageSkia& normal_icon,
106                             const gfx::ImageSkia& hover_icon);
107  virtual ~BackgroundColorHoverButton();
108
109 private:
110  // views::LabelButton:
111  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
112
113  DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
114};
115
116BackgroundColorHoverButton::BackgroundColorHoverButton(
117    views::ButtonListener* listener,
118    const base::string16& text,
119    const gfx::ImageSkia& normal_icon,
120    const gfx::ImageSkia& hover_icon)
121    : views::LabelButton(listener, text) {
122  SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew,
123                                             0, views::kButtonHEdgeMarginNew));
124  set_min_size(gfx::Size(0, kButtonHeight));
125  SetImage(STATE_NORMAL, normal_icon);
126  SetImage(STATE_HOVERED, hover_icon);
127  SetImage(STATE_PRESSED, hover_icon);
128}
129
130BackgroundColorHoverButton::~BackgroundColorHoverButton() {}
131
132void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) {
133  if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) {
134    canvas->DrawColor(GetNativeTheme()->GetSystemColor(
135        ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
136  }
137  LabelButton::OnPaint(canvas);
138}
139
140}  // namespace
141
142
143// EditableProfilePhoto -------------------------------------------------
144
145// A custom Image control that shows a "change" button when moused over.
146class EditableProfilePhoto : public views::ImageView {
147 public:
148  EditableProfilePhoto(views::ButtonListener* listener,
149                       const gfx::Image& icon,
150                       bool is_editing_allowed,
151                       const gfx::Rect& bounds)
152      : views::ImageView(),
153        change_photo_button_(NULL) {
154    gfx::Image image = profiles::GetSizedAvatarIcon(
155        icon, true,
156        kLargeImageSide + profiles::kAvatarIconPadding,
157        kLargeImageSide + profiles::kAvatarIconPadding);
158    SetImage(image.ToImageSkia());
159    SetBoundsRect(bounds);
160
161    if (!is_editing_allowed)
162      return;
163
164    set_notify_enter_exit_on_child(true);
165
166    // Button overlay that appears when hovering over the image.
167    change_photo_button_ = new views::LabelButton(listener,
168        l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON));
169    change_photo_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
170    change_photo_button_->SetBorder(views::Border::NullBorder());
171    const SkColor color = SK_ColorWHITE;
172    change_photo_button_->SetTextColor(views::Button::STATE_NORMAL, color);
173    change_photo_button_->SetTextColor(views::Button::STATE_HOVERED, color);
174
175    const SkColor kBackgroundColor = SkColorSetARGB(125, 0, 0, 0);
176    change_photo_button_->set_background(
177        views::Background::CreateSolidBackground(kBackgroundColor));
178    // Need to take into account the border padding on the avatar.
179    const int kOverlayHeight = 20;
180    change_photo_button_->SetBounds(
181        bounds.origin().x(),
182        bounds.origin().y() + kLargeImageSide - kOverlayHeight,
183        kLargeImageSide,
184        kOverlayHeight);
185    change_photo_button_->SetVisible(false);
186    AddChildView(change_photo_button_);
187  }
188
189  views::LabelButton* change_photo_button() { return change_photo_button_; }
190
191 private:
192  // views::View:
193  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
194    if (change_photo_button_)
195      change_photo_button_->SetVisible(true);
196  }
197
198  virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
199    if (change_photo_button_)
200      change_photo_button_->SetVisible(false);
201  }
202
203  // Button that is shown when hovering over the image view. Can be NULL if
204  // the photo isn't allowed to be edited (e.g. for guest profiles).
205  views::LabelButton* change_photo_button_;
206
207  DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
208};
209
210
211// EditableProfileName -------------------------------------------------
212
213// A custom text control that turns into a textfield for editing when clicked.
214class EditableProfileName : public views::LabelButton,
215                            public views::ButtonListener {
216 public:
217  EditableProfileName(views::TextfieldController* controller,
218                      const base::string16& text,
219                      bool is_editing_allowed)
220      : views::LabelButton(this, text),
221        profile_name_textfield_(NULL) {
222    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
223    const gfx::FontList& medium_font_list =
224        rb->GetFontList(ui::ResourceBundle::MediumFont);
225    SetFontList(medium_font_list);
226    SetHorizontalAlignment(gfx::ALIGN_CENTER);
227
228    if (!is_editing_allowed)
229      return;
230
231    // Show an "edit" pencil icon when hovering over. In the default state,
232    // we need to create an empty placeholder of the correct size, so that
233    // the text doesn't jump around when the hovered icon appears.
234    gfx::ImageSkia hover_image =
235        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
236    SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
237    SetImage(STATE_HOVERED, hover_image);
238    SetImage(STATE_PRESSED,
239             *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
240    // To center the text, we need to offest it by the width of the icon we
241    // are adding. We need to also add a small top/bottom padding to account
242    // for the textfield's border.
243    SetBorder(views::Border::CreateEmptyBorder(2, hover_image.width(), 2, 0));
244
245    // Textfield that overlaps the button.
246    profile_name_textfield_ = new views::Textfield();
247    profile_name_textfield_->set_controller(controller);
248    profile_name_textfield_->SetFontList(medium_font_list);
249    profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
250
251    profile_name_textfield_->SetVisible(false);
252    AddChildView(profile_name_textfield_);
253  }
254
255  views::Textfield* profile_name_textfield() {
256    return profile_name_textfield_;
257  }
258
259  // Hide the editable textfield to show the profile name button instead.
260  void ShowReadOnlyView() {
261    if (profile_name_textfield_)
262      profile_name_textfield_->SetVisible(false);
263  }
264
265 private:
266  // views::ButtonListener:
267  virtual void ButtonPressed(views::Button* sender,
268                            const ui::Event& event) OVERRIDE {
269    if (profile_name_textfield_) {
270      profile_name_textfield_->SetVisible(true);
271      profile_name_textfield_->SetText(GetText());
272      profile_name_textfield_->SelectAll(false);
273      profile_name_textfield_->RequestFocus();
274    }
275  }
276
277  // views::LabelButton:
278  virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
279    // Override CustomButton's implementation, which presses the button when
280    // you press space and clicks it when you release space, as the space can be
281    // part of the new profile name typed in the textfield.
282    return false;
283  }
284
285  virtual void Layout() OVERRIDE {
286    if (profile_name_textfield_)
287      profile_name_textfield_->SetBounds(0, 0, width(), height());
288    // This layout trick keeps the text left-aligned and the icon right-aligned.
289    SetHorizontalAlignment(gfx::ALIGN_RIGHT);
290    views::LabelButton::Layout();
291    label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
292  }
293
294  // Textfield that is shown when editing the profile name. Can be NULL if
295  // the profile name isn't allowed to be edited (e.g. for guest profiles).
296  views::Textfield* profile_name_textfield_;
297
298  DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
299};
300
301// A title card with one back button right aligned and one label center aligned.
302class TitleCard : public views::View {
303 public:
304   TitleCard(int message_id, views::ButtonListener* listener,
305             views::ImageButton** back_button) {
306    back_button_ = new views::ImageButton(listener);
307    back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
308                                    views::ImageButton::ALIGN_MIDDLE);
309    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
310    back_button_->SetImage(views::ImageButton::STATE_NORMAL,
311                           rb->GetImageSkiaNamed(IDR_BACK));
312    back_button_->SetImage(views::ImageButton::STATE_HOVERED,
313                           rb->GetImageSkiaNamed(IDR_BACK_H));
314    back_button_->SetImage(views::ImageButton::STATE_PRESSED,
315                           rb->GetImageSkiaNamed(IDR_BACK_P));
316    back_button_->SetImage(views::ImageButton::STATE_DISABLED,
317                           rb->GetImageSkiaNamed(IDR_BACK_D));
318    *back_button = back_button_;
319
320    title_label_ = new views::Label(l10n_util::GetStringUTF16(message_id));
321    title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
322    const gfx::FontList& medium_font_list =
323        rb->GetFontList(ui::ResourceBundle::MediumFont);
324    title_label_->SetFontList(medium_font_list);
325
326    AddChildView(back_button_);
327    AddChildView(title_label_);
328  }
329
330 private:
331  virtual void Layout() OVERRIDE{
332    back_button_->SetBounds(
333        0, 0, back_button_->GetPreferredSize().width(), height());
334    title_label_->SetBoundsRect(GetContentsBounds());
335  }
336
337  virtual gfx::Size GetPreferredSize() OVERRIDE{
338    int height = profiles::kAvatarIconPadding * 2 +
339        std::max(title_label_->GetPreferredSize().height(),
340                 back_button_->GetPreferredSize().height());
341    return gfx::Size(width(), height);
342  }
343
344  views::ImageButton* back_button_;
345  views::Label* title_label_;
346
347  DISALLOW_COPY_AND_ASSIGN(TitleCard);
348};
349
350// ProfileChooserView ---------------------------------------------------------
351
352// static
353ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
354bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
355
356// static
357void ProfileChooserView::ShowBubble(
358    BubbleViewMode view_mode,
359    views::View* anchor_view,
360    views::BubbleBorder::Arrow arrow,
361    views::BubbleBorder::BubbleAlignment border_alignment,
362    const gfx::Rect& anchor_rect,
363    Browser* browser) {
364  profile_bubble_ = new ProfileChooserView(anchor_view, arrow, anchor_rect,
365                                           browser, view_mode);
366  views::BubbleDelegateView::CreateBubble(profile_bubble_);
367  profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
368  profile_bubble_->SetAlignment(border_alignment);
369  profile_bubble_->GetWidget()->Show();
370  profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
371}
372
373// static
374bool ProfileChooserView::IsShowing() {
375  return profile_bubble_ != NULL;
376}
377
378// static
379void ProfileChooserView::Hide() {
380  if (IsShowing())
381    profile_bubble_->GetWidget()->Close();
382}
383
384ProfileChooserView::ProfileChooserView(views::View* anchor_view,
385                                       views::BubbleBorder::Arrow arrow,
386                                       const gfx::Rect& anchor_rect,
387                                       Browser* browser,
388                                       BubbleViewMode view_mode)
389    : BubbleDelegateView(anchor_view, arrow),
390      browser_(browser),
391      view_mode_(view_mode),
392      tutorial_mode_(TUTORIAL_MODE_NONE) {
393  // Reset the default margins inherited from the BubbleDelegateView.
394  set_margins(gfx::Insets());
395
396  ResetView();
397
398  set_background(views::Background::CreateSolidBackground(
399      GetNativeTheme()->GetSystemColor(
400          ui::NativeTheme::kColorId_DialogBackground)));
401
402  avatar_menu_.reset(new AvatarMenu(
403      &g_browser_process->profile_manager()->GetProfileInfoCache(),
404      this,
405      browser_));
406  avatar_menu_->RebuildMenu();
407
408  ProfileOAuth2TokenService* oauth2_token_service =
409      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
410  if (oauth2_token_service)
411    oauth2_token_service->AddObserver(this);
412}
413
414ProfileChooserView::~ProfileChooserView() {
415  ProfileOAuth2TokenService* oauth2_token_service =
416      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
417  if (oauth2_token_service)
418    oauth2_token_service->RemoveObserver(this);
419}
420
421void ProfileChooserView::ResetView() {
422  question_mark_button_ = NULL;
423  manage_accounts_link_ = NULL;
424  signin_current_profile_link_ = NULL;
425  users_button_ = NULL;
426  lock_button_ = NULL;
427  add_account_link_ = NULL;
428  current_profile_photo_ = NULL;
429  current_profile_name_ = NULL;
430  tutorial_ok_button_ = NULL;
431  tutorial_learn_more_link_ = NULL;
432  tutorial_enable_new_profile_management_button_ = NULL;
433  tutorial_end_preview_link_ = NULL;
434  tutorial_send_feedback_button_ = NULL;
435  end_preview_and_relaunch_button_ = NULL;
436  end_preview_cancel_button_ = NULL;
437  remove_account_and_relaunch_button_ = NULL;
438  account_removal_cancel_button_ = NULL;
439  gaia_signin_cancel_button_ = NULL;
440  open_other_profile_indexes_map_.clear();
441  current_profile_accounts_map_.clear();
442  tutorial_mode_ = TUTORIAL_MODE_NONE;
443}
444
445void ProfileChooserView::Init() {
446  ShowView(view_mode_, avatar_menu_.get());
447}
448
449void ProfileChooserView::OnAvatarMenuChanged(
450    AvatarMenu* avatar_menu) {
451  // Refresh the view with the new menu. We can't just update the local copy
452  // as this may have been triggered by a sign out action, in which case
453  // the view is being destroyed.
454  ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu);
455}
456
457void ProfileChooserView::OnRefreshTokenAvailable(
458    const std::string& account_id) {
459  // Refresh the account management view when a new account is added to the
460  // profile.
461  if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
462      view_mode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
463      view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) {
464    ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
465  }
466}
467
468void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
469  // Refresh the account management view when an account is removed from the
470  // profile.
471  if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
472    ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
473}
474
475void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
476                                  AvatarMenu* avatar_menu) {
477  // The account management view should only be displayed if the active profile
478  // is signed in.
479  if (view_to_display == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
480    const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
481        avatar_menu->GetActiveProfileIndex());
482    DCHECK(active_item.signed_in);
483  }
484
485  // Records the last tutorial mode.
486  TutorialMode last_tutorial_mode = tutorial_mode_;
487  ResetView();
488  RemoveAllChildViews(true);
489  view_mode_ = view_to_display;
490
491  views::GridLayout* layout;
492  views::View* sub_view;
493  switch (view_mode_) {
494    case BUBBLE_VIEW_MODE_GAIA_SIGNIN:
495    case BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
496      layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
497      sub_view = CreateGaiaSigninView(
498          view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT);
499      break;
500    case BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
501      layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
502      sub_view = CreateAccountRemovalView();
503      break;
504    case BUBBLE_VIEW_MODE_END_PREVIEW:
505      layout = CreateSingleColumnLayout(this, kFixedEndPreviewViewWidth);
506      sub_view = CreateEndPreviewView();
507      break;
508    default:
509      layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
510      sub_view = CreateProfileChooserView(avatar_menu, last_tutorial_mode);
511  }
512  layout->StartRow(1, 0);
513  layout->AddView(sub_view);
514  Layout();
515  if (GetBubbleFrameView())
516    SizeToContents();
517}
518
519void ProfileChooserView::WindowClosing() {
520  DCHECK_EQ(profile_bubble_, this);
521  profile_bubble_ = NULL;
522}
523
524void ProfileChooserView::ButtonPressed(views::Button* sender,
525                                       const ui::Event& event) {
526  // Disable button after clicking so that it doesn't get clicked twice and
527  // start a second action... which can crash Chrome.  But don't disable if it
528  // has no parent (like in tests) because that will also crash.
529  if (sender->parent())
530    sender->SetEnabled(false);
531
532  if (sender == users_button_) {
533    profiles::ShowUserManagerMaybeWithTutorial(browser_->profile());
534    // If this is a guest session, also close all the guest browser windows.
535    if (browser_->profile()->IsGuestSession())
536      profiles::CloseGuestProfileWindows();
537  } else if (sender == lock_button_) {
538    profiles::LockProfile(browser_->profile());
539  } else if (sender == tutorial_ok_button_) {
540    // If the user manually dismissed the tutorial, never show it again by
541    // setting the number of times shown to the maximum plus 1, so that later we
542    // could distinguish between the dismiss case and the case when the tutorial
543    // is indeed shown for the maximum number of times.
544    browser_->profile()->GetPrefs()->SetInteger(
545        prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1);
546    ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
547  } else if (sender == tutorial_enable_new_profile_management_button_) {
548    profiles::EnableNewProfileManagementPreview();
549  } else if (sender == remove_account_and_relaunch_button_) {
550    RemoveAccount();
551  } else if (sender == account_removal_cancel_button_) {
552    account_id_to_remove_.clear();
553    ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
554  } else if (sender == gaia_signin_cancel_button_) {
555    std::string primary_account =
556        SigninManagerFactory::GetForProfile(browser_->profile())->
557        GetAuthenticatedUsername();
558    ShowView(primary_account.empty() ? BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
559                                       BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
560             avatar_menu_.get());
561  } else if (sender == question_mark_button_) {
562    tutorial_mode_ = TUTORIAL_MODE_SEND_FEEDBACK;
563    ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
564  } else if (sender == tutorial_send_feedback_button_) {
565    chrome::OpenFeedbackDialog(browser_);
566  } else if (sender == end_preview_and_relaunch_button_) {
567    profiles::DisableNewProfileManagementPreview();
568  } else if (sender == end_preview_cancel_button_) {
569    tutorial_mode_ = TUTORIAL_MODE_SEND_FEEDBACK;
570    ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
571  } else if (current_profile_photo_ &&
572             sender == current_profile_photo_->change_photo_button()) {
573    avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
574  } else if (sender == signin_current_profile_link_) {
575    ShowView(BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
576  } else {
577    // Either one of the "other profiles", or one of the profile accounts
578    // buttons was pressed.
579    ButtonIndexes::const_iterator profile_match =
580        open_other_profile_indexes_map_.find(sender);
581    if (profile_match != open_other_profile_indexes_map_.end()) {
582      avatar_menu_->SwitchToProfile(
583          profile_match->second,
584          ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
585          ProfileMetrics::SWITCH_PROFILE_ICON);
586    } else {
587      // This was a profile accounts button.
588      AccountButtonIndexes::const_iterator account_match =
589      current_profile_accounts_map_.find(sender);
590      DCHECK(account_match != current_profile_accounts_map_.end());
591      account_id_to_remove_ = account_match->second;
592      ShowView(BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL, avatar_menu_.get());
593    }
594  }
595}
596
597void ProfileChooserView::RemoveAccount() {
598  DCHECK(!account_id_to_remove_.empty());
599  MutableProfileOAuth2TokenService* oauth2_token_service =
600      ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
601      browser_->profile());
602  if (oauth2_token_service)
603    oauth2_token_service->RevokeCredentials(account_id_to_remove_);
604  account_id_to_remove_.clear();
605
606  chrome::AttemptRestart();
607}
608
609void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
610  if (sender == manage_accounts_link_) {
611    // This link can either mean show/hide the account management view,
612    // depending on which view it is displayed. ShowView() will DCHECK if
613    // the account management view is displayed for non signed-in users.
614    ShowView(
615        view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
616            BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
617            BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
618        avatar_menu_.get());
619  } else if (sender == add_account_link_) {
620    ShowView(BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
621  } else if (sender == tutorial_learn_more_link_) {
622    // TODO(guohui): update |learn_more_url| once it is decided.
623    const GURL lear_more_url("https://support.google.com/chrome/?hl=en#to");
624    chrome::NavigateParams params(
625        browser_->profile(),
626        lear_more_url,
627        content::PAGE_TRANSITION_LINK);
628    params.disposition = NEW_FOREGROUND_TAB;
629    chrome::Navigate(&params);
630  } else {
631    DCHECK(sender == tutorial_end_preview_link_);
632    ShowView(BUBBLE_VIEW_MODE_END_PREVIEW, avatar_menu_.get());
633  }
634}
635
636void ProfileChooserView::StyledLabelLinkClicked(
637    const gfx::Range& range, int event_flags) {
638  chrome::ShowSettings(browser_);
639}
640
641bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
642                                        const ui::KeyEvent& key_event) {
643  views::Textfield* name_textfield =
644      current_profile_name_->profile_name_textfield();
645  DCHECK(sender == name_textfield);
646
647  if (key_event.key_code() == ui::VKEY_RETURN ||
648      key_event.key_code() == ui::VKEY_TAB) {
649    // Pressing Tab/Enter commits the new profile name, unless it's empty.
650    base::string16 new_profile_name = name_textfield->text();
651    if (new_profile_name.empty())
652      return true;
653
654    const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
655        avatar_menu_->GetActiveProfileIndex());
656    Profile* profile = g_browser_process->profile_manager()->GetProfile(
657        active_item.profile_path);
658    DCHECK(profile);
659
660    if (profile->IsManaged())
661      return true;
662
663    profiles::UpdateProfileName(profile, new_profile_name);
664    current_profile_name_->ShowReadOnlyView();
665    return true;
666  }
667  return false;
668}
669
670views::View* ProfileChooserView::CreateProfileChooserView(
671    AvatarMenu* avatar_menu, TutorialMode last_tutorial_mode) {
672  // TODO(guohui, noms): the view should be customized based on whether new
673  // profile management preview is enabled or not.
674
675  views::View* view = new views::View();
676  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
677  // Separate items into active and alternatives.
678  Indexes other_profiles;
679  views::View* tutorial_view = NULL;
680  views::View* current_profile_view = NULL;
681  views::View* current_profile_accounts = NULL;
682  views::View* option_buttons_view = NULL;
683  bool is_new_profile_management = switches::IsNewProfileManagement();
684  for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
685    const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
686    if (item.active) {
687      option_buttons_view = CreateOptionsView(item.signed_in);
688      current_profile_view = CreateCurrentProfileView(item, false);
689      if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
690        if (is_new_profile_management) {
691          tutorial_view = last_tutorial_mode == TUTORIAL_MODE_SEND_FEEDBACK ?
692              CreateSendPreviewFeedbackView() :
693              CreatePreviewEnabledTutorialView(
694                  item, last_tutorial_mode == TUTORIAL_MODE_PREVIEW_ENABLED);
695        } else {
696          tutorial_view = CreateNewProfileManagementPreviewView();
697        }
698      } else {
699        current_profile_accounts = CreateCurrentProfileAccountsView(item);
700      }
701    } else {
702      other_profiles.push_back(i);
703    }
704  }
705
706  if (tutorial_view) {
707    layout->StartRow(1, 0);
708    layout->AddView(tutorial_view);
709  }
710
711  if (!current_profile_view) {
712    // Guest windows don't have an active profile.
713    current_profile_view = CreateGuestProfileView();
714    option_buttons_view = CreateOptionsView(false);
715  }
716
717  layout->StartRow(1, 0);
718  layout->AddView(current_profile_view);
719
720  if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
721    layout->StartRow(1, 0);
722    if (switches::IsFastUserSwitching())
723      layout->AddView(CreateOtherProfilesView(other_profiles));
724  } else {
725    DCHECK(current_profile_accounts);
726    layout->StartRow(0, 0);
727    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
728    layout->StartRow(1, 0);
729    layout->AddView(current_profile_accounts);
730  }
731
732  layout->StartRow(0, 0);
733  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
734
735  // Option buttons. Only available with the new profile management flag.
736  if (switches::IsNewProfileManagement()) {
737    layout->StartRow(0, 0);
738    layout->AddView(option_buttons_view);
739  }
740
741  return view;
742}
743
744views::View* ProfileChooserView::CreatePreviewEnabledTutorialView(
745    const AvatarMenu::Item& current_avatar_item,
746    bool tutorial_shown) {
747  if (!switches::IsNewProfileManagementPreviewEnabled())
748    return NULL;
749
750  Profile* profile = browser_->profile();
751  const int show_count = profile->GetPrefs()->GetInteger(
752      prefs::kProfileAvatarTutorialShown);
753  // Do not show the tutorial if user has dismissed it.
754  if (show_count > kProfileAvatarTutorialShowMax)
755    return NULL;
756
757  if (!tutorial_shown) {
758    if (show_count == kProfileAvatarTutorialShowMax)
759      return NULL;
760    profile->GetPrefs()->SetInteger(
761        prefs::kProfileAvatarTutorialShown, show_count + 1);
762  }
763
764  return CreateTutorialView(
765      TUTORIAL_MODE_PREVIEW_ENABLED,
766      l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_TITLE),
767      l10n_util::GetStringUTF16(
768          IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_CONTENT_TEXT),
769      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
770      l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
771      &tutorial_learn_more_link_,
772      &tutorial_ok_button_);
773}
774
775views::View* ProfileChooserView::CreateSendPreviewFeedbackView() {
776  return CreateTutorialView(
777      TUTORIAL_MODE_SEND_FEEDBACK,
778      l10n_util::GetStringUTF16(IDS_PROFILES_FEEDBACK_TUTORIAL_TITLE),
779      l10n_util::GetStringUTF16(
780          IDS_PROFILES_FEEDBACK_TUTORIAL_CONTENT_TEXT),
781      l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW),
782      l10n_util::GetStringUTF16(IDS_PROFILES_SEND_FEEDBACK_BUTTON),
783      &tutorial_end_preview_link_,
784      &tutorial_send_feedback_button_);
785}
786
787views::View* ProfileChooserView::CreateTutorialView(
788    TutorialMode tutorial_mode,
789    const base::string16& title_text,
790    const base::string16& content_text,
791    const base::string16& link_text,
792    const base::string16& button_text,
793    views::Link** link,
794    views::LabelButton** button) {
795  tutorial_mode_ = tutorial_mode;
796
797  views::View* view = new views::View();
798  view->set_background(views::Background::CreateSolidBackground(
799      profiles::kAvatarTutorialBackgroundColor));
800  views::GridLayout* layout = CreateSingleColumnLayout(view,
801      kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
802  layout->SetInsets(views::kButtonVEdgeMarginNew,
803                    views::kButtonHEdgeMarginNew,
804                    views::kButtonVEdgeMarginNew,
805                    views::kButtonHEdgeMarginNew);
806
807  // Adds title.
808  views::Label* title_label = new views::Label(title_text);
809  title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
810  title_label->SetAutoColorReadabilityEnabled(false);
811  title_label->SetEnabledColor(SK_ColorWHITE);
812  title_label ->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
813      ui::ResourceBundle::MediumFont));
814  layout->StartRow(1, 0);
815  layout->AddView(title_label);
816
817  // Adds body content.
818  views::Label* content_label = new views::Label(content_text);
819  content_label->SetMultiLine(true);
820  content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
821  content_label->SetAutoColorReadabilityEnabled(false);
822  content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
823  layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
824  layout->AddView(content_label);
825
826  // Adds links and buttons.
827  views::View* button_row = new views::View();
828  views::GridLayout* button_layout = new views::GridLayout(button_row);
829  views::ColumnSet* button_columns = button_layout->AddColumnSet(0);
830  button_columns->AddColumn(views::GridLayout::LEADING,
831      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
832  button_columns->AddPaddingColumn(
833      1, views::kUnrelatedControlHorizontalSpacing);
834  button_columns->AddColumn(views::GridLayout::TRAILING,
835      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
836  button_row->SetLayoutManager(button_layout);
837
838  *link = CreateLink(link_text, this);
839  (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
840  (*link)->SetAutoColorReadabilityEnabled(false);
841  (*link)->SetEnabledColor(SK_ColorWHITE);
842  button_layout->StartRow(1, 0);
843  button_layout->AddView(*link);
844
845  *button = new views::LabelButton(this, button_text);
846  (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
847  (*button)->SetStyle(views::Button::STYLE_BUTTON);
848  button_layout->AddView(*button);
849
850  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
851  layout->AddView(button_row);
852
853  // Adds a padded caret image at the bottom.
854  views::View* padded_caret_view = new views::View();
855  views::GridLayout* padded_caret_layout =
856      new views::GridLayout(padded_caret_view);
857  views::ColumnSet* padded_columns = padded_caret_layout->AddColumnSet(0);
858  padded_columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
859  padded_columns->AddColumn(views::GridLayout::LEADING,
860      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
861  padded_caret_view->SetLayoutManager(padded_caret_layout);
862
863  views::ImageView* caret_image_view = new views::ImageView();
864  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
865  caret_image_view->SetImage(
866      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_CARET));
867
868  padded_caret_layout->StartRow(1, 0);
869  padded_caret_layout->AddView(caret_image_view);
870
871  views::View* view_with_caret = new views::View();
872  views::GridLayout* layout_with_caret =
873      CreateSingleColumnLayout(view_with_caret, kFixedMenuWidth);
874  layout_with_caret->StartRow(1, 0);
875  layout_with_caret->AddView(view);
876  layout_with_caret->StartRow(1, 0);
877  layout_with_caret->AddView(padded_caret_view);
878  return view_with_caret;
879}
880
881views::View* ProfileChooserView::CreateCurrentProfileView(
882    const AvatarMenu::Item& avatar_item,
883    bool is_guest) {
884  views::View* view = new views::View();
885  int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
886  views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
887  layout->SetInsets(views::kButtonVEdgeMarginNew,
888                    views::kButtonHEdgeMarginNew,
889                    views::kRelatedControlVerticalSpacing,
890                    views::kButtonHEdgeMarginNew);
891
892  // Profile icon, centered.
893  float x_offset = (column_width - kLargeImageSide) / 2;
894  current_profile_photo_ = new EditableProfilePhoto(
895      this, avatar_item.icon, !is_guest,
896      gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
897
898  if (switches::IsNewProfileManagementPreviewEnabled()) {
899    question_mark_button_ = new views::ImageButton(this);
900    question_mark_button_->SetImageAlignment(
901        views::ImageButton::ALIGN_LEFT, views::ImageButton::ALIGN_MIDDLE);
902    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
903    question_mark_button_->SetImage(views::ImageButton::STATE_NORMAL,
904                                    rb->GetImageSkiaNamed(IDR_QUESTION_MARK));
905    gfx::Size preferred_size = question_mark_button_->GetPreferredSize();
906    question_mark_button_->SetBounds(
907        0, 0, preferred_size.width(), preferred_size.height());
908    current_profile_photo_->AddChildView(question_mark_button_);
909  }
910
911  layout->StartRow(1, 0);
912  layout->AddView(current_profile_photo_);
913
914  // Profile name, centered.
915  current_profile_name_ = new EditableProfileName(
916      this, profiles::GetAvatarNameForProfile(browser_->profile()), !is_guest);
917  layout->StartRow(1, 0);
918  layout->AddView(current_profile_name_);
919
920  if (is_guest)
921    return view;
922
923  // The available links depend on the type of profile that is active.
924  layout->StartRow(1, 0);
925  if (avatar_item.signed_in) {
926    if (switches::IsNewProfileManagement()) {
927      base::string16 link_title = l10n_util::GetStringUTF16(
928          view_mode_ ==  BUBBLE_VIEW_MODE_PROFILE_CHOOSER ?
929              IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
930              IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
931      manage_accounts_link_ = CreateLink(link_title, this);
932      manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
933      layout->AddView(manage_accounts_link_);
934    } else {
935      views::Label* email_label = new views::Label(avatar_item.sync_state);
936      email_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
937      layout->AddView(email_label);
938    }
939  } else {
940    signin_current_profile_link_ = new views::BlueButton(
941      this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
942          l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
943    layout->AddView(signin_current_profile_link_);
944  }
945
946  return view;
947}
948
949views::View* ProfileChooserView::CreateGuestProfileView() {
950  gfx::Image guest_icon =
951      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
952          profiles::GetPlaceholderAvatarIconResourceID());
953  AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
954  guest_avatar_item.active = true;
955  guest_avatar_item.name = l10n_util::GetStringUTF16(
956      IDS_PROFILES_GUEST_PROFILE_NAME);
957  guest_avatar_item.signed_in = false;
958
959  return CreateCurrentProfileView(guest_avatar_item, true);
960}
961
962views::View* ProfileChooserView::CreateOtherProfilesView(
963    const Indexes& avatars_to_show) {
964  views::View* view = new views::View();
965  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
966
967  int num_avatars_to_show = avatars_to_show.size();
968  for (int i = 0; i < num_avatars_to_show; ++i) {
969    const size_t index = avatars_to_show[i];
970    const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
971    const int kSmallImageSide = 32;
972
973    gfx::Image image = profiles::GetSizedAvatarIcon(
974        item.icon, true,
975        kSmallImageSide + profiles::kAvatarIconPadding,
976        kSmallImageSide + profiles::kAvatarIconPadding);
977
978    views::LabelButton* button = new BackgroundColorHoverButton(
979        this,
980        item.name,
981        *image.ToImageSkia(),
982        *image.ToImageSkia());
983    button->set_min_size(gfx::Size(
984        0, kButtonHeight + views::kRelatedControlVerticalSpacing));
985
986    open_other_profile_indexes_map_[button] = index;
987
988    layout->StartRow(1, 0);
989    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
990    layout->StartRow(1, 0);
991    layout->AddView(button);
992  }
993
994  return view;
995}
996
997views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) {
998  views::View* view = new views::View();
999  views::GridLayout* layout;
1000
1001  // Only signed-in users have the ability to lock.
1002  if (enable_lock) {
1003    layout = new views::GridLayout(view);
1004    views::ColumnSet* columns = layout->AddColumnSet(0);
1005    int width_of_lock_button =
1006        2 * views::kUnrelatedControlLargeHorizontalSpacing + 12;
1007    int width_of_users_button = kFixedMenuWidth - width_of_lock_button;
1008    columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1009                       views::GridLayout::FIXED, width_of_users_button,
1010                       width_of_users_button);
1011    columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1012                       views::GridLayout::FIXED, width_of_lock_button,
1013                       width_of_lock_button);
1014    view->SetLayoutManager(layout);
1015  } else {
1016    layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1017  }
1018
1019  base::string16 text = browser_->profile()->IsGuestSession() ?
1020      l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1021      l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU_BUTTON,
1022          profiles::GetAvatarNameForProfile(browser_->profile()));
1023  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1024  users_button_ = new BackgroundColorHoverButton(
1025      this,
1026      text,
1027      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR),
1028      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1029  users_button_->set_min_size(gfx::Size(
1030      0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1031
1032  layout->StartRow(1, 0);
1033  layout->AddView(users_button_);
1034
1035  if (enable_lock) {
1036    lock_button_ = new BackgroundColorHoverButton(
1037        this,
1038        base::string16(),
1039        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK),
1040        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1041    lock_button_->set_min_size(gfx::Size(
1042      0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1043    layout->AddView(lock_button_);
1044  }
1045  return view;
1046}
1047
1048views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1049    const AvatarMenu::Item& avatar_item) {
1050  DCHECK(avatar_item.signed_in);
1051  views::View* view = new views::View();
1052  view->set_background(views::Background::CreateSolidBackground(
1053      profiles::kAvatarBubbleAccountsBackgroundColor));
1054  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1055
1056  Profile* profile = browser_->profile();
1057  std::string primary_account =
1058      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
1059  DCHECK(!primary_account.empty());
1060  std::vector<std::string>accounts =
1061      profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1062
1063  // The primary account should always be listed first.
1064  // TODO(rogerta): we still need to further differentiate the primary account
1065  // from the others in the UI, so more work is likely required here:
1066  // crbug.com/311124.
1067  CreateAccountButton(layout, primary_account, true, kFixedMenuWidth);
1068  for (size_t i = 0; i < accounts.size(); ++i)
1069    CreateAccountButton(layout, accounts[i], false, kFixedMenuWidth);
1070  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1071
1072  add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1073      IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1074  add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1075      0, views::kButtonVEdgeMarginNew,
1076      views::kRelatedControlVerticalSpacing, 0));
1077  layout->StartRow(1, 0);
1078  layout->AddView(add_account_link_);
1079  return view;
1080}
1081
1082void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1083                                             const std::string& account,
1084                                             bool is_primary_account,
1085                                             int width) {
1086  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1087  const gfx::ImageSkia* menu_marker =
1088      rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1089
1090  views::LabelButton* email_button = new BackgroundColorHoverButton(
1091      this,
1092      gfx::ElideEmail(base::UTF8ToUTF16(account),
1093                      rb->GetFontList(ui::ResourceBundle::BaseFont),
1094                      width - menu_marker->width()),
1095      gfx::ImageSkia(),
1096      gfx::ImageSkia());
1097  layout->StartRow(1, 0);
1098  layout->AddView(email_button);
1099
1100  // Save the original email address, as the button text could be elided.
1101  current_profile_accounts_map_[email_button] = account;
1102}
1103
1104views::View* ProfileChooserView::CreateGaiaSigninView(
1105    bool add_secondary_account) {
1106  views::View* view = new views::View();
1107  views::GridLayout* layout =
1108      CreateSingleColumnLayout(view, kFixedGaiaViewWidth);
1109
1110  // Adds title.
1111  views::View* padded_title = new views::View();
1112  int available_width = kFixedGaiaViewWidth - 2 * views::kButtonHEdgeMarginNew;
1113  views::GridLayout* padded_layout = CreateSingleColumnLayout(
1114      padded_title, available_width);
1115  padded_layout->SetInsets(views::kButtonVEdgeMarginNew,
1116                           views::kButtonHEdgeMarginNew,
1117                           views::kButtonVEdgeMarginNew,
1118                           views::kButtonHEdgeMarginNew);
1119  padded_layout->StartRow(1, 0);
1120  padded_layout->AddView(new TitleCard(
1121      add_secondary_account ? IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE :
1122                              IDS_PROFILES_GAIA_SIGNIN_TITLE,
1123      this, &gaia_signin_cancel_button_));
1124
1125  layout->StartRow(1, 0);
1126  layout->AddView(padded_title);
1127  layout->StartRow(1, 0);
1128  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1129
1130  // Adds Gaia signin webview
1131  Profile* profile = browser_->profile();
1132  views::WebView* web_view = new views::WebView(profile);
1133  signin::Source source = add_secondary_account ?
1134      signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT :
1135      signin::SOURCE_AVATAR_BUBBLE_SIGN_IN;
1136  GURL url(signin::GetPromoURL(
1137      source, false /* auto_close */, true /* is_constrained */));
1138  web_view->LoadInitialURL(url);
1139  web_view->SetPreferredSize(
1140      gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1141
1142  layout->StartRow(1, 0);
1143  layout->AddView(web_view);
1144
1145  return view;
1146}
1147
1148views::View* ProfileChooserView::CreateAccountRemovalView() {
1149  views::View* view = new views::View();
1150  views::GridLayout* layout = CreateSingleColumnLayout(
1151      view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1152  layout->SetInsets(views::kButtonVEdgeMarginNew,
1153                    views::kButtonHEdgeMarginNew,
1154                    views::kButtonVEdgeMarginNew,
1155                    views::kButtonHEdgeMarginNew);
1156
1157  // Adds title.
1158  layout->StartRow(1, 0);
1159  layout->AddView(new TitleCard(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE, this,
1160                                &account_removal_cancel_button_));
1161  layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
1162  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1163
1164  const std::string& primary_account = SigninManagerFactory::GetForProfile(
1165      browser_->profile())->GetAuthenticatedUsername();
1166  bool is_primary_account = primary_account == account_id_to_remove_;
1167
1168  // Adds main text.
1169  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1170  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1171  const gfx::FontList& small_font_list =
1172      rb->GetFontList(ui::ResourceBundle::SmallFont);
1173
1174  if (is_primary_account) {
1175    std::vector<size_t> offsets;
1176    const base::string16 settings_text =
1177        l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1178    const base::string16 primary_account_removal_text =
1179        l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1180            base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets);
1181    views::StyledLabel* primary_account_removal_label =
1182        new views::StyledLabel(primary_account_removal_text, this);
1183    primary_account_removal_label->AddStyleRange(
1184        gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1185        views::StyledLabel::RangeStyleInfo::CreateForLink());
1186    primary_account_removal_label->SetBaseFontList(small_font_list);
1187    layout->AddView(primary_account_removal_label);
1188  } else {
1189    views::Label* content_label = new views::Label(
1190        l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1191    content_label->SetMultiLine(true);
1192    content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1193    content_label->SetFontList(small_font_list);
1194    layout->AddView(content_label);
1195  }
1196
1197  // Adds button.
1198  if (!is_primary_account) {
1199    remove_account_and_relaunch_button_ = new views::BlueButton(
1200        this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1201    remove_account_and_relaunch_button_->SetHorizontalAlignment(
1202        gfx::ALIGN_CENTER);
1203    layout->StartRowWithPadding(
1204        1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1205    layout->AddView(remove_account_and_relaunch_button_);
1206  } else {
1207    layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1208  }
1209
1210  return view;
1211}
1212
1213views::View* ProfileChooserView::CreateNewProfileManagementPreviewView() {
1214  return CreateTutorialView(
1215      TUTORIAL_MODE_ENABLE_PREVIEW,
1216      l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_TITLE),
1217      l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_CONTENT_TEXT),
1218      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1219      l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_TRY_BUTTON),
1220      &tutorial_learn_more_link_,
1221      &tutorial_enable_new_profile_management_button_);
1222}
1223
1224views::View* ProfileChooserView::CreateEndPreviewView() {
1225  views::View* view = new views::View();
1226  views::GridLayout* layout = CreateSingleColumnLayout(
1227      view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1228  layout->SetInsets(views::kButtonVEdgeMarginNew,
1229                    views::kButtonHEdgeMarginNew,
1230                    views::kButtonVEdgeMarginNew,
1231                    views::kButtonHEdgeMarginNew);
1232
1233  // Adds title.
1234  layout->StartRow(1, 0);
1235  layout->AddView(new TitleCard(IDS_PROFILES_END_PREVIEW, this,
1236                                &end_preview_cancel_button_));
1237  layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
1238  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1239
1240  // Adds main text.
1241  views::Label* content_label = new views::Label(
1242      l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_TEXT));
1243  content_label->SetMultiLine(true);
1244  content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1245  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1246  const gfx::FontList& small_font_list =
1247      rb->GetFontList(ui::ResourceBundle::SmallFont);
1248  content_label->SetFontList(small_font_list);
1249  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1250  layout->AddView(content_label);
1251
1252  // Adds button.
1253  end_preview_and_relaunch_button_ = new views::BlueButton(
1254      this, l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_AND_RELAUNCH));
1255  end_preview_and_relaunch_button_->SetHorizontalAlignment(
1256      gfx::ALIGN_CENTER);
1257  layout->StartRowWithPadding(
1258      1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1259  layout->AddView(end_preview_and_relaunch_button_);
1260
1261  return view;
1262}
1263
1264