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