Home | History | Annotate | Download | only in profiles
      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.
     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 
     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 
    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 
    109 bool HasAuthError(Profile* profile) {
    110   const SigninErrorController* error =
    111       profiles::GetSigninErrorController(profile);
    112   return error && error->HasError();
    113 }
    114 
    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 
    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:
    138   BackgroundColorHoverButton(views::ButtonListener* listener,
    139                              const base::string16& text,
    140                              const gfx::ImageSkia& icon)
    141       : views::LabelButton(listener, text) {
    142     SetImageLabelSpacing(views::kItemLabelSpacing);
    143     SetBorder(views::Border::CreateEmptyBorder(
    144         0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew));
    145     SetMinSize(gfx::Size(0,
    146         kButtonHeight + views::kRelatedControlVerticalSpacing));
    147     SetImage(STATE_NORMAL, icon);
    148     SetFocusable(true);
    149   }
    150 
    151   virtual ~BackgroundColorHoverButton() {}
    152 
    153  private:
    154   // views::LabelButton:
    155   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    156     if ((state() == STATE_PRESSED) ||
    157         (state() == STATE_HOVERED)) {
    158       canvas->DrawColor(GetNativeTheme()->GetSystemColor(
    159           ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
    160     }
    161     LabelButton::OnPaint(canvas);
    162   }
    163 
    164   DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
    165 };
    166 
    167 // SizedContainer -------------------------------------------------
    168 
    169 // A simple container view that takes an explicit preferred size.
    170 class SizedContainer : public views::View {
    171  public:
    172   explicit SizedContainer(const gfx::Size& preferred_size)
    173       : preferred_size_(preferred_size) {}
    174 
    175   virtual gfx::Size GetPreferredSize() const OVERRIDE {
    176     return preferred_size_;
    177   }
    178 
    179  private:
    180   gfx::Size preferred_size_;
    181 };
    182 
    183 }  // namespace
    184 
    185 // RightAlignedIconLabelButton -------------------------------------------------
    186 
    187 // A custom LabelButton that has a centered text and right aligned icon.
    188 class RightAlignedIconLabelButton : public views::LabelButton {
    189  public:
    190   RightAlignedIconLabelButton(views::ButtonListener* listener,
    191                               const base::string16& text)
    192       : views::LabelButton(listener, text) {
    193   }
    194 
    195  protected:
    196   virtual void Layout() OVERRIDE {
    197     // This layout trick keeps the text left-aligned and the icon right-aligned.
    198     SetHorizontalAlignment(gfx::ALIGN_RIGHT);
    199     views::LabelButton::Layout();
    200     label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
    201   }
    202 
    203  private:
    204   DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton);
    205 };
    206 
    207 // EditableProfilePhoto -------------------------------------------------
    208 
    209 // A custom Image control that shows a "change" button when moused over.
    210 class EditableProfilePhoto : public views::LabelButton {
    211  public:
    212   EditableProfilePhoto(views::ButtonListener* listener,
    213                        const gfx::Image& icon,
    214                        bool is_editing_allowed,
    215                        const gfx::Rect& bounds)
    216       : views::LabelButton(listener, base::string16()),
    217         photo_overlay_(NULL) {
    218     gfx::Image image = profiles::GetSizedAvatarIcon(
    219         icon, true, kLargeImageSide, kLargeImageSide);
    220     SetImage(views::LabelButton::STATE_NORMAL, *image.ToImageSkia());
    221     SetBorder(views::Border::NullBorder());
    222     SetBoundsRect(bounds);
    223 
    224     // Calculate the circular mask that will be used to display the photo.
    225     circular_mask_.addCircle(SkIntToScalar(bounds.width() / 2),
    226                              SkIntToScalar(bounds.height() / 2),
    227                              SkIntToScalar(bounds.width() / 2));
    228 
    229     if (!is_editing_allowed) {
    230       SetEnabled(false);
    231       return;
    232     }
    233 
    234     set_notify_enter_exit_on_child(true);
    235 
    236     // Photo overlay that appears when hovering over the button.
    237     photo_overlay_ = new views::ImageView();
    238 
    239     const SkColor kBackgroundColor = SkColorSetARGB(65, 255, 255, 255);
    240     photo_overlay_->set_background(
    241         views::Background::CreateSolidBackground(kBackgroundColor));
    242     photo_overlay_->SetImage(*ui::ResourceBundle::GetSharedInstance().
    243         GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_CAMERA));
    244 
    245     photo_overlay_->SetSize(bounds.size());
    246     photo_overlay_->SetVisible(false);
    247     AddChildView(photo_overlay_);
    248   }
    249 
    250   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    251     // Display the profile picture as a circle.
    252     canvas->ClipPath(circular_mask_, true);
    253     views::LabelButton::OnPaint(canvas);
    254   }
    255 
    256   virtual void PaintChildren(gfx::Canvas* canvas,
    257                              const views::CullSet& cull_set) OVERRIDE {
    258     // Display any children (the "change photo" overlay) as a circle.
    259     canvas->ClipPath(circular_mask_, true);
    260     View::PaintChildren(canvas, cull_set);
    261   }
    262 
    263  private:
    264   // views::CustomButton:
    265   virtual void StateChanged() OVERRIDE {
    266     bool show_overlay =
    267         (state() == STATE_PRESSED || state() == STATE_HOVERED || HasFocus());
    268     if (photo_overlay_)
    269       photo_overlay_->SetVisible(show_overlay);
    270   }
    271 
    272   virtual void OnFocus() OVERRIDE {
    273     views::LabelButton::OnFocus();
    274     if (photo_overlay_)
    275       photo_overlay_->SetVisible(true);
    276   }
    277 
    278   virtual void OnBlur() OVERRIDE {
    279     views::LabelButton::OnBlur();
    280     // Don't hide the overlay if it's being shown as a result of a mouseover.
    281     if (photo_overlay_ && state() != STATE_HOVERED)
    282       photo_overlay_->SetVisible(false);
    283   }
    284 
    285   gfx::Path circular_mask_;
    286 
    287   // Image that is shown when hovering over the image button. Can be NULL if
    288   // the photo isn't allowed to be edited (e.g. for guest profiles).
    289   views::ImageView* photo_overlay_;
    290 
    291   DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
    292 };
    293 
    294 // EditableProfileName -------------------------------------------------
    295 
    296 // A custom text control that turns into a textfield for editing when clicked.
    297 class EditableProfileName : public RightAlignedIconLabelButton,
    298                             public views::ButtonListener {
    299  public:
    300   EditableProfileName(views::TextfieldController* controller,
    301                       const base::string16& text,
    302                       bool is_editing_allowed)
    303       : RightAlignedIconLabelButton(this, text),
    304         profile_name_textfield_(NULL) {
    305     ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
    306     const gfx::FontList& medium_font_list =
    307         rb->GetFontList(ui::ResourceBundle::MediumFont);
    308     SetFontList(medium_font_list);
    309     SetHorizontalAlignment(gfx::ALIGN_CENTER);
    310 
    311     if (!is_editing_allowed) {
    312       SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
    313       return;
    314     }
    315 
    316     // Show an "edit" pencil icon when hovering over. In the default state,
    317     // we need to create an empty placeholder of the correct size, so that
    318     // the text doesn't jump around when the hovered icon appears.
    319     gfx::ImageSkia hover_image =
    320         *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
    321     SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
    322     SetImage(STATE_HOVERED, hover_image);
    323     SetImage(STATE_PRESSED,
    324              *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
    325     // To center the text, we need to offest it by the width of the icon we
    326     // are adding and its padding. We need to also add a small top/bottom
    327     // padding to account for the textfield's border.
    328     const int kIconTextLabelButtonSpacing = 5;
    329     SetBorder(views::Border::CreateEmptyBorder(
    330         2, hover_image.width() + kIconTextLabelButtonSpacing, 2, 0));
    331 
    332     // Textfield that overlaps the button.
    333     profile_name_textfield_ = new views::Textfield();
    334     profile_name_textfield_->set_controller(controller);
    335     profile_name_textfield_->SetFontList(medium_font_list);
    336     profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
    337 
    338     profile_name_textfield_->SetVisible(false);
    339     AddChildView(profile_name_textfield_);
    340   }
    341 
    342   views::Textfield* profile_name_textfield() {
    343     return profile_name_textfield_;
    344   }
    345 
    346   // Hide the editable textfield to show the profile name button instead.
    347   void ShowReadOnlyView() {
    348     if (profile_name_textfield_)
    349       profile_name_textfield_->SetVisible(false);
    350   }
    351 
    352  private:
    353   // views::ButtonListener:
    354   virtual void ButtonPressed(views::Button* sender,
    355                             const ui::Event& event) OVERRIDE {
    356     if (profile_name_textfield_) {
    357       profile_name_textfield_->SetVisible(true);
    358       profile_name_textfield_->SetText(GetText());
    359       profile_name_textfield_->SelectAll(false);
    360       profile_name_textfield_->RequestFocus();
    361     }
    362   }
    363 
    364   // views::LabelButton:
    365   virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
    366     // Override CustomButton's implementation, which presses the button when
    367     // you press space and clicks it when you release space, as the space can be
    368     // part of the new profile name typed in the textfield.
    369     return false;
    370   }
    371 
    372   virtual void Layout() OVERRIDE {
    373     if (profile_name_textfield_)
    374       profile_name_textfield_->SetBounds(0, 0, width(), height());
    375     RightAlignedIconLabelButton::Layout();
    376   }
    377 
    378   virtual void OnFocus() OVERRIDE {
    379     RightAlignedIconLabelButton::OnFocus();
    380     SetState(STATE_HOVERED);
    381   }
    382 
    383   virtual void OnBlur() OVERRIDE {
    384     RightAlignedIconLabelButton::OnBlur();
    385     SetState(STATE_NORMAL);
    386   }
    387 
    388   // Textfield that is shown when editing the profile name. Can be NULL if
    389   // the profile name isn't allowed to be edited (e.g. for guest profiles).
    390   views::Textfield* profile_name_textfield_;
    391 
    392   DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
    393 };
    394 
    395 // A title card with one back button right aligned and one label center aligned.
    396 class TitleCard : public views::View {
    397  public:
    398   TitleCard(const base::string16& message, views::ButtonListener* listener,
    399             views::ImageButton** back_button) {
    400     back_button_ = new views::ImageButton(listener);
    401     back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
    402                                     views::ImageButton::ALIGN_MIDDLE);
    403     ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
    404     back_button_->SetImage(views::ImageButton::STATE_NORMAL,
    405                            rb->GetImageSkiaNamed(IDR_BACK));
    406     back_button_->SetImage(views::ImageButton::STATE_HOVERED,
    407                            rb->GetImageSkiaNamed(IDR_BACK_H));
    408     back_button_->SetImage(views::ImageButton::STATE_PRESSED,
    409                            rb->GetImageSkiaNamed(IDR_BACK_P));
    410     back_button_->SetImage(views::ImageButton::STATE_DISABLED,
    411                            rb->GetImageSkiaNamed(IDR_BACK_D));
    412     back_button_->SetFocusable(true);
    413     *back_button = back_button_;
    414 
    415     title_label_ = new views::Label(message);
    416     title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
    417     const gfx::FontList& medium_font_list =
    418         rb->GetFontList(ui::ResourceBundle::MediumFont);
    419     title_label_->SetFontList(medium_font_list);
    420 
    421     AddChildView(back_button_);
    422     AddChildView(title_label_);
    423   }
    424 
    425   // Creates a new view that has the |title_card| with horizontal padding at the
    426   // top, an edge-to-edge separator below, and the specified |view| at the
    427   // bottom.
    428   static views::View* AddPaddedTitleCard(views::View* view,
    429                                          TitleCard* title_card,
    430                                          int width) {
    431     views::View* titled_view = new views::View();
    432     views::GridLayout* layout = new views::GridLayout(titled_view);
    433     titled_view->SetLayoutManager(layout);
    434 
    435     // Column set 0 is a single column layout with horizontal padding at left
    436     // and right, and column set 1 is a single column layout with no padding.
    437     views::ColumnSet* columns = layout->AddColumnSet(0);
    438     columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
    439     int available_width = width - 2 * views::kButtonHEdgeMarginNew;
    440     columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
    441         views::GridLayout::FIXED, available_width, available_width);
    442     columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
    443     layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
    444         views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
    445 
    446     layout->StartRowWithPadding(1, 0, 0, kVerticalSpacing);
    447     layout->AddView(title_card);
    448     layout->StartRowWithPadding(1, 1, 0, kVerticalSpacing);
    449     layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
    450 
    451     layout->StartRow(1, 1);
    452     layout->AddView(view);
    453 
    454     return titled_view;
    455   }
    456 
    457  private:
    458   virtual void Layout() OVERRIDE {
    459     int back_button_width = back_button_->GetPreferredSize().width();
    460     back_button_->SetBounds(0, 0, back_button_width, height());
    461     int label_padding = back_button_width + views::kButtonHEdgeMarginNew;
    462     int label_width = width() - 2 * label_padding;
    463     DCHECK_GT(label_width, 0);
    464     title_label_->SetBounds(label_padding, 0, label_width, height());
    465   }
    466 
    467   virtual gfx::Size GetPreferredSize() const OVERRIDE {
    468     int height = std::max(title_label_->GetPreferredSize().height(),
    469         back_button_->GetPreferredSize().height());
    470     return gfx::Size(width(), height);
    471   }
    472 
    473   views::ImageButton* back_button_;
    474   views::Label* title_label_;
    475 
    476   DISALLOW_COPY_AND_ASSIGN(TitleCard);
    477 };
    478 
    479 // ProfileChooserView ---------------------------------------------------------
    480 
    481 // static
    482 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
    483 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
    484 
    485 // static
    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
    512 bool ProfileChooserView::IsShowing() {
    513   return profile_bubble_ != NULL;
    514 }
    515 
    516 // static
    517 void ProfileChooserView::Hide() {
    518   if (IsShowing())
    519     profile_bubble_->GetWidget()->Close();
    520 }
    521 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    852 void ProfileChooserView::StyledLabelLinkClicked(
    853     const gfx::Range& range, int event_flags) {
    854   chrome::ShowSettings(browser_);
    855 }
    856 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1648 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 
   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