Revert "Only store leading 13 bits of password hash."
[chromium-blink-merge.git] / chrome / browser / ui / views / profiles / profile_chooser_view.cc
blob86f0e2a590bb1d60e19fe17f9ee938e53ce65e7b
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.
5 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
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 "content/public/browser/render_widget_host_view.h"
43 #include "grit/theme_resources.h"
44 #include "third_party/skia/include/core/SkColor.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h"
47 #include "ui/gfx/canvas.h"
48 #include "ui/gfx/image/image.h"
49 #include "ui/gfx/image/image_skia.h"
50 #include "ui/gfx/path.h"
51 #include "ui/gfx/skia_util.h"
52 #include "ui/gfx/text_elider.h"
53 #include "ui/native_theme/native_theme.h"
54 #include "ui/views/controls/button/blue_button.h"
55 #include "ui/views/controls/button/image_button.h"
56 #include "ui/views/controls/button/label_button.h"
57 #include "ui/views/controls/button/label_button_border.h"
58 #include "ui/views/controls/button/menu_button.h"
59 #include "ui/views/controls/label.h"
60 #include "ui/views/controls/link.h"
61 #include "ui/views/controls/separator.h"
62 #include "ui/views/controls/styled_label.h"
63 #include "ui/views/controls/textfield/textfield.h"
64 #include "ui/views/controls/webview/webview.h"
65 #include "ui/views/layout/grid_layout.h"
66 #include "ui/views/layout/layout_constants.h"
67 #include "ui/views/widget/widget.h"
69 namespace {
71 // Helpers --------------------------------------------------------------------
73 const int kFixedMenuWidth = 250;
74 const int kButtonHeight = 32;
75 const int kFixedGaiaViewHeight = 440;
76 const int kFixedGaiaViewWidth = 360;
77 const int kFixedAccountRemovalViewWidth = 280;
78 const int kFixedSwitchUserViewWidth = 320;
79 const int kLargeImageSide = 88;
81 const int kVerticalSpacing = 16;
83 // Creates a GridLayout with a single column. This ensures that all the child
84 // views added get auto-expanded to fill the full width of the bubble.
85 views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
86 views::GridLayout* layout = new views::GridLayout(view);
87 view->SetLayoutManager(layout);
89 views::ColumnSet* columns = layout->AddColumnSet(0);
90 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
91 views::GridLayout::FIXED, width, width);
92 return layout;
95 views::Link* CreateLink(const base::string16& link_text,
96 views::LinkListener* listener) {
97 views::Link* link_button = new views::Link(link_text);
98 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
99 link_button->SetUnderline(false);
100 link_button->set_listener(listener);
101 return link_button;
104 gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
105 SkBitmap bitmap;
106 bitmap.allocPixels(SkImageInfo::MakeA8(size, size));
107 bitmap.eraseARGB(0, 0, 0, 0);
108 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
111 bool HasAuthError(Profile* profile) {
112 const SigninErrorController* error =
113 profiles::GetSigninErrorController(profile);
114 return error && error->HasError();
117 std::string GetAuthErrorAccountId(Profile* profile) {
118 const SigninErrorController* error =
119 profiles::GetSigninErrorController(profile);
120 if (!error)
121 return std::string();
123 return error->error_account_id();
126 std::string GetAuthErrorUsername(Profile* profile) {
127 const SigninErrorController* error =
128 profiles::GetSigninErrorController(profile);
129 if (!error)
130 return std::string();
132 return error->error_username();
135 // BackgroundColorHoverButton -------------------------------------------------
137 // A custom button that allows for setting a background color when hovered over.
138 class BackgroundColorHoverButton : public views::LabelButton {
139 public:
140 BackgroundColorHoverButton(views::ButtonListener* listener,
141 const base::string16& text,
142 const gfx::ImageSkia& icon)
143 : views::LabelButton(listener, text) {
144 SetImageLabelSpacing(views::kItemLabelSpacing);
145 SetBorder(views::Border::CreateEmptyBorder(
146 0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew));
147 SetMinSize(gfx::Size(0,
148 kButtonHeight + views::kRelatedControlVerticalSpacing));
149 SetImage(STATE_NORMAL, icon);
150 SetFocusable(true);
153 ~BackgroundColorHoverButton() override {}
155 private:
156 // views::LabelButton:
157 void OnPaint(gfx::Canvas* canvas) override {
158 if ((state() == STATE_PRESSED) ||
159 (state() == STATE_HOVERED)) {
160 canvas->DrawColor(GetNativeTheme()->GetSystemColor(
161 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
163 LabelButton::OnPaint(canvas);
166 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
169 // SizedContainer -------------------------------------------------
171 // A simple container view that takes an explicit preferred size.
172 class SizedContainer : public views::View {
173 public:
174 explicit SizedContainer(const gfx::Size& preferred_size)
175 : preferred_size_(preferred_size) {}
177 gfx::Size GetPreferredSize() const override { return preferred_size_; }
179 private:
180 gfx::Size preferred_size_;
183 } // namespace
185 // RightAlignedIconLabelButton -------------------------------------------------
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) {
195 protected:
196 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);
203 private:
204 DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton);
207 // EditableProfilePhoto -------------------------------------------------
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);
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));
229 if (!is_editing_allowed) {
230 SetEnabled(false);
231 return;
234 set_notify_enter_exit_on_child(true);
236 // Photo overlay that appears when hovering over the button.
237 photo_overlay_ = new views::ImageView();
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));
245 photo_overlay_->SetSize(bounds.size());
246 photo_overlay_->SetVisible(false);
247 AddChildView(photo_overlay_);
250 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);
256 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);
263 private:
264 // views::CustomButton:
265 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);
272 void OnFocus() override {
273 views::LabelButton::OnFocus();
274 if (photo_overlay_)
275 photo_overlay_->SetVisible(true);
278 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);
285 gfx::Path circular_mask_;
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_;
291 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
294 // EditableProfileName -------------------------------------------------
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);
311 if (!is_editing_allowed) {
312 SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
313 return;
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));
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);
338 profile_name_textfield_->SetVisible(false);
339 AddChildView(profile_name_textfield_);
342 views::Textfield* profile_name_textfield() {
343 return profile_name_textfield_;
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);
352 private:
353 // views::ButtonListener:
354 void ButtonPressed(views::Button* sender, const ui::Event& event) override {
355 if (profile_name_textfield_) {
356 profile_name_textfield_->SetVisible(true);
357 profile_name_textfield_->SetText(GetText());
358 profile_name_textfield_->SelectAll(false);
359 profile_name_textfield_->RequestFocus();
363 // views::LabelButton:
364 bool OnKeyReleased(const ui::KeyEvent& event) override {
365 // Override CustomButton's implementation, which presses the button when
366 // you press space and clicks it when you release space, as the space can be
367 // part of the new profile name typed in the textfield.
368 return false;
371 void Layout() override {
372 if (profile_name_textfield_)
373 profile_name_textfield_->SetBounds(0, 0, width(), height());
374 RightAlignedIconLabelButton::Layout();
377 void OnFocus() override {
378 RightAlignedIconLabelButton::OnFocus();
379 SetState(STATE_HOVERED);
382 void OnBlur() override {
383 RightAlignedIconLabelButton::OnBlur();
384 SetState(STATE_NORMAL);
387 // Textfield that is shown when editing the profile name. Can be NULL if
388 // the profile name isn't allowed to be edited (e.g. for guest profiles).
389 views::Textfield* profile_name_textfield_;
391 DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
394 // A title card with one back button right aligned and one label center aligned.
395 class TitleCard : public views::View {
396 public:
397 TitleCard(const base::string16& message, views::ButtonListener* listener,
398 views::ImageButton** back_button) {
399 back_button_ = new views::ImageButton(listener);
400 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
401 views::ImageButton::ALIGN_MIDDLE);
402 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
403 back_button_->SetImage(views::ImageButton::STATE_NORMAL,
404 rb->GetImageSkiaNamed(IDR_BACK));
405 back_button_->SetImage(views::ImageButton::STATE_HOVERED,
406 rb->GetImageSkiaNamed(IDR_BACK_H));
407 back_button_->SetImage(views::ImageButton::STATE_PRESSED,
408 rb->GetImageSkiaNamed(IDR_BACK_P));
409 back_button_->SetImage(views::ImageButton::STATE_DISABLED,
410 rb->GetImageSkiaNamed(IDR_BACK_D));
411 back_button_->SetFocusable(true);
412 *back_button = back_button_;
414 title_label_ = new views::Label(message);
415 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
416 const gfx::FontList& medium_font_list =
417 rb->GetFontList(ui::ResourceBundle::MediumFont);
418 title_label_->SetFontList(medium_font_list);
420 AddChildView(back_button_);
421 AddChildView(title_label_);
424 // Creates a new view that has the |title_card| with horizontal padding at the
425 // top, an edge-to-edge separator below, and the specified |view| at the
426 // bottom.
427 static views::View* AddPaddedTitleCard(views::View* view,
428 TitleCard* title_card,
429 int width) {
430 views::View* titled_view = new views::View();
431 views::GridLayout* layout = new views::GridLayout(titled_view);
432 titled_view->SetLayoutManager(layout);
434 // Column set 0 is a single column layout with horizontal padding at left
435 // and right, and column set 1 is a single column layout with no padding.
436 views::ColumnSet* columns = layout->AddColumnSet(0);
437 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
438 int available_width = width - 2 * views::kButtonHEdgeMarginNew;
439 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
440 views::GridLayout::FIXED, available_width, available_width);
441 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
442 layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
443 views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
445 layout->StartRowWithPadding(1, 0, 0, kVerticalSpacing);
446 layout->AddView(title_card);
447 layout->StartRowWithPadding(1, 1, 0, kVerticalSpacing);
448 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
450 layout->StartRow(1, 1);
451 layout->AddView(view);
453 return titled_view;
456 private:
457 void Layout() override {
458 int back_button_width = back_button_->GetPreferredSize().width();
459 back_button_->SetBounds(0, 0, back_button_width, height());
460 int label_padding = back_button_width + views::kButtonHEdgeMarginNew;
461 int label_width = width() - 2 * label_padding;
462 DCHECK_GT(label_width, 0);
463 title_label_->SetBounds(label_padding, 0, label_width, height());
466 gfx::Size GetPreferredSize() const override {
467 int height = std::max(title_label_->GetPreferredSize().height(),
468 back_button_->GetPreferredSize().height());
469 return gfx::Size(width(), height);
472 views::ImageButton* back_button_;
473 views::Label* title_label_;
475 DISALLOW_COPY_AND_ASSIGN(TitleCard);
478 // ProfileChooserView ---------------------------------------------------------
480 // static
481 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
482 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
484 // static
485 void ProfileChooserView::ShowBubble(
486 profiles::BubbleViewMode view_mode,
487 profiles::TutorialMode tutorial_mode,
488 const signin::ManageAccountsParams& manage_accounts_params,
489 views::View* anchor_view,
490 views::BubbleBorder::Arrow arrow,
491 views::BubbleBorder::BubbleAlignment border_alignment,
492 Browser* browser) {
493 if (IsShowing()) {
494 if (tutorial_mode != profiles::TUTORIAL_MODE_NONE) {
495 profile_bubble_->tutorial_mode_ = tutorial_mode;
496 profile_bubble_->ShowView(view_mode, profile_bubble_->avatar_menu_.get());
498 return;
501 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, browser,
502 view_mode, tutorial_mode, manage_accounts_params.service_type);
503 views::BubbleDelegateView::CreateBubble(profile_bubble_);
504 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
505 profile_bubble_->SetAlignment(border_alignment);
506 profile_bubble_->GetWidget()->Show();
507 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
510 // static
511 bool ProfileChooserView::IsShowing() {
512 return profile_bubble_ != NULL;
515 // static
516 void ProfileChooserView::Hide() {
517 if (IsShowing())
518 profile_bubble_->GetWidget()->Close();
521 ProfileChooserView::ProfileChooserView(views::View* anchor_view,
522 views::BubbleBorder::Arrow arrow,
523 Browser* browser,
524 profiles::BubbleViewMode view_mode,
525 profiles::TutorialMode tutorial_mode,
526 signin::GAIAServiceType service_type)
527 : BubbleDelegateView(anchor_view, arrow),
528 browser_(browser),
529 view_mode_(view_mode),
530 tutorial_mode_(tutorial_mode),
531 gaia_service_type_(service_type) {
532 // Reset the default margins inherited from the BubbleDelegateView.
533 // Add a small bottom inset so that the bubble's rounded corners show up.
534 set_margins(gfx::Insets(0, 0, 1, 0));
535 set_background(views::Background::CreateSolidBackground(
536 GetNativeTheme()->GetSystemColor(
537 ui::NativeTheme::kColorId_DialogBackground)));
538 ResetView();
540 avatar_menu_.reset(new AvatarMenu(
541 &g_browser_process->profile_manager()->GetProfileInfoCache(),
542 this,
543 browser_));
544 avatar_menu_->RebuildMenu();
546 ProfileOAuth2TokenService* oauth2_token_service =
547 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
548 if (oauth2_token_service)
549 oauth2_token_service->AddObserver(this);
552 ProfileChooserView::~ProfileChooserView() {
553 ProfileOAuth2TokenService* oauth2_token_service =
554 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
555 if (oauth2_token_service)
556 oauth2_token_service->RemoveObserver(this);
559 void ProfileChooserView::ResetView() {
560 open_other_profile_indexes_map_.clear();
561 delete_account_button_map_.clear();
562 reauth_account_button_map_.clear();
563 manage_accounts_link_ = NULL;
564 signin_current_profile_link_ = NULL;
565 auth_error_email_button_ = NULL;
566 current_profile_photo_ = NULL;
567 current_profile_name_ = NULL;
568 users_button_ = NULL;
569 go_incognito_button_ = NULL;
570 lock_button_ = NULL;
571 add_account_link_ = NULL;
572 gaia_signin_cancel_button_ = NULL;
573 remove_account_button_ = NULL;
574 account_removal_cancel_button_ = NULL;
575 add_person_button_ = NULL;
576 disconnect_button_ = NULL;
577 switch_user_cancel_button_ = NULL;
578 tutorial_sync_settings_ok_button_ = NULL;
579 tutorial_close_button_ = NULL;
580 tutorial_sync_settings_link_ = NULL;
581 tutorial_see_whats_new_button_ = NULL;
582 tutorial_not_you_link_ = NULL;
583 tutorial_learn_more_link_ = NULL;
586 void ProfileChooserView::Init() {
587 // If view mode is PROFILE_CHOOSER but there is an auth error, force
588 // ACCOUNT_MANAGEMENT mode.
589 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER &&
590 HasAuthError(browser_->profile()) &&
591 switches::IsEnableAccountConsistency() &&
592 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex()).
593 signed_in) {
594 view_mode_ = profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
597 // The arrow keys can be used to tab between items.
598 AddAccelerator(ui::Accelerator(ui::VKEY_DOWN, ui::EF_NONE));
599 AddAccelerator(ui::Accelerator(ui::VKEY_UP, ui::EF_NONE));
601 ShowView(view_mode_, avatar_menu_.get());
604 void ProfileChooserView::OnAvatarMenuChanged(
605 AvatarMenu* avatar_menu) {
606 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ||
607 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
608 // Refresh the view with the new menu. We can't just update the local copy
609 // as this may have been triggered by a sign out action, in which case
610 // the view is being destroyed.
611 ShowView(view_mode_, avatar_menu);
615 void ProfileChooserView::OnRefreshTokenAvailable(
616 const std::string& account_id) {
617 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
618 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
619 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
620 // The account management UI is only available through the
621 // --enable-account-consistency flag.
622 ShowView(switches::IsEnableAccountConsistency() ?
623 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
624 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
628 void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
629 // Refresh the account management view when an account is removed from the
630 // profile.
631 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
632 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
635 void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display,
636 AvatarMenu* avatar_menu) {
637 // The account management view should only be displayed if the active profile
638 // is signed in.
639 if (view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
640 DCHECK(switches::IsEnableAccountConsistency());
641 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
642 avatar_menu->GetActiveProfileIndex());
643 DCHECK(active_item.signed_in);
646 if (browser_->profile()->IsSupervised() &&
647 (view_to_display == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
648 view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL)) {
649 LOG(WARNING) << "Supervised user attempted to add/remove account";
650 return;
653 ResetView();
654 RemoveAllChildViews(true);
655 view_mode_ = view_to_display;
657 views::GridLayout* layout;
658 views::View* sub_view;
659 switch (view_mode_) {
660 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
661 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
662 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH:
663 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
664 sub_view = CreateGaiaSigninView();
665 break;
666 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
667 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
668 sub_view = CreateAccountRemovalView();
669 break;
670 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER:
671 layout = CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth);
672 sub_view = CreateSwitchUserView();
673 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
674 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW);
675 break;
676 default:
677 layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
678 sub_view = CreateProfileChooserView(avatar_menu);
680 // Clears tutorial mode for all non-profile-chooser views.
681 if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER)
682 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
684 layout->StartRow(1, 0);
685 layout->AddView(sub_view);
686 Layout();
687 if (GetBubbleFrameView())
688 SizeToContents();
691 void ProfileChooserView::WindowClosing() {
692 DCHECK_EQ(profile_bubble_, this);
693 profile_bubble_ = NULL;
695 if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) {
696 LoginUIServiceFactory::GetForProfile(browser_->profile())->
697 SyncConfirmationUIClosed(false /* configure_sync_first */);
701 bool ProfileChooserView::AcceleratorPressed(
702 const ui::Accelerator& accelerator) {
703 if (accelerator.key_code() != ui::VKEY_DOWN &&
704 accelerator.key_code() != ui::VKEY_UP)
705 return BubbleDelegateView::AcceleratorPressed(accelerator);
706 // Move the focus up or down.
707 GetFocusManager()->AdvanceFocus(accelerator.key_code() != ui::VKEY_DOWN);
708 return true;
711 bool ProfileChooserView::HandleContextMenu(
712 const content::ContextMenuParams& params) {
713 // Suppresses the context menu because some features, such as inspecting
714 // elements, are not appropriate in a bubble.
715 return true;
718 void ProfileChooserView::ButtonPressed(views::Button* sender,
719 const ui::Event& event) {
720 if (sender == users_button_) {
721 // If this is a guest session, close all the guest browser windows.
722 if (browser_->profile()->IsGuestSession()) {
723 profiles::CloseGuestProfileWindows();
724 } else {
725 UserManager::Show(base::FilePath(),
726 profiles::USER_MANAGER_NO_TUTORIAL,
727 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
729 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER);
730 } else if (sender == go_incognito_button_) {
731 DCHECK(ShouldShowGoIncognito());
732 chrome::NewIncognitoWindow(browser_);
733 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_GO_INCOGNITO);
734 } else if (sender == lock_button_) {
735 profiles::LockProfile(browser_->profile());
736 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK);
737 } else if (sender == auth_error_email_button_) {
738 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
739 } else if (sender == tutorial_sync_settings_ok_button_) {
740 LoginUIServiceFactory::GetForProfile(browser_->profile())->
741 SyncConfirmationUIClosed(false /* configure_sync_first */);
742 DismissTutorial();
743 ProfileMetrics::LogProfileNewAvatarMenuSignin(
744 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK);
745 } else if (sender == tutorial_close_button_) {
746 DCHECK(tutorial_mode_ != profiles::TUTORIAL_MODE_NONE &&
747 tutorial_mode_ != profiles::TUTORIAL_MODE_CONFIRM_SIGNIN);
748 DismissTutorial();
749 } else if (sender == tutorial_see_whats_new_button_) {
750 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
751 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW);
752 UserManager::Show(base::FilePath(),
753 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
754 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
755 } else if (sender == remove_account_button_) {
756 RemoveAccount();
757 } else if (sender == account_removal_cancel_button_) {
758 account_id_to_remove_.clear();
759 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
760 } else if (sender == gaia_signin_cancel_button_) {
761 // The account management view is only available with the
762 // --enable-account-consistency flag.
763 bool account_management_available =
764 SigninManagerFactory::GetForProfile(browser_->profile())->
765 IsAuthenticated() &&
766 switches::IsEnableAccountConsistency();
767 ShowView(account_management_available ?
768 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
769 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
770 } else if (sender == current_profile_photo_) {
771 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
772 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE);
773 } else if (sender == signin_current_profile_link_) {
774 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
775 } else if (sender == add_person_button_) {
776 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
777 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON);
778 UserManager::Show(base::FilePath(),
779 profiles::USER_MANAGER_NO_TUTORIAL,
780 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
781 } else if (sender == disconnect_button_) {
782 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
783 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT);
784 chrome::ShowSettings(browser_);
785 } else if (sender == switch_user_cancel_button_) {
786 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
787 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
788 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK);
789 } else {
790 // Either one of the "other profiles", or one of the profile accounts
791 // buttons was pressed.
792 ButtonIndexes::const_iterator profile_match =
793 open_other_profile_indexes_map_.find(sender);
794 if (profile_match != open_other_profile_indexes_map_.end()) {
795 avatar_menu_->SwitchToProfile(
796 profile_match->second,
797 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
798 ProfileMetrics::SWITCH_PROFILE_ICON);
799 } else {
800 // This was a profile accounts button.
801 AccountButtonIndexes::const_iterator account_match =
802 delete_account_button_map_.find(sender);
803 if (account_match != delete_account_button_map_.end()) {
804 account_id_to_remove_ = account_match->second;
805 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL,
806 avatar_menu_.get());
807 } else {
808 account_match = reauth_account_button_map_.find(sender);
809 DCHECK(account_match != reauth_account_button_map_.end());
810 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
816 void ProfileChooserView::RemoveAccount() {
817 DCHECK(!account_id_to_remove_.empty());
818 MutableProfileOAuth2TokenService* oauth2_token_service =
819 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
820 browser_->profile());
821 if (oauth2_token_service) {
822 oauth2_token_service->RevokeCredentials(account_id_to_remove_);
823 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT);
825 account_id_to_remove_.clear();
827 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
830 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
831 if (sender == manage_accounts_link_) {
832 // This link can either mean show/hide the account management view,
833 // depending on which view it is displayed. ShowView() will DCHECK if
834 // the account management view is displayed for non signed-in users.
835 ShowView(
836 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
837 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
838 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
839 avatar_menu_.get());
840 } else if (sender == add_account_link_) {
841 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
842 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT);
843 } else if (sender == tutorial_sync_settings_link_) {
844 LoginUIServiceFactory::GetForProfile(browser_->profile())->
845 SyncConfirmationUIClosed(true /* configure_sync_first */);
846 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
847 ProfileMetrics::LogProfileNewAvatarMenuSignin(
848 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS);
849 } else if (sender == tutorial_not_you_link_) {
850 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
851 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU);
852 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER, avatar_menu_.get());
853 } else {
854 DCHECK(sender == tutorial_learn_more_link_);
855 signin_ui_util::ShowSigninErrorLearnMorePage(browser_->profile());
859 void ProfileChooserView::StyledLabelLinkClicked(
860 const gfx::Range& range, int event_flags) {
861 chrome::ShowSettings(browser_);
864 bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
865 const ui::KeyEvent& key_event) {
866 views::Textfield* name_textfield =
867 current_profile_name_->profile_name_textfield();
868 DCHECK(sender == name_textfield);
870 if (key_event.key_code() == ui::VKEY_RETURN ||
871 key_event.key_code() == ui::VKEY_TAB) {
872 // Pressing Tab/Enter commits the new profile name, unless it's empty.
873 base::string16 new_profile_name = name_textfield->text();
874 base::TrimWhitespace(new_profile_name, base::TRIM_ALL, &new_profile_name);
875 if (new_profile_name.empty())
876 return true;
878 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
879 avatar_menu_->GetActiveProfileIndex());
880 Profile* profile = g_browser_process->profile_manager()->GetProfile(
881 active_item.profile_path);
882 DCHECK(profile);
884 if (profile->IsLegacySupervised())
885 return true;
887 profiles::UpdateProfileName(profile, new_profile_name);
888 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
889 current_profile_name_->ShowReadOnlyView();
890 return true;
892 return false;
895 views::View* ProfileChooserView::CreateProfileChooserView(
896 AvatarMenu* avatar_menu) {
897 views::View* view = new views::View();
898 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
899 // Separate items into active and alternatives.
900 Indexes other_profiles;
901 views::View* tutorial_view = NULL;
902 views::View* current_profile_view = NULL;
903 views::View* current_profile_accounts = NULL;
904 views::View* option_buttons_view = NULL;
905 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
906 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
907 if (item.active) {
908 option_buttons_view = CreateOptionsView(
909 item.signed_in && profiles::IsLockAvailable(browser_->profile()));
910 current_profile_view = CreateCurrentProfileView(item, false);
911 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
912 switch (tutorial_mode_) {
913 case profiles::TUTORIAL_MODE_NONE:
914 case profiles::TUTORIAL_MODE_WELCOME_UPGRADE:
915 tutorial_view = CreateWelcomeUpgradeTutorialViewIfNeeded(
916 tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE,
917 item);
918 break;
919 case profiles::TUTORIAL_MODE_CONFIRM_SIGNIN:
920 tutorial_view = CreateSigninConfirmationView();
921 break;
922 case profiles::TUTORIAL_MODE_SHOW_ERROR:
923 tutorial_view = CreateSigninErrorView();
924 break;
926 } else {
927 current_profile_accounts = CreateCurrentProfileAccountsView(item);
929 } else {
930 other_profiles.push_back(i);
934 if (tutorial_view) {
935 // TODO(mlerman): update UMA stats for the new tutorial.
936 layout->StartRow(1, 0);
937 layout->AddView(tutorial_view);
938 } else {
939 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
942 if (!current_profile_view) {
943 // Guest windows don't have an active profile.
944 current_profile_view = CreateGuestProfileView();
945 option_buttons_view = CreateOptionsView(false);
948 layout->StartRow(1, 0);
949 layout->AddView(current_profile_view);
951 if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
952 DCHECK(current_profile_accounts);
953 layout->StartRow(0, 0);
954 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
955 layout->StartRow(1, 0);
956 layout->AddView(current_profile_accounts);
959 if (browser_->profile()->IsSupervised()) {
960 layout->StartRow(0, 0);
961 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
962 layout->StartRow(1, 0);
963 layout->AddView(CreateSupervisedUserDisclaimerView());
966 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
967 layout->StartRow(1, 0);
968 if (switches::IsFastUserSwitching())
969 layout->AddView(CreateOtherProfilesView(other_profiles));
972 layout->StartRow(0, 0);
973 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
975 if (option_buttons_view) {
976 layout->StartRow(0, 0);
977 layout->AddView(option_buttons_view);
980 return view;
983 void ProfileChooserView::DismissTutorial() {
984 // Never shows the upgrade tutorial again if manually closed.
985 if (tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) {
986 browser_->profile()->GetPrefs()->SetInteger(
987 prefs::kProfileAvatarTutorialShown,
988 signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1);
991 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
992 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
995 views::View* ProfileChooserView::CreateTutorialView(
996 profiles::TutorialMode tutorial_mode,
997 const base::string16& title_text,
998 const base::string16& content_text,
999 const base::string16& link_text,
1000 const base::string16& button_text,
1001 bool stack_button,
1002 views::Link** link,
1003 views::LabelButton** button,
1004 views::ImageButton** close_button) {
1005 tutorial_mode_ = tutorial_mode;
1007 views::View* view = new views::View();
1008 view->set_background(views::Background::CreateSolidBackground(
1009 profiles::kAvatarTutorialBackgroundColor));
1010 views::GridLayout* layout = CreateSingleColumnLayout(view,
1011 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1012 // Creates a second column set for buttons and links.
1013 views::ColumnSet* button_columns = layout->AddColumnSet(1);
1014 button_columns->AddColumn(views::GridLayout::LEADING,
1015 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1016 button_columns->AddPaddingColumn(
1017 1, views::kUnrelatedControlHorizontalSpacing);
1018 button_columns->AddColumn(views::GridLayout::TRAILING,
1019 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1020 layout->SetInsets(views::kButtonVEdgeMarginNew,
1021 views::kButtonHEdgeMarginNew,
1022 views::kButtonVEdgeMarginNew,
1023 views::kButtonHEdgeMarginNew);
1025 // Adds title and close button if needed.
1026 views::Label* title_label = new views::Label(title_text);
1027 title_label->SetMultiLine(true);
1028 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1029 title_label->SetAutoColorReadabilityEnabled(false);
1030 title_label->SetEnabledColor(SK_ColorWHITE);
1031 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1032 ui::ResourceBundle::MediumFont));
1034 if (close_button) {
1035 layout->StartRow(1, 1);
1036 layout->AddView(title_label);
1037 *close_button = new views::ImageButton(this);
1038 (*close_button)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1039 views::ImageButton::ALIGN_MIDDLE);
1040 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1041 (*close_button)->SetImage(views::ImageButton::STATE_NORMAL,
1042 rb->GetImageSkiaNamed(IDR_CLOSE_1));
1043 (*close_button)->SetImage(views::ImageButton::STATE_HOVERED,
1044 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1045 (*close_button)->SetImage(views::ImageButton::STATE_PRESSED,
1046 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1047 layout->AddView(*close_button);
1048 } else {
1049 layout->StartRow(1, 0);
1050 layout->AddView(title_label);
1053 // Adds body content.
1054 views::Label* content_label = new views::Label(content_text);
1055 content_label->SetMultiLine(true);
1056 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1057 content_label->SetAutoColorReadabilityEnabled(false);
1058 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
1059 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
1060 layout->AddView(content_label);
1062 // Adds links and buttons.
1063 bool has_button = !button_text.empty();
1064 if (has_button) {
1065 *button = new views::LabelButton(this, button_text);
1066 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1067 (*button)->SetStyle(views::Button::STYLE_BUTTON);
1070 bool has_link = !link_text.empty();
1071 if (has_link) {
1072 *link = CreateLink(link_text, this);
1073 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1074 (*link)->SetAutoColorReadabilityEnabled(false);
1075 (*link)->SetEnabledColor(SK_ColorWHITE);
1078 if (stack_button) {
1079 DCHECK(has_button);
1080 layout->StartRowWithPadding(
1081 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1082 layout->AddView(*button);
1083 if (has_link) {
1084 layout->StartRowWithPadding(
1085 1, 0, 0, views::kRelatedControlVerticalSpacing);
1086 (*link)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1087 layout->AddView(*link);
1089 } else {
1090 DCHECK(has_link || has_button);
1091 layout->StartRowWithPadding(
1092 1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1093 if (has_link)
1094 layout->AddView(*link);
1095 else
1096 layout->SkipColumns(1);
1097 if (has_button)
1098 layout->AddView(*button);
1099 else
1100 layout->SkipColumns(1);
1103 return view;
1106 views::View* ProfileChooserView::CreateCurrentProfileView(
1107 const AvatarMenu::Item& avatar_item,
1108 bool is_guest) {
1109 views::View* view = new views::View();
1110 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
1111 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
1112 layout->SetInsets(views::kButtonVEdgeMarginNew,
1113 views::kButtonHEdgeMarginNew,
1114 views::kUnrelatedControlVerticalSpacing,
1115 views::kButtonHEdgeMarginNew);
1117 // Profile icon, centered.
1118 int x_offset = (column_width - kLargeImageSide) / 2;
1119 current_profile_photo_ = new EditableProfilePhoto(
1120 this, avatar_item.icon, !is_guest,
1121 gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
1122 SizedContainer* profile_icon_container =
1123 new SizedContainer(gfx::Size(column_width, kLargeImageSide));
1124 profile_icon_container->AddChildView(current_profile_photo_);
1126 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1127 if (browser_->profile()->IsSupervised()) {
1128 views::ImageView* supervised_icon = new views::ImageView();
1129 int image_id = browser_->profile()->IsChild()
1130 ? IDR_ICON_PROFILES_MENU_CHILD
1131 : IDR_ICON_PROFILES_MENU_SUPERVISED;
1132 supervised_icon->SetImage(rb->GetImageSkiaNamed(image_id));
1133 gfx::Size preferred_size = supervised_icon->GetPreferredSize();
1134 gfx::Rect parent_bounds = current_profile_photo_->bounds();
1135 supervised_icon->SetBounds(
1136 parent_bounds.right() - preferred_size.width(),
1137 parent_bounds.bottom() - preferred_size.height(),
1138 preferred_size.width(),
1139 preferred_size.height());
1140 profile_icon_container->AddChildView(supervised_icon);
1143 layout->StartRow(1, 0);
1144 layout->AddView(profile_icon_container);
1146 // Profile name, centered.
1147 bool editing_allowed = !is_guest &&
1148 !browser_->profile()->IsLegacySupervised();
1149 current_profile_name_ = new EditableProfileName(
1150 this,
1151 profiles::GetAvatarNameForProfile(browser_->profile()->GetPath()),
1152 editing_allowed);
1153 layout->StartRowWithPadding(1, 0, 0,
1154 views::kRelatedControlSmallVerticalSpacing);
1155 layout->StartRow(1, 0);
1156 layout->AddView(current_profile_name_);
1158 if (is_guest)
1159 return view;
1161 // The available links depend on the type of profile that is active.
1162 if (avatar_item.signed_in) {
1163 layout->StartRow(1, 0);
1164 if (switches::IsEnableAccountConsistency()) {
1165 base::string16 link_title = l10n_util::GetStringUTF16(
1166 view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ?
1167 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
1168 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
1169 manage_accounts_link_ = CreateLink(link_title, this);
1170 manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1171 layout->AddView(manage_accounts_link_);
1172 } else {
1173 // Badge the email address if there's an authentication error.
1174 if (HasAuthError(browser_->profile())) {
1175 const gfx::ImageSkia warning_image = *rb->GetImageNamed(
1176 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia();
1177 auth_error_email_button_ =
1178 new RightAlignedIconLabelButton(this, avatar_item.sync_state);
1179 auth_error_email_button_->SetElideBehavior(gfx::ELIDE_EMAIL);
1180 auth_error_email_button_->SetImage(
1181 views::LabelButton::STATE_NORMAL, warning_image);
1182 auth_error_email_button_->SetTextColor(
1183 views::LabelButton::STATE_NORMAL,
1184 views::Link::GetDefaultEnabledColor());
1185 auth_error_email_button_->SetFocusable(true);
1186 gfx::Insets insets = views::LabelButtonBorder::GetDefaultInsetsForStyle(
1187 views::Button::STYLE_TEXTBUTTON);
1188 auth_error_email_button_->SetBorder(views::Border::CreateEmptyBorder(
1189 insets.top(), insets.left(), insets.bottom(), insets.right()));
1190 layout->AddView(auth_error_email_button_);
1191 } else {
1192 // Add a small padding between the email button and the profile name.
1193 layout->StartRowWithPadding(1, 0, 0, 2);
1194 views::Label* email_label = new views::Label(avatar_item.sync_state);
1195 email_label->SetElideBehavior(gfx::ELIDE_EMAIL);
1196 email_label->SetEnabled(false);
1197 layout->AddView(email_label);
1200 } else {
1201 SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(
1202 browser_->profile()->GetOriginalProfile());
1203 if (signin_manager->IsSigninAllowed()) {
1204 views::Label* promo = new views::Label(
1205 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO));
1206 promo->SetMultiLine(true);
1207 promo->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1208 layout->StartRowWithPadding(1, 0, 0,
1209 views::kRelatedControlSmallVerticalSpacing);
1210 layout->StartRow(1, 0);
1211 layout->AddView(promo);
1213 signin_current_profile_link_ = new views::BlueButton(
1214 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
1215 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
1216 layout->StartRowWithPadding(1, 0, 0,
1217 views::kRelatedControlVerticalSpacing);
1218 layout->StartRow(1, 0);
1219 layout->AddView(signin_current_profile_link_);
1223 return view;
1226 views::View* ProfileChooserView::CreateGuestProfileView() {
1227 gfx::Image guest_icon =
1228 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1229 profiles::GetPlaceholderAvatarIconResourceID());
1230 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
1231 guest_avatar_item.active = true;
1232 guest_avatar_item.name = l10n_util::GetStringUTF16(
1233 IDS_PROFILES_GUEST_PROFILE_NAME);
1234 guest_avatar_item.signed_in = false;
1236 return CreateCurrentProfileView(guest_avatar_item, true);
1239 views::View* ProfileChooserView::CreateOtherProfilesView(
1240 const Indexes& avatars_to_show) {
1241 views::View* view = new views::View();
1242 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1244 int num_avatars_to_show = avatars_to_show.size();
1245 for (int i = 0; i < num_avatars_to_show; ++i) {
1246 const size_t index = avatars_to_show[i];
1247 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
1248 const int kSmallImageSide = 32;
1250 gfx::Image image = profiles::GetSizedAvatarIcon(
1251 item.icon, true, kSmallImageSide, kSmallImageSide);
1253 views::LabelButton* button = new BackgroundColorHoverButton(
1254 this,
1255 item.name,
1256 *image.ToImageSkia());
1257 open_other_profile_indexes_map_[button] = index;
1259 layout->StartRow(1, 0);
1260 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1261 layout->StartRow(1, 0);
1262 layout->AddView(button);
1265 return view;
1268 views::View* ProfileChooserView::CreateOptionsView(bool display_lock) {
1269 views::View* view = new views::View();
1270 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1272 base::string16 text = browser_->profile()->IsGuestSession() ?
1273 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1274 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON);
1275 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1276 users_button_ = new BackgroundColorHoverButton(
1277 this,
1278 text,
1279 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1280 layout->StartRow(1, 0);
1281 layout->AddView(users_button_);
1283 if (ShouldShowGoIncognito()) {
1284 layout->StartRow(1, 0);
1285 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1287 go_incognito_button_ = new BackgroundColorHoverButton(
1288 this,
1289 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON),
1290 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO));
1291 layout->StartRow(1, 0);
1292 layout->AddView(go_incognito_button_);
1295 if (display_lock) {
1296 layout->StartRow(1, 0);
1297 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1299 lock_button_ = new BackgroundColorHoverButton(
1300 this,
1301 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON),
1302 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1303 layout->StartRow(1, 0);
1304 layout->AddView(lock_button_);
1306 return view;
1309 views::View* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1310 views::View* view = new views::View();
1311 views::GridLayout* layout = CreateSingleColumnLayout(
1312 view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1313 layout->SetInsets(views::kRelatedControlVerticalSpacing,
1314 views::kButtonHEdgeMarginNew,
1315 views::kRelatedControlVerticalSpacing,
1316 views::kButtonHEdgeMarginNew);
1317 views::Label* disclaimer = new views::Label(
1318 avatar_menu_->GetSupervisedUserInformation());
1319 disclaimer->SetMultiLine(true);
1320 disclaimer->SetAllowCharacterBreak(true);
1321 disclaimer->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1322 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1323 disclaimer->SetFontList(rb->GetFontList(ui::ResourceBundle::SmallFont));
1324 layout->StartRow(1, 0);
1325 layout->AddView(disclaimer);
1327 return view;
1330 views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1331 const AvatarMenu::Item& avatar_item) {
1332 DCHECK(avatar_item.signed_in);
1333 views::View* view = new views::View();
1334 view->set_background(views::Background::CreateSolidBackground(
1335 profiles::kAvatarBubbleAccountsBackgroundColor));
1336 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1338 Profile* profile = browser_->profile();
1339 std::string primary_account =
1340 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
1341 DCHECK(!primary_account.empty());
1342 std::vector<std::string>accounts =
1343 profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1345 // Get state of authentication error, if any.
1346 std::string error_account_id = GetAuthErrorAccountId(profile);
1348 // The primary account should always be listed first.
1349 // TODO(rogerta): we still need to further differentiate the primary account
1350 // from the others in the UI, so more work is likely required here:
1351 // crbug.com/311124.
1352 CreateAccountButton(layout, primary_account, true,
1353 error_account_id == primary_account, kFixedMenuWidth);
1354 for (size_t i = 0; i < accounts.size(); ++i)
1355 CreateAccountButton(layout, accounts[i], false,
1356 error_account_id == accounts[i], kFixedMenuWidth);
1358 if (!profile->IsSupervised()) {
1359 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1361 add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1362 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1363 add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1364 0, views::kButtonVEdgeMarginNew,
1365 views::kRelatedControlVerticalSpacing, 0));
1366 layout->StartRow(1, 0);
1367 layout->AddView(add_account_link_);
1370 return view;
1373 void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1374 const std::string& account_id,
1375 bool is_primary_account,
1376 bool reauth_required,
1377 int width) {
1378 std::string email = signin_ui_util::GetDisplayEmail(browser_->profile(),
1379 account_id);
1380 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1381 const gfx::ImageSkia* delete_default_image =
1382 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1383 const int kDeleteButtonWidth = delete_default_image->width();
1384 const gfx::ImageSkia warning_default_image = reauth_required ?
1385 *rb->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia() :
1386 gfx::ImageSkia();
1387 const int kWarningButtonWidth = reauth_required ?
1388 warning_default_image.width() + views::kRelatedButtonHSpacing : 0;
1389 int available_width = width - 2 * views::kButtonHEdgeMarginNew
1390 - kDeleteButtonWidth - kWarningButtonWidth;
1391 views::LabelButton* email_button = new BackgroundColorHoverButton(
1392 reauth_required ? this : NULL,
1393 base::UTF8ToUTF16(email),
1394 warning_default_image);
1395 email_button->SetElideBehavior(gfx::ELIDE_EMAIL);
1396 email_button->SetMinSize(gfx::Size(0, kButtonHeight));
1397 email_button->SetMaxSize(gfx::Size(available_width, kButtonHeight));
1398 layout->StartRow(1, 0);
1399 layout->AddView(email_button);
1401 if (reauth_required)
1402 reauth_account_button_map_[email_button] = account_id;
1404 // Delete button.
1405 if (!browser_->profile()->IsSupervised()) {
1406 views::ImageButton* delete_button = new views::ImageButton(this);
1407 delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1408 views::ImageButton::ALIGN_MIDDLE);
1409 delete_button->SetImage(views::ImageButton::STATE_NORMAL,
1410 delete_default_image);
1411 delete_button->SetImage(views::ImageButton::STATE_HOVERED,
1412 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1413 delete_button->SetImage(views::ImageButton::STATE_PRESSED,
1414 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1415 delete_button->SetBounds(
1416 width - views::kButtonHEdgeMarginNew - kDeleteButtonWidth,
1417 0, kDeleteButtonWidth, kButtonHeight);
1419 email_button->set_notify_enter_exit_on_child(true);
1420 email_button->AddChildView(delete_button);
1422 // Save the original email address, as the button text could be elided.
1423 delete_account_button_map_[delete_button] = account_id;
1427 views::View* ProfileChooserView::CreateGaiaSigninView() {
1428 GURL url;
1429 int message_id;
1431 switch (view_mode_) {
1432 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
1433 url = signin::GetPromoURL(signin_metrics::SOURCE_AVATAR_BUBBLE_SIGN_IN,
1434 false /* auto_close */,
1435 true /* is_constrained */);
1436 message_id = IDS_PROFILES_GAIA_SIGNIN_TITLE;
1437 break;
1438 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
1439 url = signin::GetPromoURL(
1440 signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT,
1441 false /* auto_close */,
1442 true /* is_constrained */);
1443 message_id = IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE;
1444 break;
1445 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: {
1446 DCHECK(HasAuthError(browser_->profile()));
1447 url = signin::GetReauthURL(browser_->profile(),
1448 GetAuthErrorUsername(browser_->profile()));
1449 message_id = IDS_PROFILES_GAIA_REAUTH_TITLE;
1450 break;
1452 default:
1453 NOTREACHED() << "Called with invalid mode=" << view_mode_;
1454 return NULL;
1457 // Adds Gaia signin webview
1458 Profile* profile = browser_->profile();
1459 views::WebView* web_view = new views::WebView(profile);
1460 web_view->LoadInitialURL(url);
1461 web_view->GetWebContents()->SetDelegate(this);
1462 web_view->SetPreferredSize(
1463 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1464 content::RenderWidgetHostView* rwhv =
1465 web_view->GetWebContents()->GetRenderWidgetHostView();
1466 if (rwhv)
1467 rwhv->SetBackgroundColor(profiles::kAvatarBubbleGaiaBackgroundColor);
1468 TitleCard* title_card = new TitleCard(l10n_util::GetStringUTF16(message_id),
1469 this,
1470 &gaia_signin_cancel_button_);
1471 return TitleCard::AddPaddedTitleCard(
1472 web_view, title_card, kFixedGaiaViewWidth);
1475 views::View* ProfileChooserView::CreateAccountRemovalView() {
1476 views::View* view = new views::View();
1477 views::GridLayout* layout = CreateSingleColumnLayout(
1478 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1479 layout->SetInsets(0,
1480 views::kButtonHEdgeMarginNew,
1481 views::kButtonVEdgeMarginNew,
1482 views::kButtonHEdgeMarginNew);
1484 const std::string& primary_account = SigninManagerFactory::GetForProfile(
1485 browser_->profile())->GetAuthenticatedAccountId();
1486 bool is_primary_account = primary_account == account_id_to_remove_;
1488 // Adds main text.
1489 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1490 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1491 const gfx::FontList& small_font_list =
1492 rb->GetFontList(ui::ResourceBundle::SmallFont);
1494 if (is_primary_account) {
1495 std::string email = signin_ui_util::GetDisplayEmail(browser_->profile(),
1496 account_id_to_remove_);
1497 std::vector<size_t> offsets;
1498 const base::string16 settings_text =
1499 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1500 const base::string16 primary_account_removal_text =
1501 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1502 base::UTF8ToUTF16(email), settings_text, &offsets);
1503 views::StyledLabel* primary_account_removal_label =
1504 new views::StyledLabel(primary_account_removal_text, this);
1505 primary_account_removal_label->AddStyleRange(
1506 gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1507 views::StyledLabel::RangeStyleInfo::CreateForLink());
1508 primary_account_removal_label->SetBaseFontList(small_font_list);
1509 layout->AddView(primary_account_removal_label);
1510 } else {
1511 views::Label* content_label = new views::Label(
1512 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1513 content_label->SetMultiLine(true);
1514 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1515 content_label->SetFontList(small_font_list);
1516 layout->AddView(content_label);
1519 // Adds button.
1520 if (!is_primary_account) {
1521 remove_account_button_ = new views::BlueButton(
1522 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1523 remove_account_button_->SetHorizontalAlignment(
1524 gfx::ALIGN_CENTER);
1525 layout->StartRowWithPadding(
1526 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1527 layout->AddView(remove_account_button_);
1528 } else {
1529 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1532 TitleCard* title_card = new TitleCard(
1533 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE),
1534 this, &account_removal_cancel_button_);
1535 return TitleCard::AddPaddedTitleCard(view, title_card,
1536 kFixedAccountRemovalViewWidth);
1539 views::View* ProfileChooserView::CreateWelcomeUpgradeTutorialViewIfNeeded(
1540 bool tutorial_shown, const AvatarMenu::Item& avatar_item) {
1541 Profile* profile = browser_->profile();
1543 const int show_count = profile->GetPrefs()->GetInteger(
1544 prefs::kProfileAvatarTutorialShown);
1545 // Do not show the tutorial if user has dismissed it.
1546 if (show_count > signin_ui_util::kUpgradeWelcomeTutorialShowMax)
1547 return NULL;
1549 if (!tutorial_shown) {
1550 if (show_count == signin_ui_util::kUpgradeWelcomeTutorialShowMax)
1551 return NULL;
1552 profile->GetPrefs()->SetInteger(
1553 prefs::kProfileAvatarTutorialShown, show_count + 1);
1555 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1556 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW);
1558 // For local profiles, the "Not you" link doesn't make sense.
1559 base::string16 link_message = avatar_item.signed_in ?
1560 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name) :
1561 base::string16();
1563 return CreateTutorialView(
1564 profiles::TUTORIAL_MODE_WELCOME_UPGRADE,
1565 l10n_util::GetStringUTF16(
1566 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE),
1567 l10n_util::GetStringUTF16(
1568 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT),
1569 link_message,
1570 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON),
1571 true /* stack_button */,
1572 &tutorial_not_you_link_,
1573 &tutorial_see_whats_new_button_,
1574 &tutorial_close_button_);
1577 views::View* ProfileChooserView::CreateSigninConfirmationView() {
1578 ProfileMetrics::LogProfileNewAvatarMenuSignin(
1579 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW);
1581 return CreateTutorialView(
1582 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN,
1583 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE),
1584 l10n_util::GetStringUTF16(
1585 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT),
1586 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK),
1587 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
1588 false /* stack_button */,
1589 &tutorial_sync_settings_link_,
1590 &tutorial_sync_settings_ok_button_,
1591 NULL /* close_button*/);
1594 views::View* ProfileChooserView::CreateSigninErrorView() {
1595 LoginUIService* login_ui_service =
1596 LoginUIServiceFactory::GetForProfile(browser_->profile());
1597 base::string16 last_login_result(login_ui_service->GetLastLoginResult());
1598 return CreateTutorialView(
1599 profiles::TUTORIAL_MODE_SHOW_ERROR,
1600 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE),
1601 last_login_result,
1602 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1603 base::string16(),
1604 false /* stack_button */,
1605 &tutorial_learn_more_link_,
1606 NULL,
1607 &tutorial_close_button_);
1610 views::View* ProfileChooserView::CreateSwitchUserView() {
1611 views::View* view = new views::View();
1612 views::GridLayout* layout = CreateSingleColumnLayout(
1613 view, kFixedSwitchUserViewWidth);
1614 views::ColumnSet* columns = layout->AddColumnSet(1);
1615 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1616 int label_width =
1617 kFixedSwitchUserViewWidth - 2 * views::kButtonHEdgeMarginNew;
1618 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1619 views::GridLayout::FIXED, label_width, label_width);
1620 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1622 // Adds main text.
1623 layout->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1624 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1625 const gfx::FontList& small_font_list =
1626 rb->GetFontList(ui::ResourceBundle::SmallFont);
1627 const AvatarMenu::Item& avatar_item =
1628 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex());
1629 views::Label* content_label = new views::Label(
1630 l10n_util::GetStringFUTF16(
1631 IDS_PROFILES_NOT_YOU_CONTENT_TEXT, avatar_item.name));
1632 content_label->SetMultiLine(true);
1633 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1634 content_label->SetFontList(small_font_list);
1635 layout->AddView(content_label);
1637 // Adds "Add person" button.
1638 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1639 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1641 add_person_button_ = new BackgroundColorHoverButton(
1642 this,
1643 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON),
1644 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1645 layout->StartRow(1, 0);
1646 layout->AddView(add_person_button_);
1648 // Adds "Disconnect your Google Account" button.
1649 layout->StartRow(1, 0);
1650 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1652 disconnect_button_ = new BackgroundColorHoverButton(
1653 this,
1654 l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON),
1655 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT));
1656 layout->StartRow(1, 0);
1657 layout->AddView(disconnect_button_);
1659 TitleCard* title_card = new TitleCard(
1660 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name),
1661 this, &switch_user_cancel_button_);
1662 return TitleCard::AddPaddedTitleCard(view, title_card,
1663 kFixedSwitchUserViewWidth);
1666 bool ProfileChooserView::ShouldShowGoIncognito() const {
1667 bool incognito_available =
1668 IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) !=
1669 IncognitoModePrefs::DISABLED;
1670 return incognito_available && !browser_->profile()->IsGuestSession();
1673 void ProfileChooserView::PostActionPerformed(
1674 ProfileMetrics::ProfileDesktopMenu action_performed) {
1675 ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_);
1676 gaia_service_type_ = signin::GAIA_SERVICE_TYPE_NONE;