MacViews: Use Mac's "Constrained Window Button" style for Button::STYLE_BUTTON LabelB...
[chromium-blink-merge.git] / chrome / browser / ui / views / profiles / profile_chooser_view.cc
blob1949a23511b23508479c2b9198b3b230307147a7
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/chrome_signin_helper.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/signin/signin_error_controller_factory.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/profile_oauth2_token_service.h"
38 #include "components/signin/core/browser/signin_error_controller.h"
39 #include "components/signin/core/browser/signin_header_helper.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/compositor/clip_transform_recorder.h"
48 #include "ui/gfx/canvas.h"
49 #include "ui/gfx/image/image.h"
50 #include "ui/gfx/image/image_skia.h"
51 #include "ui/gfx/paint_vector_icon.h"
52 #include "ui/gfx/path.h"
53 #include "ui/gfx/skia_util.h"
54 #include "ui/gfx/text_elider.h"
55 #include "ui/gfx/vector_icons_public2.h"
56 #include "ui/native_theme/native_theme.h"
57 #include "ui/views/controls/button/blue_button.h"
58 #include "ui/views/controls/button/image_button.h"
59 #include "ui/views/controls/button/label_button.h"
60 #include "ui/views/controls/button/label_button_border.h"
61 #include "ui/views/controls/button/menu_button.h"
62 #include "ui/views/controls/label.h"
63 #include "ui/views/controls/link.h"
64 #include "ui/views/controls/separator.h"
65 #include "ui/views/controls/styled_label.h"
66 #include "ui/views/controls/textfield/textfield.h"
67 #include "ui/views/controls/webview/webview.h"
68 #include "ui/views/layout/grid_layout.h"
69 #include "ui/views/layout/layout_constants.h"
70 #include "ui/views/widget/widget.h"
72 namespace {
74 // Helpers --------------------------------------------------------------------
76 const int kFixedMenuWidth = 250;
77 const int kButtonHeight = 32;
78 const int kFixedGaiaViewHeight = 440;
79 const int kFixedGaiaViewWidth = 360;
80 const int kFixedAccountRemovalViewWidth = 280;
81 const int kFixedSwitchUserViewWidth = 320;
82 const int kLargeImageSide = 88;
84 const int kVerticalSpacing = 16;
86 bool IsProfileChooser(profiles::BubbleViewMode mode) {
87 return mode == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ||
88 mode == profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER;
91 // Creates a GridLayout with a single column. This ensures that all the child
92 // views added get auto-expanded to fill the full width of the bubble.
93 views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
94 views::GridLayout* layout = new views::GridLayout(view);
95 view->SetLayoutManager(layout);
97 views::ColumnSet* columns = layout->AddColumnSet(0);
98 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
99 views::GridLayout::FIXED, width, width);
100 return layout;
103 views::Link* CreateLink(const base::string16& link_text,
104 views::LinkListener* listener) {
105 views::Link* link_button = new views::Link(link_text);
106 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
107 link_button->SetUnderline(false);
108 link_button->set_listener(listener);
109 return link_button;
112 gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
113 SkBitmap bitmap;
114 bitmap.allocPixels(SkImageInfo::MakeA8(size, size));
115 bitmap.eraseARGB(0, 0, 0, 0);
116 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
119 bool HasAuthError(Profile* profile) {
120 const SigninErrorController* error =
121 SigninErrorControllerFactory::GetForProfile(profile);
122 return error && error->HasError();
125 std::string GetAuthErrorAccountId(Profile* profile) {
126 const SigninErrorController* error =
127 SigninErrorControllerFactory::GetForProfile(profile);
128 if (!error)
129 return std::string();
131 return error->error_account_id();
134 // BackgroundColorHoverButton -------------------------------------------------
136 // A custom button that allows for setting a background color when hovered over.
137 class BackgroundColorHoverButton : public views::LabelButton {
138 public:
139 BackgroundColorHoverButton(views::ButtonListener* listener,
140 const base::string16& text,
141 const gfx::ImageSkia& icon)
142 : views::LabelButton(listener, text) {
143 SetImageLabelSpacing(views::kItemLabelSpacing);
144 SetBorder(views::Border::CreateEmptyBorder(
145 0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew));
146 SetMinSize(gfx::Size(0,
147 kButtonHeight + views::kRelatedControlVerticalSpacing));
148 SetImage(STATE_NORMAL, icon);
149 SetFocusable(true);
152 ~BackgroundColorHoverButton() override {}
154 private:
155 // views::LabelButton:
156 void OnPaint(gfx::Canvas* canvas) override {
157 if ((state() == STATE_PRESSED) ||
158 (state() == STATE_HOVERED)) {
159 canvas->DrawColor(GetNativeTheme()->GetSystemColor(
160 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
162 LabelButton::OnPaint(canvas);
165 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
168 // SizedContainer -------------------------------------------------
170 // A simple container view that takes an explicit preferred size.
171 class SizedContainer : public views::View {
172 public:
173 explicit SizedContainer(const gfx::Size& preferred_size)
174 : preferred_size_(preferred_size) {}
176 gfx::Size GetPreferredSize() const override { return preferred_size_; }
178 private:
179 gfx::Size preferred_size_;
182 } // namespace
184 // RightAlignedIconLabelButton -------------------------------------------------
186 // A custom LabelButton that has a centered text and right aligned icon.
187 class RightAlignedIconLabelButton : public views::LabelButton {
188 public:
189 RightAlignedIconLabelButton(views::ButtonListener* listener,
190 const base::string16& text)
191 : views::LabelButton(listener, text) {
194 protected:
195 void Layout() override {
196 // This layout trick keeps the text left-aligned and the icon right-aligned.
197 SetHorizontalAlignment(gfx::ALIGN_RIGHT);
198 views::LabelButton::Layout();
199 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
202 private:
203 DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton);
206 // EditableProfilePhoto -------------------------------------------------
208 // A custom Image control that shows a "change" button when moused over.
209 class EditableProfilePhoto : public views::LabelButton {
210 public:
211 EditableProfilePhoto(views::ButtonListener* listener,
212 const gfx::Image& icon,
213 bool is_editing_allowed,
214 const gfx::Rect& bounds)
215 : views::LabelButton(listener, base::string16()),
216 photo_overlay_(NULL) {
217 gfx::Image image = profiles::GetSizedAvatarIcon(
218 icon, true, kLargeImageSide, kLargeImageSide);
219 SetImage(views::LabelButton::STATE_NORMAL, *image.ToImageSkia());
220 SetBorder(views::Border::NullBorder());
221 SetBoundsRect(bounds);
223 // Calculate the circular mask that will be used to display the photo.
224 circular_mask_.addCircle(SkIntToScalar(bounds.width() / 2),
225 SkIntToScalar(bounds.height() / 2),
226 SkIntToScalar(bounds.width() / 2));
228 if (!is_editing_allowed) {
229 SetEnabled(false);
230 return;
233 set_notify_enter_exit_on_child(true);
235 // Photo overlay that appears when hovering over the button.
236 photo_overlay_ = new views::ImageView();
238 const SkColor kBackgroundColor = SkColorSetARGB(65, 255, 255, 255);
239 photo_overlay_->set_background(
240 views::Background::CreateSolidBackground(kBackgroundColor));
241 photo_overlay_->SetImage(gfx::CreateVectorIcon(
242 gfx::VectorIconId::PHOTO_CAMERA, 48u, SkColorSetRGB(0x33, 0x33, 0x33)));
244 photo_overlay_->SetSize(bounds.size());
245 photo_overlay_->SetVisible(false);
246 AddChildView(photo_overlay_);
249 void OnPaint(gfx::Canvas* canvas) override {
250 // Display the profile picture as a circle.
251 canvas->ClipPath(circular_mask_, true);
252 views::LabelButton::OnPaint(canvas);
255 void PaintChildren(const ui::PaintContext& context) override {
256 // Display any children (the "change photo" overlay) as a circle.
257 ui::ClipTransformRecorder clip_transform_recorder(context);
258 clip_transform_recorder.ClipPathWithAntiAliasing(circular_mask_);
259 View::PaintChildren(context);
262 private:
263 // views::CustomButton:
264 void StateChanged() override {
265 bool show_overlay =
266 (state() == STATE_PRESSED || state() == STATE_HOVERED || HasFocus());
267 if (photo_overlay_)
268 photo_overlay_->SetVisible(show_overlay);
271 void OnFocus() override {
272 views::LabelButton::OnFocus();
273 if (photo_overlay_)
274 photo_overlay_->SetVisible(true);
277 void OnBlur() override {
278 views::LabelButton::OnBlur();
279 // Don't hide the overlay if it's being shown as a result of a mouseover.
280 if (photo_overlay_ && state() != STATE_HOVERED)
281 photo_overlay_->SetVisible(false);
284 gfx::Path circular_mask_;
286 // Image that is shown when hovering over the image button. Can be NULL if
287 // the photo isn't allowed to be edited (e.g. for guest profiles).
288 views::ImageView* photo_overlay_;
290 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
293 // EditableProfileName -------------------------------------------------
295 // A custom text control that turns into a textfield for editing when clicked.
296 class EditableProfileName : public RightAlignedIconLabelButton,
297 public views::ButtonListener {
298 public:
299 EditableProfileName(views::TextfieldController* controller,
300 const base::string16& text,
301 bool is_editing_allowed)
302 : RightAlignedIconLabelButton(this, text),
303 profile_name_textfield_(NULL) {
304 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
305 const gfx::FontList& medium_font_list =
306 rb->GetFontList(ui::ResourceBundle::MediumFont);
307 SetFontList(medium_font_list);
308 SetHorizontalAlignment(gfx::ALIGN_CENTER);
310 if (!is_editing_allowed) {
311 SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
312 return;
315 // Show an "edit" pencil icon when hovering over. In the default state,
316 // we need to create an empty placeholder of the correct size, so that
317 // the text doesn't jump around when the hovered icon appears.
318 gfx::ImageSkia hover_image =
319 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
320 SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
321 SetImage(STATE_HOVERED, hover_image);
322 SetImage(STATE_PRESSED,
323 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
324 // To center the text, we need to offest it by the width of the icon we
325 // are adding and its padding. We need to also add a small top/bottom
326 // padding to account for the textfield's border.
327 const int kIconTextLabelButtonSpacing = 5;
328 SetBorder(views::Border::CreateEmptyBorder(
329 2, hover_image.width() + kIconTextLabelButtonSpacing, 2, 0));
331 // Textfield that overlaps the button.
332 profile_name_textfield_ = new views::Textfield();
333 profile_name_textfield_->set_controller(controller);
334 profile_name_textfield_->SetFontList(medium_font_list);
335 profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
337 profile_name_textfield_->SetVisible(false);
338 AddChildView(profile_name_textfield_);
341 views::Textfield* profile_name_textfield() {
342 return profile_name_textfield_;
345 // Hide the editable textfield to show the profile name button instead.
346 void ShowReadOnlyView() {
347 if (profile_name_textfield_)
348 profile_name_textfield_->SetVisible(false);
351 private:
352 // views::ButtonListener:
353 void ButtonPressed(views::Button* sender, const ui::Event& event) override {
354 if (profile_name_textfield_) {
355 profile_name_textfield_->SetVisible(true);
356 profile_name_textfield_->SetText(GetText());
357 profile_name_textfield_->SelectAll(false);
358 profile_name_textfield_->RequestFocus();
362 // views::LabelButton:
363 bool OnKeyReleased(const ui::KeyEvent& event) override {
364 // Override CustomButton's implementation, which presses the button when
365 // you press space and clicks it when you release space, as the space can be
366 // part of the new profile name typed in the textfield.
367 return false;
370 void Layout() override {
371 if (profile_name_textfield_)
372 profile_name_textfield_->SetBounds(0, 0, width(), height());
373 RightAlignedIconLabelButton::Layout();
376 void OnFocus() override {
377 RightAlignedIconLabelButton::OnFocus();
378 SetState(STATE_HOVERED);
381 void OnBlur() override {
382 RightAlignedIconLabelButton::OnBlur();
383 SetState(STATE_NORMAL);
386 // Textfield that is shown when editing the profile name. Can be NULL if
387 // the profile name isn't allowed to be edited (e.g. for guest profiles).
388 views::Textfield* profile_name_textfield_;
390 DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
393 // A title card with one back button right aligned and one label center aligned.
394 class TitleCard : public views::View {
395 public:
396 TitleCard(const base::string16& message, views::ButtonListener* listener,
397 views::ImageButton** back_button) {
398 back_button_ = new views::ImageButton(listener);
399 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
400 views::ImageButton::ALIGN_MIDDLE);
401 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
402 back_button_->SetImage(views::ImageButton::STATE_NORMAL,
403 rb->GetImageSkiaNamed(IDR_BACK));
404 back_button_->SetImage(views::ImageButton::STATE_HOVERED,
405 rb->GetImageSkiaNamed(IDR_BACK_H));
406 back_button_->SetImage(views::ImageButton::STATE_PRESSED,
407 rb->GetImageSkiaNamed(IDR_BACK_P));
408 back_button_->SetImage(views::ImageButton::STATE_DISABLED,
409 rb->GetImageSkiaNamed(IDR_BACK_D));
410 back_button_->SetFocusable(true);
411 *back_button = back_button_;
413 title_label_ = new views::Label(message);
414 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
415 const gfx::FontList& medium_font_list =
416 rb->GetFontList(ui::ResourceBundle::MediumFont);
417 title_label_->SetFontList(medium_font_list);
419 AddChildView(back_button_);
420 AddChildView(title_label_);
423 // Creates a new view that has the |title_card| with horizontal padding at the
424 // top, an edge-to-edge separator below, and the specified |view| at the
425 // bottom.
426 static views::View* AddPaddedTitleCard(views::View* view,
427 TitleCard* title_card,
428 int width) {
429 views::View* titled_view = new views::View();
430 views::GridLayout* layout = new views::GridLayout(titled_view);
431 titled_view->SetLayoutManager(layout);
433 // Column set 0 is a single column layout with horizontal padding at left
434 // and right, and column set 1 is a single column layout with no padding.
435 views::ColumnSet* columns = layout->AddColumnSet(0);
436 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
437 int available_width = width - 2 * views::kButtonHEdgeMarginNew;
438 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
439 views::GridLayout::FIXED, available_width, available_width);
440 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
441 layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
442 views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
444 layout->StartRowWithPadding(1, 0, 0, kVerticalSpacing);
445 layout->AddView(title_card);
446 layout->StartRowWithPadding(1, 1, 0, kVerticalSpacing);
447 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
449 layout->StartRow(1, 1);
450 layout->AddView(view);
452 return titled_view;
455 private:
456 void Layout() override {
457 int back_button_width = back_button_->GetPreferredSize().width();
458 back_button_->SetBounds(0, 0, back_button_width, height());
459 int label_padding = back_button_width + views::kButtonHEdgeMarginNew;
460 int label_width = width() - 2 * label_padding;
461 DCHECK_GT(label_width, 0);
462 title_label_->SetBounds(label_padding, 0, label_width, height());
465 gfx::Size GetPreferredSize() const override {
466 int height = std::max(title_label_->GetPreferredSize().height(),
467 back_button_->GetPreferredSize().height());
468 return gfx::Size(width(), height);
471 views::ImageButton* back_button_;
472 views::Label* title_label_;
474 DISALLOW_COPY_AND_ASSIGN(TitleCard);
477 // ProfileChooserView ---------------------------------------------------------
479 // static
480 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
481 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
483 // static
484 void ProfileChooserView::ShowBubble(
485 profiles::BubbleViewMode view_mode,
486 profiles::TutorialMode tutorial_mode,
487 const signin::ManageAccountsParams& manage_accounts_params,
488 views::View* anchor_view,
489 views::BubbleBorder::Arrow arrow,
490 views::BubbleBorder::BubbleAlignment border_alignment,
491 Browser* browser) {
492 // Don't start creating the view if it would be an empty fast user switcher.
493 // It has to happen here to prevent the view system from creating an empty
494 // container.
495 if (view_mode == profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER &&
496 !profiles::HasProfileSwitchTargets(browser->profile())) {
497 return;
500 if (IsShowing()) {
501 if (tutorial_mode != profiles::TUTORIAL_MODE_NONE) {
502 profile_bubble_->tutorial_mode_ = tutorial_mode;
503 profile_bubble_->ShowView(view_mode, profile_bubble_->avatar_menu_.get());
505 return;
508 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, browser,
509 view_mode, tutorial_mode, manage_accounts_params.service_type);
510 views::BubbleDelegateView::CreateBubble(profile_bubble_);
511 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
512 profile_bubble_->SetAlignment(border_alignment);
513 profile_bubble_->GetWidget()->Show();
514 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
517 // static
518 bool ProfileChooserView::IsShowing() {
519 return profile_bubble_ != NULL;
522 // static
523 void ProfileChooserView::Hide() {
524 if (IsShowing())
525 profile_bubble_->GetWidget()->Close();
528 ProfileChooserView::ProfileChooserView(views::View* anchor_view,
529 views::BubbleBorder::Arrow arrow,
530 Browser* browser,
531 profiles::BubbleViewMode view_mode,
532 profiles::TutorialMode tutorial_mode,
533 signin::GAIAServiceType service_type)
534 : BubbleDelegateView(anchor_view, arrow),
535 browser_(browser),
536 view_mode_(view_mode),
537 tutorial_mode_(tutorial_mode),
538 gaia_service_type_(service_type) {
539 // Reset the default margins inherited from the BubbleDelegateView.
540 // Add a small bottom inset so that the bubble's rounded corners show up.
541 set_margins(gfx::Insets(0, 0, 1, 0));
542 set_background(views::Background::CreateSolidBackground(
543 GetNativeTheme()->GetSystemColor(
544 ui::NativeTheme::kColorId_DialogBackground)));
545 ResetView();
547 avatar_menu_.reset(new AvatarMenu(
548 &g_browser_process->profile_manager()->GetProfileInfoCache(),
549 this,
550 browser_));
551 avatar_menu_->RebuildMenu();
553 ProfileOAuth2TokenService* oauth2_token_service =
554 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
555 if (oauth2_token_service)
556 oauth2_token_service->AddObserver(this);
559 ProfileChooserView::~ProfileChooserView() {
560 ProfileOAuth2TokenService* oauth2_token_service =
561 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
562 if (oauth2_token_service)
563 oauth2_token_service->RemoveObserver(this);
566 void ProfileChooserView::ResetView() {
567 open_other_profile_indexes_map_.clear();
568 delete_account_button_map_.clear();
569 reauth_account_button_map_.clear();
570 manage_accounts_link_ = NULL;
571 signin_current_profile_link_ = NULL;
572 auth_error_email_button_ = NULL;
573 current_profile_photo_ = NULL;
574 current_profile_name_ = NULL;
575 users_button_ = NULL;
576 go_incognito_button_ = NULL;
577 lock_button_ = NULL;
578 add_account_link_ = NULL;
579 gaia_signin_cancel_button_ = NULL;
580 remove_account_button_ = NULL;
581 account_removal_cancel_button_ = NULL;
582 add_person_button_ = NULL;
583 disconnect_button_ = NULL;
584 switch_user_cancel_button_ = NULL;
585 tutorial_sync_settings_ok_button_ = NULL;
586 tutorial_close_button_ = NULL;
587 tutorial_sync_settings_link_ = NULL;
588 tutorial_see_whats_new_button_ = NULL;
589 tutorial_not_you_link_ = NULL;
590 tutorial_learn_more_link_ = NULL;
593 void ProfileChooserView::Init() {
594 // If view mode is PROFILE_CHOOSER but there is an auth error, force
595 // ACCOUNT_MANAGEMENT mode.
596 if (IsProfileChooser(view_mode_) &&
597 HasAuthError(browser_->profile()) &&
598 switches::IsEnableAccountConsistency() &&
599 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex()).
600 signed_in) {
601 view_mode_ = profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
604 // The arrow keys can be used to tab between items.
605 AddAccelerator(ui::Accelerator(ui::VKEY_DOWN, ui::EF_NONE));
606 AddAccelerator(ui::Accelerator(ui::VKEY_UP, ui::EF_NONE));
608 ShowView(view_mode_, avatar_menu_.get());
611 void ProfileChooserView::OnAvatarMenuChanged(
612 AvatarMenu* avatar_menu) {
613 if (IsProfileChooser(view_mode_) ||
614 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
615 // Refresh the view with the new menu. We can't just update the local copy
616 // as this may have been triggered by a sign out action, in which case
617 // the view is being destroyed.
618 ShowView(view_mode_, avatar_menu);
622 void ProfileChooserView::OnRefreshTokenAvailable(
623 const std::string& account_id) {
624 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
625 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
626 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
627 // The account management UI is only available through the
628 // --enable-account-consistency flag.
629 ShowView(switches::IsEnableAccountConsistency() ?
630 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
631 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
635 void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
636 // Refresh the account management view when an account is removed from the
637 // profile.
638 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
639 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
642 void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display,
643 AvatarMenu* avatar_menu) {
644 // The account management view should only be displayed if the active profile
645 // is signed in.
646 if (view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
647 DCHECK(switches::IsEnableAccountConsistency());
648 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
649 avatar_menu->GetActiveProfileIndex());
650 DCHECK(active_item.signed_in);
653 if (browser_->profile()->IsSupervised() &&
654 (view_to_display == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
655 view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL)) {
656 LOG(WARNING) << "Supervised user attempted to add/remove account";
657 return;
660 ResetView();
661 RemoveAllChildViews(true);
662 view_mode_ = view_to_display;
664 views::GridLayout* layout;
665 views::View* sub_view;
666 views::View* view_to_focus = nullptr;
667 switch (view_mode_) {
668 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
669 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
670 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH:
671 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
672 sub_view = CreateGaiaSigninView(&view_to_focus);
673 break;
674 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
675 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
676 sub_view = CreateAccountRemovalView();
677 break;
678 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER:
679 layout = CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth);
680 sub_view = CreateSwitchUserView();
681 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
682 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW);
683 break;
684 default:
685 layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
686 sub_view = CreateProfileChooserView(avatar_menu);
688 // Clears tutorial mode for all non-profile-chooser views.
689 if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER)
690 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
692 layout->StartRow(1, 0);
693 layout->AddView(sub_view);
694 Layout();
695 if (GetBubbleFrameView())
696 SizeToContents();
697 if (view_to_focus)
698 view_to_focus->RequestFocus();
701 void ProfileChooserView::WindowClosing() {
702 DCHECK_EQ(profile_bubble_, this);
703 profile_bubble_ = NULL;
705 if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) {
706 LoginUIServiceFactory::GetForProfile(browser_->profile())->
707 SyncConfirmationUIClosed(false /* configure_sync_first */);
711 bool ProfileChooserView::AcceleratorPressed(
712 const ui::Accelerator& accelerator) {
713 if (accelerator.key_code() != ui::VKEY_DOWN &&
714 accelerator.key_code() != ui::VKEY_UP)
715 return BubbleDelegateView::AcceleratorPressed(accelerator);
716 // Move the focus up or down.
717 GetFocusManager()->AdvanceFocus(accelerator.key_code() != ui::VKEY_DOWN);
718 return true;
721 views::View* ProfileChooserView::GetInitiallyFocusedView() {
722 return signin_current_profile_link_;
725 bool ProfileChooserView::HandleContextMenu(
726 const content::ContextMenuParams& params) {
727 // Suppresses the context menu because some features, such as inspecting
728 // elements, are not appropriate in a bubble.
729 return true;
732 void ProfileChooserView::ButtonPressed(views::Button* sender,
733 const ui::Event& event) {
734 if (sender == users_button_) {
735 // If this is a guest session, close all the guest browser windows.
736 if (browser_->profile()->IsGuestSession()) {
737 profiles::CloseGuestProfileWindows();
738 } else {
739 UserManager::Show(base::FilePath(),
740 profiles::USER_MANAGER_NO_TUTORIAL,
741 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
743 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER);
744 } else if (sender == go_incognito_button_) {
745 DCHECK(ShouldShowGoIncognito());
746 chrome::NewIncognitoWindow(browser_);
747 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_GO_INCOGNITO);
748 } else if (sender == lock_button_) {
749 profiles::LockProfile(browser_->profile());
750 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK);
751 } else if (sender == auth_error_email_button_) {
752 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
753 } else if (sender == tutorial_sync_settings_ok_button_) {
754 LoginUIServiceFactory::GetForProfile(browser_->profile())->
755 SyncConfirmationUIClosed(false /* configure_sync_first */);
756 DismissTutorial();
757 ProfileMetrics::LogProfileNewAvatarMenuSignin(
758 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK);
759 } else if (sender == tutorial_close_button_) {
760 DCHECK(tutorial_mode_ != profiles::TUTORIAL_MODE_NONE &&
761 tutorial_mode_ != profiles::TUTORIAL_MODE_CONFIRM_SIGNIN);
762 DismissTutorial();
763 } else if (sender == tutorial_see_whats_new_button_) {
764 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
765 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW);
766 UserManager::Show(base::FilePath(),
767 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
768 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
769 } else if (sender == remove_account_button_) {
770 RemoveAccount();
771 } else if (sender == account_removal_cancel_button_) {
772 account_id_to_remove_.clear();
773 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
774 } else if (sender == gaia_signin_cancel_button_) {
775 // The account management view is only available with the
776 // --enable-account-consistency flag.
777 bool account_management_available =
778 SigninManagerFactory::GetForProfile(browser_->profile())->
779 IsAuthenticated() &&
780 switches::IsEnableAccountConsistency();
781 ShowView(account_management_available ?
782 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
783 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
784 } else if (sender == current_profile_photo_) {
785 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
786 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE);
787 } else if (sender == signin_current_profile_link_) {
788 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
789 } else if (sender == add_person_button_) {
790 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
791 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON);
792 UserManager::Show(base::FilePath(),
793 profiles::USER_MANAGER_NO_TUTORIAL,
794 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
795 } else if (sender == disconnect_button_) {
796 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
797 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT);
798 chrome::ShowSettings(browser_);
799 } else if (sender == switch_user_cancel_button_) {
800 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
801 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
802 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK);
803 } else {
804 // Either one of the "other profiles", or one of the profile accounts
805 // buttons was pressed.
806 ButtonIndexes::const_iterator profile_match =
807 open_other_profile_indexes_map_.find(sender);
808 if (profile_match != open_other_profile_indexes_map_.end()) {
809 avatar_menu_->SwitchToProfile(
810 profile_match->second,
811 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
812 ProfileMetrics::SWITCH_PROFILE_ICON);
813 } else {
814 // This was a profile accounts button.
815 AccountButtonIndexes::const_iterator account_match =
816 delete_account_button_map_.find(sender);
817 if (account_match != delete_account_button_map_.end()) {
818 account_id_to_remove_ = account_match->second;
819 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL,
820 avatar_menu_.get());
821 } else {
822 account_match = reauth_account_button_map_.find(sender);
823 DCHECK(account_match != reauth_account_button_map_.end());
824 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
830 void ProfileChooserView::RemoveAccount() {
831 DCHECK(!account_id_to_remove_.empty());
832 ProfileOAuth2TokenService* oauth2_token_service =
833 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
834 if (oauth2_token_service) {
835 oauth2_token_service->RevokeCredentials(account_id_to_remove_);
836 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT);
838 account_id_to_remove_.clear();
840 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
843 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
844 if (sender == manage_accounts_link_) {
845 // This link can either mean show/hide the account management view,
846 // depending on which view it is displayed. ShowView() will DCHECK if
847 // the account management view is displayed for non signed-in users.
848 ShowView(
849 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
850 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
851 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
852 avatar_menu_.get());
853 } else if (sender == add_account_link_) {
854 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
855 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT);
856 } else if (sender == tutorial_sync_settings_link_) {
857 LoginUIServiceFactory::GetForProfile(browser_->profile())->
858 SyncConfirmationUIClosed(true /* configure_sync_first */);
859 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
860 ProfileMetrics::LogProfileNewAvatarMenuSignin(
861 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS);
862 } else if (sender == tutorial_not_you_link_) {
863 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
864 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU);
865 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER, avatar_menu_.get());
866 } else {
867 DCHECK(sender == tutorial_learn_more_link_);
868 signin_ui_util::ShowSigninErrorLearnMorePage(browser_->profile());
872 void ProfileChooserView::StyledLabelLinkClicked(
873 const gfx::Range& range, int event_flags) {
874 chrome::ShowSettings(browser_);
877 bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
878 const ui::KeyEvent& key_event) {
879 views::Textfield* name_textfield =
880 current_profile_name_->profile_name_textfield();
881 DCHECK(sender == name_textfield);
883 if (key_event.key_code() == ui::VKEY_RETURN ||
884 key_event.key_code() == ui::VKEY_TAB) {
885 // Pressing Tab/Enter commits the new profile name, unless it's empty.
886 base::string16 new_profile_name = name_textfield->text();
887 base::TrimWhitespace(new_profile_name, base::TRIM_ALL, &new_profile_name);
888 if (new_profile_name.empty())
889 return true;
891 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
892 avatar_menu_->GetActiveProfileIndex());
893 Profile* profile = g_browser_process->profile_manager()->GetProfile(
894 active_item.profile_path);
895 DCHECK(profile);
897 if (profile->IsLegacySupervised())
898 return true;
900 profiles::UpdateProfileName(profile, new_profile_name);
901 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
902 current_profile_name_->ShowReadOnlyView();
903 return true;
905 return false;
908 void ProfileChooserView::PopulateCompleteProfileChooserView(
909 views::GridLayout* layout,
910 AvatarMenu* avatar_menu) {
911 // Separate items into active and alternatives.
912 Indexes other_profiles;
913 views::View* tutorial_view = NULL;
914 views::View* current_profile_view = NULL;
915 views::View* current_profile_accounts = NULL;
916 views::View* option_buttons_view = NULL;
917 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
918 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
919 if (item.active) {
920 option_buttons_view = CreateOptionsView(
921 item.signed_in && profiles::IsLockAvailable(browser_->profile()));
922 current_profile_view = CreateCurrentProfileView(item, false);
923 if (IsProfileChooser(view_mode_)) {
924 tutorial_view = CreateTutorialViewIfNeeded(item);
925 } else {
926 current_profile_accounts = CreateCurrentProfileAccountsView(item);
928 } else {
929 other_profiles.push_back(i);
933 if (tutorial_view) {
934 // TODO(mlerman): update UMA stats for the new tutorial.
935 layout->StartRow(1, 0);
936 layout->AddView(tutorial_view);
937 } else {
938 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
941 if (!current_profile_view) {
942 // Guest windows don't have an active profile.
943 current_profile_view = CreateGuestProfileView();
944 option_buttons_view = CreateOptionsView(false);
947 layout->StartRow(1, 0);
948 layout->AddView(current_profile_view);
950 if (!IsProfileChooser(view_mode_)) {
951 DCHECK(current_profile_accounts);
952 layout->StartRow(0, 0);
953 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
954 layout->StartRow(1, 0);
955 layout->AddView(current_profile_accounts);
958 if (browser_->profile()->IsSupervised()) {
959 layout->StartRow(0, 0);
960 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
961 layout->StartRow(1, 0);
962 layout->AddView(CreateSupervisedUserDisclaimerView());
965 layout->StartRow(0, 0);
966 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
968 if (option_buttons_view) {
969 layout->StartRow(0, 0);
970 layout->AddView(option_buttons_view);
974 void ProfileChooserView::PopulateMinimalProfileChooserView(
975 views::GridLayout* layout,
976 AvatarMenu* avatar_menu) {
977 Indexes other_profiles;
978 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
979 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
980 if (!item.active) {
981 other_profiles.push_back(i);
985 layout->StartRow(1, 0);
986 layout->AddView(CreateOtherProfilesView(other_profiles));
989 views::View* ProfileChooserView::CreateProfileChooserView(
990 AvatarMenu* avatar_menu) {
991 views::View* view = new views::View();
992 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
994 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER) {
995 PopulateMinimalProfileChooserView(layout, avatar_menu);
996 // The user is using right-click switching, no need to tell them about it.
997 PrefService* local_state = g_browser_process->local_state();
998 local_state->SetBoolean(
999 prefs::kProfileAvatarRightClickTutorialDismissed, true);
1000 } else {
1001 PopulateCompleteProfileChooserView(layout, avatar_menu);
1004 return view;
1007 void ProfileChooserView::DismissTutorial() {
1008 // Never shows the upgrade tutorial again if manually closed.
1009 if (tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) {
1010 browser_->profile()->GetPrefs()->SetInteger(
1011 prefs::kProfileAvatarTutorialShown,
1012 signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1);
1015 if (tutorial_mode_ == profiles::TUTORIAL_MODE_RIGHT_CLICK_SWITCHING) {
1016 PrefService* local_state = g_browser_process->local_state();
1017 local_state->SetBoolean(
1018 prefs::kProfileAvatarRightClickTutorialDismissed, true);
1021 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
1022 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
1025 views::View* ProfileChooserView::CreateTutorialViewIfNeeded(
1026 const AvatarMenu::Item& item) {
1027 if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN)
1028 return CreateSigninConfirmationView();
1030 if (tutorial_mode_ == profiles::TUTORIAL_MODE_SHOW_ERROR)
1031 return CreateSigninErrorView();
1033 if (profiles::ShouldShowWelcomeUpgradeTutorial(
1034 browser_->profile(), tutorial_mode_)) {
1035 if (tutorial_mode_ != profiles::TUTORIAL_MODE_WELCOME_UPGRADE) {
1036 Profile* profile = browser_->profile();
1037 const int show_count = profile->GetPrefs()->GetInteger(
1038 prefs::kProfileAvatarTutorialShown);
1039 profile->GetPrefs()->SetInteger(
1040 prefs::kProfileAvatarTutorialShown, show_count + 1);
1043 return CreateWelcomeUpgradeTutorialView(item);
1046 if (profiles::ShouldShowRightClickTutorial(browser_->profile()))
1047 return CreateRightClickTutorialView();
1049 return nullptr;
1052 views::View* ProfileChooserView::CreateTutorialView(
1053 profiles::TutorialMode tutorial_mode,
1054 const base::string16& title_text,
1055 const base::string16& content_text,
1056 const base::string16& link_text,
1057 const base::string16& button_text,
1058 bool stack_button,
1059 views::Link** link,
1060 views::LabelButton** button,
1061 views::ImageButton** close_button) {
1062 tutorial_mode_ = tutorial_mode;
1064 views::View* view = new views::View();
1065 view->set_background(views::Background::CreateSolidBackground(
1066 profiles::kAvatarTutorialBackgroundColor));
1067 views::GridLayout* layout = CreateSingleColumnLayout(view,
1068 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1069 // Creates a second column set for buttons and links.
1070 views::ColumnSet* button_columns = layout->AddColumnSet(1);
1071 button_columns->AddColumn(views::GridLayout::LEADING,
1072 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1073 button_columns->AddPaddingColumn(
1074 1, views::kUnrelatedControlHorizontalSpacing);
1075 button_columns->AddColumn(views::GridLayout::TRAILING,
1076 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1077 layout->SetInsets(views::kButtonVEdgeMarginNew,
1078 views::kButtonHEdgeMarginNew,
1079 views::kButtonVEdgeMarginNew,
1080 views::kButtonHEdgeMarginNew);
1082 // Adds title and close button if needed.
1083 views::Label* title_label = new views::Label(title_text);
1084 title_label->SetMultiLine(true);
1085 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1086 title_label->SetAutoColorReadabilityEnabled(false);
1087 title_label->SetEnabledColor(SK_ColorWHITE);
1088 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1089 ui::ResourceBundle::MediumFont));
1091 if (close_button) {
1092 layout->StartRow(1, 1);
1093 layout->AddView(title_label);
1094 *close_button = new views::ImageButton(this);
1095 (*close_button)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1096 views::ImageButton::ALIGN_MIDDLE);
1097 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1098 (*close_button)->SetImage(views::ImageButton::STATE_NORMAL,
1099 rb->GetImageSkiaNamed(IDR_CLOSE_1));
1100 (*close_button)->SetImage(views::ImageButton::STATE_HOVERED,
1101 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1102 (*close_button)->SetImage(views::ImageButton::STATE_PRESSED,
1103 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1104 layout->AddView(*close_button);
1105 } else {
1106 layout->StartRow(1, 0);
1107 layout->AddView(title_label);
1110 // Adds body content.
1111 views::Label* content_label = new views::Label(content_text);
1112 content_label->SetMultiLine(true);
1113 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1114 content_label->SetAutoColorReadabilityEnabled(false);
1115 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
1116 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
1117 layout->AddView(content_label);
1119 // Adds links and buttons.
1120 bool has_button = !button_text.empty();
1121 if (has_button) {
1122 *button = new views::LabelButton(this, button_text);
1123 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1124 (*button)->SetStyle(views::Button::STYLE_BUTTON);
1127 bool has_link = !link_text.empty();
1128 if (has_link) {
1129 *link = CreateLink(link_text, this);
1130 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1131 (*link)->SetAutoColorReadabilityEnabled(false);
1132 (*link)->SetEnabledColor(SK_ColorWHITE);
1135 if (stack_button) {
1136 DCHECK(has_button);
1137 layout->StartRowWithPadding(
1138 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1139 layout->AddView(*button);
1140 if (has_link) {
1141 layout->StartRowWithPadding(
1142 1, 0, 0, views::kRelatedControlVerticalSpacing);
1143 (*link)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1144 layout->AddView(*link);
1146 } else {
1147 DCHECK(has_link || has_button);
1148 layout->StartRowWithPadding(
1149 1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1150 if (has_link)
1151 layout->AddView(*link);
1152 else
1153 layout->SkipColumns(1);
1154 if (has_button)
1155 layout->AddView(*button);
1156 else
1157 layout->SkipColumns(1);
1160 return view;
1163 views::View* ProfileChooserView::CreateCurrentProfileView(
1164 const AvatarMenu::Item& avatar_item,
1165 bool is_guest) {
1166 views::View* view = new views::View();
1167 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
1168 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
1169 layout->SetInsets(views::kButtonVEdgeMarginNew,
1170 views::kButtonHEdgeMarginNew,
1171 views::kUnrelatedControlVerticalSpacing,
1172 views::kButtonHEdgeMarginNew);
1174 // Profile icon, centered.
1175 int x_offset = (column_width - kLargeImageSide) / 2;
1176 current_profile_photo_ = new EditableProfilePhoto(
1177 this, avatar_item.icon, !is_guest,
1178 gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
1179 SizedContainer* profile_icon_container =
1180 new SizedContainer(gfx::Size(column_width, kLargeImageSide));
1181 profile_icon_container->AddChildView(current_profile_photo_);
1183 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1184 if (browser_->profile()->IsSupervised()) {
1185 views::ImageView* supervised_icon = new views::ImageView();
1186 int image_id = browser_->profile()->IsChild()
1187 ? IDR_ICON_PROFILES_MENU_CHILD
1188 : IDR_ICON_PROFILES_MENU_LEGACY_SUPERVISED;
1189 supervised_icon->SetImage(rb->GetImageSkiaNamed(image_id));
1190 gfx::Size preferred_size = supervised_icon->GetPreferredSize();
1191 gfx::Rect parent_bounds = current_profile_photo_->bounds();
1192 supervised_icon->SetBounds(
1193 parent_bounds.right() - preferred_size.width(),
1194 parent_bounds.bottom() - preferred_size.height(),
1195 preferred_size.width(),
1196 preferred_size.height());
1197 profile_icon_container->AddChildView(supervised_icon);
1200 layout->StartRow(1, 0);
1201 layout->AddView(profile_icon_container);
1203 // Profile name, centered.
1204 bool editing_allowed = !is_guest &&
1205 !browser_->profile()->IsLegacySupervised();
1206 current_profile_name_ = new EditableProfileName(
1207 this,
1208 profiles::GetAvatarNameForProfile(browser_->profile()->GetPath()),
1209 editing_allowed);
1210 layout->StartRowWithPadding(1, 0, 0,
1211 views::kRelatedControlSmallVerticalSpacing);
1212 layout->StartRow(1, 0);
1213 layout->AddView(current_profile_name_);
1215 if (is_guest)
1216 return view;
1218 // The available links depend on the type of profile that is active.
1219 if (avatar_item.signed_in) {
1220 layout->StartRow(1, 0);
1221 if (switches::IsEnableAccountConsistency()) {
1222 base::string16 link_title = l10n_util::GetStringUTF16(
1223 IsProfileChooser(view_mode_) ?
1224 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
1225 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
1226 manage_accounts_link_ = CreateLink(link_title, this);
1227 manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1228 layout->AddView(manage_accounts_link_);
1229 } else {
1230 // Badge the email address if there's an authentication error.
1231 if (HasAuthError(browser_->profile())) {
1232 const gfx::ImageSkia warning_image = *rb->GetImageNamed(
1233 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia();
1234 auth_error_email_button_ =
1235 new RightAlignedIconLabelButton(this, avatar_item.username);
1236 auth_error_email_button_->SetElideBehavior(gfx::ELIDE_EMAIL);
1237 auth_error_email_button_->SetImage(
1238 views::LabelButton::STATE_NORMAL, warning_image);
1239 auth_error_email_button_->SetTextColor(
1240 views::LabelButton::STATE_NORMAL,
1241 views::Link::GetDefaultEnabledColor());
1242 auth_error_email_button_->SetFocusable(true);
1243 gfx::Insets insets =
1244 views::LabelButtonAssetBorder::GetDefaultInsetsForStyle(
1245 views::Button::STYLE_TEXTBUTTON);
1246 auth_error_email_button_->SetBorder(views::Border::CreateEmptyBorder(
1247 insets.top(), insets.left(), insets.bottom(), insets.right()));
1248 layout->AddView(auth_error_email_button_);
1249 } else {
1250 // Add a small padding between the email button and the profile name.
1251 layout->StartRowWithPadding(1, 0, 0, 2);
1252 views::Label* email_label = new views::Label(avatar_item.username);
1253 email_label->SetElideBehavior(gfx::ELIDE_EMAIL);
1254 email_label->SetEnabled(false);
1255 layout->AddView(email_label);
1258 } else {
1259 SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(
1260 browser_->profile()->GetOriginalProfile());
1261 if (signin_manager->IsSigninAllowed()) {
1262 views::Label* promo = new views::Label(
1263 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO));
1264 promo->SetMultiLine(true);
1265 promo->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1266 layout->StartRowWithPadding(1, 0, 0,
1267 views::kRelatedControlSmallVerticalSpacing);
1268 layout->StartRow(1, 0);
1269 layout->AddView(promo);
1271 signin_current_profile_link_ = new views::BlueButton(
1272 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
1273 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
1274 layout->StartRowWithPadding(1, 0, 0,
1275 views::kRelatedControlVerticalSpacing);
1276 layout->StartRow(1, 0);
1277 layout->AddView(signin_current_profile_link_);
1281 return view;
1284 views::View* ProfileChooserView::CreateGuestProfileView() {
1285 gfx::Image guest_icon =
1286 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1287 profiles::GetPlaceholderAvatarIconResourceID());
1288 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
1289 guest_avatar_item.active = true;
1290 guest_avatar_item.name = l10n_util::GetStringUTF16(
1291 IDS_PROFILES_GUEST_PROFILE_NAME);
1292 guest_avatar_item.signed_in = false;
1294 return CreateCurrentProfileView(guest_avatar_item, true);
1297 views::View* ProfileChooserView::CreateOtherProfilesView(
1298 const Indexes& avatars_to_show) {
1299 views::View* view = new views::View();
1300 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1302 for (size_t index : avatars_to_show) {
1303 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
1304 const int kSmallImageSide = 32;
1306 // Use the low-res, small default avatars in the fast user switcher, like
1307 // we do in the menu bar.
1308 gfx::Image item_icon;
1309 bool is_rectangle;
1310 AvatarMenu::GetImageForMenuButton(
1311 item.profile_path, &item_icon, &is_rectangle);
1313 gfx::Image image = profiles::GetSizedAvatarIcon(
1314 item_icon, true, kSmallImageSide, kSmallImageSide);
1316 views::LabelButton* button = new BackgroundColorHoverButton(
1317 this,
1318 profiles::GetProfileSwitcherTextForItem(item),
1319 *image.ToImageSkia());
1320 open_other_profile_indexes_map_[button] = index;
1322 layout->StartRow(1, 0);
1323 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1324 layout->StartRow(1, 0);
1325 layout->AddView(button);
1328 return view;
1331 views::View* ProfileChooserView::CreateOptionsView(bool display_lock) {
1332 views::View* view = new views::View();
1333 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1335 base::string16 text = browser_->profile()->IsGuestSession() ?
1336 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1337 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON);
1338 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1339 users_button_ = new BackgroundColorHoverButton(
1340 this,
1341 text,
1342 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1343 layout->StartRow(1, 0);
1344 layout->AddView(users_button_);
1346 if (ShouldShowGoIncognito()) {
1347 layout->StartRow(1, 0);
1348 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1350 go_incognito_button_ = new BackgroundColorHoverButton(
1351 this,
1352 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON),
1353 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO));
1354 layout->StartRow(1, 0);
1355 layout->AddView(go_incognito_button_);
1358 if (display_lock) {
1359 layout->StartRow(1, 0);
1360 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1362 lock_button_ = new BackgroundColorHoverButton(
1363 this,
1364 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON),
1365 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1366 layout->StartRow(1, 0);
1367 layout->AddView(lock_button_);
1369 return view;
1372 views::View* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1373 views::View* view = new views::View();
1374 views::GridLayout* layout = CreateSingleColumnLayout(
1375 view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1376 layout->SetInsets(views::kRelatedControlVerticalSpacing,
1377 views::kButtonHEdgeMarginNew,
1378 views::kRelatedControlVerticalSpacing,
1379 views::kButtonHEdgeMarginNew);
1380 views::Label* disclaimer = new views::Label(
1381 avatar_menu_->GetSupervisedUserInformation());
1382 disclaimer->SetMultiLine(true);
1383 disclaimer->SetAllowCharacterBreak(true);
1384 disclaimer->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1385 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1386 disclaimer->SetFontList(rb->GetFontList(ui::ResourceBundle::SmallFont));
1387 layout->StartRow(1, 0);
1388 layout->AddView(disclaimer);
1390 return view;
1393 views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1394 const AvatarMenu::Item& avatar_item) {
1395 DCHECK(avatar_item.signed_in);
1396 views::View* view = new views::View();
1397 view->set_background(views::Background::CreateSolidBackground(
1398 profiles::kAvatarBubbleAccountsBackgroundColor));
1399 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1401 Profile* profile = browser_->profile();
1402 std::string primary_account =
1403 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
1404 DCHECK(!primary_account.empty());
1405 std::vector<std::string>accounts =
1406 profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1408 // Get state of authentication error, if any.
1409 std::string error_account_id = GetAuthErrorAccountId(profile);
1411 // The primary account should always be listed first.
1412 // TODO(rogerta): we still need to further differentiate the primary account
1413 // from the others in the UI, so more work is likely required here:
1414 // crbug.com/311124.
1415 CreateAccountButton(layout, primary_account, true,
1416 error_account_id == primary_account, kFixedMenuWidth);
1417 for (size_t i = 0; i < accounts.size(); ++i)
1418 CreateAccountButton(layout, accounts[i], false,
1419 error_account_id == accounts[i], kFixedMenuWidth);
1421 if (!profile->IsSupervised()) {
1422 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1424 add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1425 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1426 add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1427 0, views::kButtonVEdgeMarginNew,
1428 views::kRelatedControlVerticalSpacing, 0));
1429 layout->StartRow(1, 0);
1430 layout->AddView(add_account_link_);
1433 return view;
1436 void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1437 const std::string& account_id,
1438 bool is_primary_account,
1439 bool reauth_required,
1440 int width) {
1441 std::string email = signin_ui_util::GetDisplayEmail(browser_->profile(),
1442 account_id);
1443 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1444 const gfx::ImageSkia* delete_default_image =
1445 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1446 const int kDeleteButtonWidth = delete_default_image->width();
1447 const gfx::ImageSkia warning_default_image = reauth_required ?
1448 *rb->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia() :
1449 gfx::ImageSkia();
1450 const int kWarningButtonWidth = reauth_required ?
1451 warning_default_image.width() + views::kRelatedButtonHSpacing : 0;
1452 int available_width = width - 2 * views::kButtonHEdgeMarginNew
1453 - kDeleteButtonWidth - kWarningButtonWidth;
1454 views::LabelButton* email_button = new BackgroundColorHoverButton(
1455 reauth_required ? this : NULL,
1456 base::UTF8ToUTF16(email),
1457 warning_default_image);
1458 email_button->SetElideBehavior(gfx::ELIDE_EMAIL);
1459 email_button->SetMinSize(gfx::Size(0, kButtonHeight));
1460 email_button->SetMaxSize(gfx::Size(available_width, kButtonHeight));
1461 layout->StartRow(1, 0);
1462 layout->AddView(email_button);
1464 if (reauth_required)
1465 reauth_account_button_map_[email_button] = account_id;
1467 // Delete button.
1468 if (!browser_->profile()->IsSupervised()) {
1469 views::ImageButton* delete_button = new views::ImageButton(this);
1470 delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1471 views::ImageButton::ALIGN_MIDDLE);
1472 delete_button->SetImage(views::ImageButton::STATE_NORMAL,
1473 delete_default_image);
1474 delete_button->SetImage(views::ImageButton::STATE_HOVERED,
1475 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1476 delete_button->SetImage(views::ImageButton::STATE_PRESSED,
1477 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1478 delete_button->SetBounds(
1479 width - views::kButtonHEdgeMarginNew - kDeleteButtonWidth,
1480 0, kDeleteButtonWidth, kButtonHeight);
1482 email_button->set_notify_enter_exit_on_child(true);
1483 email_button->AddChildView(delete_button);
1485 // Save the original email address, as the button text could be elided.
1486 delete_account_button_map_[delete_button] = account_id;
1490 views::View* ProfileChooserView::CreateGaiaSigninView(
1491 views::View** signin_content_view) {
1492 GURL url;
1493 int message_id;
1495 switch (view_mode_) {
1496 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
1497 url = signin::GetPromoURL(signin_metrics::SOURCE_AVATAR_BUBBLE_SIGN_IN,
1498 false /* auto_close */,
1499 true /* is_constrained */);
1500 message_id = IDS_PROFILES_GAIA_SIGNIN_TITLE;
1501 break;
1502 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
1503 url = signin::GetPromoURL(
1504 signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT,
1505 false /* auto_close */,
1506 true /* is_constrained */);
1507 message_id = IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE;
1508 break;
1509 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: {
1510 DCHECK(HasAuthError(browser_->profile()));
1511 url = signin::GetReauthURL(browser_->profile(),
1512 GetAuthErrorAccountId(browser_->profile()));
1513 message_id = IDS_PROFILES_GAIA_REAUTH_TITLE;
1514 break;
1516 default:
1517 NOTREACHED() << "Called with invalid mode=" << view_mode_;
1518 return NULL;
1521 // Adds Gaia signin webview
1522 Profile* profile = browser_->profile();
1523 views::WebView* web_view = new views::WebView(profile);
1524 web_view->LoadInitialURL(url);
1525 web_view->GetWebContents()->SetDelegate(this);
1526 web_view->SetPreferredSize(
1527 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1528 content::RenderWidgetHostView* rwhv =
1529 web_view->GetWebContents()->GetRenderWidgetHostView();
1530 if (rwhv)
1531 rwhv->SetBackgroundColor(profiles::kAvatarBubbleGaiaBackgroundColor);
1532 TitleCard* title_card = new TitleCard(l10n_util::GetStringUTF16(message_id),
1533 this,
1534 &gaia_signin_cancel_button_);
1535 if (signin_content_view)
1536 *signin_content_view = web_view;
1537 return TitleCard::AddPaddedTitleCard(
1538 web_view, title_card, kFixedGaiaViewWidth);
1541 views::View* ProfileChooserView::CreateAccountRemovalView() {
1542 views::View* view = new views::View();
1543 views::GridLayout* layout = CreateSingleColumnLayout(
1544 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1545 layout->SetInsets(0,
1546 views::kButtonHEdgeMarginNew,
1547 views::kButtonVEdgeMarginNew,
1548 views::kButtonHEdgeMarginNew);
1550 const std::string& primary_account = SigninManagerFactory::GetForProfile(
1551 browser_->profile())->GetAuthenticatedAccountId();
1552 bool is_primary_account = primary_account == account_id_to_remove_;
1554 // Adds main text.
1555 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1556 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1557 const gfx::FontList& small_font_list =
1558 rb->GetFontList(ui::ResourceBundle::SmallFont);
1560 if (is_primary_account) {
1561 std::string email = signin_ui_util::GetDisplayEmail(browser_->profile(),
1562 account_id_to_remove_);
1563 std::vector<size_t> offsets;
1564 const base::string16 settings_text =
1565 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1566 const base::string16 primary_account_removal_text =
1567 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1568 base::UTF8ToUTF16(email), settings_text, &offsets);
1569 views::StyledLabel* primary_account_removal_label =
1570 new views::StyledLabel(primary_account_removal_text, this);
1571 primary_account_removal_label->AddStyleRange(
1572 gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1573 views::StyledLabel::RangeStyleInfo::CreateForLink());
1574 primary_account_removal_label->SetBaseFontList(small_font_list);
1575 layout->AddView(primary_account_removal_label);
1576 } else {
1577 views::Label* content_label = new views::Label(
1578 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1579 content_label->SetMultiLine(true);
1580 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1581 content_label->SetFontList(small_font_list);
1582 layout->AddView(content_label);
1585 // Adds button.
1586 if (!is_primary_account) {
1587 remove_account_button_ = new views::BlueButton(
1588 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1589 remove_account_button_->SetHorizontalAlignment(
1590 gfx::ALIGN_CENTER);
1591 layout->StartRowWithPadding(
1592 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1593 layout->AddView(remove_account_button_);
1594 } else {
1595 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1598 TitleCard* title_card = new TitleCard(
1599 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE),
1600 this, &account_removal_cancel_button_);
1601 return TitleCard::AddPaddedTitleCard(view, title_card,
1602 kFixedAccountRemovalViewWidth);
1605 views::View* ProfileChooserView::CreateWelcomeUpgradeTutorialView(
1606 const AvatarMenu::Item& avatar_item) {
1607 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1608 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW);
1610 // For local profiles, the "Not you" link doesn't make sense.
1611 base::string16 link_message = avatar_item.signed_in ?
1612 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name) :
1613 base::string16();
1615 return CreateTutorialView(
1616 profiles::TUTORIAL_MODE_WELCOME_UPGRADE,
1617 l10n_util::GetStringUTF16(
1618 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE),
1619 l10n_util::GetStringUTF16(
1620 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT),
1621 link_message,
1622 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON),
1623 true /* stack_button */,
1624 &tutorial_not_you_link_,
1625 &tutorial_see_whats_new_button_,
1626 &tutorial_close_button_);
1629 views::View* ProfileChooserView::CreateSigninConfirmationView() {
1630 ProfileMetrics::LogProfileNewAvatarMenuSignin(
1631 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW);
1633 return CreateTutorialView(
1634 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN,
1635 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE),
1636 l10n_util::GetStringUTF16(
1637 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT),
1638 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK),
1639 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
1640 false /* stack_button */,
1641 &tutorial_sync_settings_link_,
1642 &tutorial_sync_settings_ok_button_,
1643 NULL /* close_button*/);
1646 views::View* ProfileChooserView::CreateSigninErrorView() {
1647 LoginUIService* login_ui_service =
1648 LoginUIServiceFactory::GetForProfile(browser_->profile());
1649 base::string16 last_login_result(login_ui_service->GetLastLoginResult());
1650 return CreateTutorialView(
1651 profiles::TUTORIAL_MODE_SHOW_ERROR,
1652 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE),
1653 last_login_result,
1654 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1655 base::string16(),
1656 false /* stack_button */,
1657 &tutorial_learn_more_link_,
1658 NULL,
1659 &tutorial_close_button_);
1662 views::View* ProfileChooserView::CreateRightClickTutorialView() {
1663 return CreateTutorialView(
1664 profiles::TUTORIAL_MODE_RIGHT_CLICK_SWITCHING,
1665 l10n_util::GetStringUTF16(IDS_PROFILES_RIGHT_CLICK_TUTORIAL_TITLE),
1666 l10n_util::GetStringUTF16(IDS_PROFILES_RIGHT_CLICK_TUTORIAL_CONTENT_TEXT),
1667 base::string16(),
1668 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
1669 false,
1670 nullptr,
1671 &tutorial_sync_settings_ok_button_,
1672 nullptr);
1675 views::View* ProfileChooserView::CreateSwitchUserView() {
1676 views::View* view = new views::View();
1677 views::GridLayout* layout = CreateSingleColumnLayout(
1678 view, kFixedSwitchUserViewWidth);
1679 views::ColumnSet* columns = layout->AddColumnSet(1);
1680 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1681 int label_width =
1682 kFixedSwitchUserViewWidth - 2 * views::kButtonHEdgeMarginNew;
1683 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1684 views::GridLayout::FIXED, label_width, label_width);
1685 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1687 // Adds main text.
1688 layout->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1689 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1690 const gfx::FontList& small_font_list =
1691 rb->GetFontList(ui::ResourceBundle::SmallFont);
1692 const AvatarMenu::Item& avatar_item =
1693 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex());
1694 views::Label* content_label = new views::Label(
1695 l10n_util::GetStringFUTF16(
1696 IDS_PROFILES_NOT_YOU_CONTENT_TEXT, avatar_item.name));
1697 content_label->SetMultiLine(true);
1698 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1699 content_label->SetFontList(small_font_list);
1700 layout->AddView(content_label);
1702 // Adds "Add person" button.
1703 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1704 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1706 add_person_button_ = new BackgroundColorHoverButton(
1707 this,
1708 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON),
1709 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1710 layout->StartRow(1, 0);
1711 layout->AddView(add_person_button_);
1713 // Adds "Disconnect your Google Account" button.
1714 layout->StartRow(1, 0);
1715 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1717 disconnect_button_ = new BackgroundColorHoverButton(
1718 this,
1719 l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON),
1720 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT));
1721 layout->StartRow(1, 0);
1722 layout->AddView(disconnect_button_);
1724 TitleCard* title_card = new TitleCard(
1725 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name),
1726 this, &switch_user_cancel_button_);
1727 return TitleCard::AddPaddedTitleCard(view, title_card,
1728 kFixedSwitchUserViewWidth);
1731 bool ProfileChooserView::ShouldShowGoIncognito() const {
1732 bool incognito_available =
1733 IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) !=
1734 IncognitoModePrefs::DISABLED;
1735 return incognito_available && !browser_->profile()->IsGuestSession();
1738 void ProfileChooserView::PostActionPerformed(
1739 ProfileMetrics::ProfileDesktopMenu action_performed) {
1740 ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_);
1741 gaia_service_type_ = signin::GAIA_SERVICE_TYPE_NONE;