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